Last active
November 25, 2020 23:36
-
-
Save fourgates/855aad3c722f623da895548e8cd6a8b5 to your computer and use it in GitHub Desktop.
AWS CDK - S3 / Cloudfront + Domain + SSL & ECS (ecr, ecs-pattern [elb, taskdef, service, cluster])
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from '@aws-cdk/core'; | |
import * as dynamodb from '@aws-cdk/aws-dynamodb'; | |
import * as s3 from '@aws-cdk/aws-s3'; | |
import * as s3Deploy from '@aws-cdk/aws-s3-deployment'; | |
import * as cloudfront from '@aws-cdk/aws-cloudfront'; | |
import * as route53 from '@aws-cdk/aws-route53'; | |
import * as acm from '@aws-cdk/aws-certificatemanager'; | |
import * as targets from '@aws-cdk/aws-route53-targets/lib'; | |
import { OriginAccessIdentity } from '@aws-cdk/aws-cloudfront'; | |
import * as ecr from '@aws-cdk/aws-ecr'; | |
import * as ecsPatterns from '@aws-cdk/aws-ecs-patterns' | |
import * as ecs from '@aws-cdk/aws-ecs' | |
import * as ec2 from '@aws-cdk/aws-ec2' | |
import * as elb2 from '@aws-cdk/aws-elasticloadbalancingv2' | |
import { StaticSite, StaticSiteProps } from './static-website/static-webiste'; | |
export class CdkStack extends cdk.Stack { | |
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { | |
super(scope, id, props); | |
// 0. we need a NoSQL db to persist data | |
// create dynamoDb table to store data | |
const table = new dynamodb.Table(this, 'Questions', { | |
partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING }, | |
sortKey: {name: 'sk', type: dynamodb.AttributeType.STRING}, | |
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, | |
tableName: 'Questions' | |
}); | |
new cdk.CfnOutput(this, 'Dynamo', { value: table.tableName }); | |
// 1. we need an angular app to fun the FE and connect to an app api | |
// - S3 Bucket, Cloudfront Dist, Route 53 Alias | |
// create S3 + CloudFront to host the FE | |
const siteSubDomain = "app"; | |
const domainName = "yourdomain.com"; | |
const zone = route53.HostedZone.fromLookup(this, 'Zone', { domainName: domainName }); | |
const siteDomain = siteSubDomain + '.' + domainName; | |
new cdk.CfnOutput(this, 'Site', { value: 'https://' + siteDomain }); | |
// TLS certificate | |
const wildCartCert = new acm.DnsValidatedCertificate(this, 'SiteCertificate', { | |
domainName: "*.yourdomain.com", | |
hostedZone: zone, | |
region: 'us-east-1', // Cloudfront only checks this region for certificates. | |
}); | |
const certificateArn = wildCartCert.certificateArn; | |
new cdk.CfnOutput(this, 'Certificate', { value: certificateArn }); | |
// S3 | |
const bucket = new s3.Bucket(this, "MathDynastyAppBucket", { | |
publicReadAccess: false, | |
removalPolicy: cdk.RemovalPolicy.DESTROY, | |
websiteIndexDocument: "index.html", | |
bucketName: "math-dynasty-app-bucket" | |
}); | |
new cdk.CfnOutput(this, 'Bucket', { value: bucket.bucketName }); | |
const oia = new OriginAccessIdentity(this, 'OIA', { | |
comment: "Created by CDK" | |
}); | |
bucket.grantRead(oia); | |
// Cloudfront | |
const distribution = new cloudfront.CloudFrontWebDistribution(this, "CDKMDAAPPDistribution", { | |
aliasConfiguration: { | |
acmCertRef: certificateArn, | |
names: [ siteDomain ], | |
sslMethod: cloudfront.SSLMethod.SNI, | |
securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016 | |
}, | |
originConfigs: [ | |
{ | |
s3OriginSource: { | |
s3BucketSource: bucket, | |
originAccessIdentity: oia | |
}, | |
behaviors: [{isDefaultBehavior: true}] | |
}, | |
] | |
}); | |
new cdk.CfnOutput(this, 'DistributionId', { value: distribution.distributionId }); | |
// Route53 alias record for the CloudFront distribution | |
new route53.ARecord(this, 'SiteAliasRecord', { | |
recordName: siteDomain, | |
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)), | |
zone | |
}); | |
// Deployment - deploy angular app | |
const src = new s3Deploy.BucketDeployment(this, "DeployMDAWithInvalidation", { | |
sources: [s3Deploy.Source.asset("./build")], | |
destinationBucket: bucket, | |
distribution, | |
distributionPaths: ['/*'], | |
}); | |
// 2. we need several ECS Repo | |
// angular FE, express BE, cdk | |
// ECR | |
const appDev = new ecr.Repository(this, 'md-app-dev', { | |
imageScanOnPush: true, | |
repositoryName: 'md-app-dev' | |
}); | |
new cdk.CfnOutput(this, 'App Repo', { value: appDev.repositoryUri }); | |
const appApi = new ecr.Repository(this, 'md-app-api-dev', { | |
imageScanOnPush: true, | |
repositoryName: 'md-app-api-dev' | |
}); | |
new cdk.CfnOutput(this, 'App-API Repo', { value: appApi.repositoryUri }); | |
const appCdk = new ecr.Repository(this, 'md-app-cdk', { | |
imageScanOnPush: true, | |
repositoryName: 'md-app-cdk' | |
}); | |
new cdk.CfnOutput(this, 'App-CDK Repo', { value: appCdk.repositoryUri }); | |
const prodVpc = new ec2.Vpc(this, 'VPC'); | |
// TODO create a prod security group | |
const prodCluster = new ecs.Cluster(this, 'Cluster', { | |
vpc: prodVpc, | |
clusterName: 'prod', | |
}); | |
const prodLoadBalancedFargateService = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'ProdService', { | |
cluster: prodCluster, | |
certificate: wildCartCert, | |
desiredCount: 1, | |
assignPublicIp: true, | |
protocol: elb2.ApplicationProtocol.HTTPS, | |
redirectHTTP: true, | |
memoryLimitMiB: 1024, | |
cpu: 512, | |
taskImageOptions: { | |
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), | |
containerName: 'app-api', | |
containerPort: 80, | |
enableLogging: true, | |
family: 'prod-app-api', | |
logDriver: ecs.LogDriver.awsLogs({ | |
streamPrefix: "prod-app-api", | |
}) | |
}, | |
domainName: 'app-api.mathdynasty.com', | |
domainZone: zone, | |
serviceName: 'app-api' | |
}); | |
prodLoadBalancedFargateService.targetGroup.configureHealthCheck({ | |
path: "/custom-health-path", | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment