Skip to content

Instantly share code, notes, and snippets.

@jamiefdhurst
Created August 29, 2024 20:06
Show Gist options
  • Save jamiefdhurst/36e51a51d1ca7e9f1273c783fb3e1f4e to your computer and use it in GitHub Desktop.
Save jamiefdhurst/36e51a51d1ca7e9f1273c783fb3e1f4e to your computer and use it in GitHub Desktop.
import * as cdk from 'aws-cdk-lib';
import { Certificate, CertificateValidation } from 'aws-cdk-lib/aws-certificatemanager';
import { Peer, Port, SecurityGroup, Vpc } from 'aws-cdk-lib/aws-ec2';
import { FileSystem, PerformanceMode, ThroughputMode } from 'aws-cdk-lib/aws-efs';
import { ApplicationLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { LambdaTarget } from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets';
import { Effect, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
import { Code, Function, FunctionUrlAuthType, FileSystem as LambdaFileSystem, Runtime } from 'aws-cdk-lib/aws-lambda';
import { ARecord, HostedZone, RecordTarget } from 'aws-cdk-lib/aws-route53';
import { LoadBalancerTarget } from 'aws-cdk-lib/aws-route53-targets';
import { Construct } from 'constructs';
import { join } from 'path';
export class JournalInfraStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const defaultVpc = Vpc.fromLookup(this, 'DefaultVPC', {
isDefault: true,
});
const sg = new SecurityGroup(this, 'JournalSG', {
vpc: defaultVpc,
allowAllOutbound: true,
});
sg.addIngressRule(Peer.anyIpv4(), Port.tcp(443));
const role = new Role(this, 'JournalRole', {
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
});
role.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
resources: [`arn:aws:logs:*:${this.account}:*`],
actions: ['logs:CreateLogGroup'],
}));
role.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
resources: [`arn:aws:logs:*:${this.account}:log-group:*:*`],
actions: ['logs:CreateLogStream', 'logs:PutLogEvents'],
}));
role.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
resources: ['*'],
actions: ['ec2:DescribeNetworkInterfaces', 'ec2:CreateNetworkInterface', 'ec2:DeleteNetworkInterface', 'ec2:DescribeInstances', 'ec2:AttachNetworkInterface'],
}));
const efs = new FileSystem(this, 'JournalEFS', {
vpc: defaultVpc,
performanceMode: PerformanceMode.GENERAL_PURPOSE,
throughputMode: ThroughputMode.ELASTIC,
});
const accessPoint = efs.addAccessPoint('JournalEFSAccessPoint', {
createAcl: {
ownerGid: '1001',
ownerUid: '1001',
permissions: '777'
},
path: '/db',
posixUser: {
gid: '1001',
uid: '1001'
},
});
role.addToPolicy(new PolicyStatement({
effect: Effect.ALLOW,
resources: [efs.fileSystemArn, accessPoint.accessPointArn],
actions: ['elasticfilesystem:ClientMount', 'elasticfilesystem:ClientRootAccess', 'elasticfilesystem:ClientWrite', 'elasticfilesystem:DescribeMountTargets'],
}));
const lambda = new Function(this, 'JournalLambda', {
role,
runtime: Runtime.PROVIDED_AL2023,
code: Code.fromAsset(join(__dirname, '../dist')),
handler: 'bootstrap',
vpc: defaultVpc,
filesystem: LambdaFileSystem.fromEfsAccessPoint(accessPoint, '/mnt/db'),
environment: {
J_DB_PATH: '/mnt/db/journal.db',
},
securityGroups: [sg],
allowPublicSubnet: true,
});
efs.connections.allowFrom(lambda, Port.allTcp());
const zone = HostedZone.fromLookup(this, 'JournalHostedZone', {
domainName: 'jamiehurst.co.uk',
});
const cert = new Certificate(this, 'JournalCert', {
domainName: 'journal-lambda.jamiehurst.co.uk',
validation: CertificateValidation.fromDns(zone),
});
const alb = new ApplicationLoadBalancer(this, 'JournalALB', {
vpc: defaultVpc,
internetFacing: true,
});
alb.addRedirect();
const listener = alb.addListener('JournalHTTPSListener', {
port: 443,
certificates: [cert],
});
const target = listener.addTargets('JournalHTTPSListenerTargets', {
targets: [new LambdaTarget(lambda)],
healthCheck: {
enabled: true
},
});
target.setAttribute('lambda.multi_value_headers.enabled', 'true');
new ARecord(this, 'JournalDNSRecord', {
zone,
recordName: 'journal-lambda',
target: RecordTarget.fromAlias(new LoadBalancerTarget(alb)),
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment