diff --git a/cdk.context.json b/cdk.context.json index 0967ef4..cbf79c4 100644 --- a/cdk.context.json +++ b/cdk.context.json @@ -1 +1,6 @@ -{} +{ + "hosted-zone:account=775126750502:domainName=rememberval.com:region=us-east-1": { + "Id": "/hostedzone/Z10280523GOIQ59UKGL5W", + "Name": "rememberval.com." + } +} diff --git a/cdk/bin.ts b/cdk/bin.ts index 4fb6a21..d5bef98 100644 --- a/cdk/bin.ts +++ b/cdk/bin.ts @@ -4,6 +4,7 @@ import { writeJSON } from '@bevry/jsonfile'; import { getConfig, STAGE } from './config'; import { Next } from './stacks/next'; +import { DNS } from './stacks/dns'; const builder = new Builder('.', './build', { args: ['build'] }); const config = getConfig(); @@ -19,6 +20,17 @@ const main = async () => { // Build the NextJS app await builder.build(); + const dNSStack = new DNS(app, `${config.codenameCapitalized}DNS`, { + terminationProtection: config.isProd, + env: { + account: process.env.AWS_DEFAULT_ACCOUNT_ID, + region: process.env.AWS_DEFAULT_REGION || 'us-east-1', + }, + analyticsReporting: true, + description: 'The DNS stack', + config, + }); + // Deploy the NextJS app new Next(app, `${config.prefixCamelCase}Next`, { terminationProtection: config.isProd, @@ -29,7 +41,8 @@ const main = async () => { analyticsReporting: true, description: 'The Next stack', config, - }); + zoneId: dNSStack.zoneId, + }).addDependency(dNSStack); }; main(); diff --git a/cdk/config.ts b/cdk/config.ts index f8535dc..bd1ad85 100644 --- a/cdk/config.ts +++ b/cdk/config.ts @@ -73,6 +73,7 @@ const prefixKebabCase = `${stage}-${codename}-`; export interface Config { bucketConfigName: string; codename: string; + codenameCapitalized: string; dbMailingList: string; developerEmail: string; domainBase: string; @@ -84,7 +85,7 @@ export interface Config { githubRepository: string; githubServerUrl: string; githubSha: string; - hCaptchaSecret: string; + hCaptchaSecret: string; isBranch: boolean; isMerge: boolean; isProd: boolean; @@ -102,6 +103,7 @@ export const getConfig = () => { return { bucketConfigName: `${prefixKebabCase}config-bucket`, codename, + codenameCapitalized, dbMailingList, developerEmail, domainBase, diff --git a/cdk/stacks/dns.ts b/cdk/stacks/dns.ts new file mode 100644 index 0000000..c63ee23 --- /dev/null +++ b/cdk/stacks/dns.ts @@ -0,0 +1,73 @@ +import { Certificate, CertificateValidation } from 'aws-cdk-lib/aws-certificatemanager'; +import { Construct } from 'constructs'; +import { HostedZone, ARecord, RecordTarget, CnameRecord, NsRecord } from 'aws-cdk-lib/aws-route53'; +import { Metric } from 'aws-cdk-lib/aws-cloudwatch'; +import { Route53RecordTarget } from 'aws-cdk-lib/aws-route53-targets'; +import { Stack, StackProps, Duration, CfnOutput, RemovalPolicy } from 'aws-cdk-lib'; + +import { Config } from '../config'; + +interface DNSProps extends StackProps { + config: Config; +} + +export class DNS extends Stack { + readonly zoneId; + constructor(scope: Construct, id: string, props: DNSProps) { + super(scope, id, props); + + // DNS & certs + const zone = new HostedZone(this, `${props.config.codenameCapitalized}HostedZone`, { + zoneName: props.config.domainBase, + }); + zone.applyRemovalPolicy(RemovalPolicy.DESTROY); + + this.zoneId = zone.hostedZoneId; + const metric = new Metric({ + namespace: 'AWS/Route53', + metricName: 'DNSQueries', + dimensionsMap: { + HostedZoneId: zone.hostedZoneId, + } + }); + + // const record =vnew ARecord(this, 'AliasRecord', { + // zone, + // target: RecordTarget.fromAlias(new Route53RecordTarget(props.config.domainBase), + // deleteExisting: true, + // ttl: Duration.minutes(5), + // }); + // record.applyRemovalPolicy(RemovalPolicy.DESTROY); + + // const cname = new CnameRecord(this, `${props.config.stage}CnameRecord`, { + // recordName: props.config.stage, + // zone, + // domainName: props.config.domainBase, + // deleteExisting: true, + // ttl: Duration.minutes(5), + // }); + // cname.applyRemovalPolicy(RemovalPolicy.DESTROY); + + // const ns = new NsRecord(this, 'NSRecord', { + // zone, + // recordName: props.config.domainBase, + // values: [ + // // Get these from the AWS > Route53 > Registered domains > > Name servers + // 'ns-1214.awsdns-23.org.', + // 'ns-191.awsdns-23.com.', + // 'ns-1640.awsdns-13.co.uk.', + // 'ns-790.awsdns-34.net.', + // ], + // deleteExisting: true, + // ttl: Duration.minutes(5), + // }); + // ns.applyRemovalPolicy(RemovalPolicy.DESTROY); + + // const certificate = new Certificate(this, `${id}Certificate`, { + // domainName: props.config.domainBase, + // subjectAlternativeNames: [`www.${props.config.domainBase}`], + // validation: CertificateValidation.fromDns(zone), + // }); + // certificate.applyRemovalPolicy(RemovalPolicy.DESTROY); + } +} diff --git a/cdk/stacks/next.ts b/cdk/stacks/next.ts index 12cf186..cf2e0a7 100644 --- a/cdk/stacks/next.ts +++ b/cdk/stacks/next.ts @@ -14,6 +14,7 @@ import { Config } from '../config'; interface NextProps extends StackProps { config: Config; + zoneId: string; } export class Next extends Stack { @@ -21,50 +22,10 @@ export class Next extends Stack { super(scope, id, props); // DNS & certs - const zone = new HostedZone(this, `${id}HostedZone`, { + const zone = HostedZone.fromHostedZoneAttributes(this, props.zoneId, { zoneName: props.config.domainBase, + hostedZoneId: props.zoneId, }); - zone.applyRemovalPolicy(RemovalPolicy.DESTROY); - - const metric = new Metric({ - namespace: 'AWS/Route53', - metricName: 'DNSQueries', - dimensionsMap: { - HostedZoneId: zone.hostedZoneId - } - }); - - // const record =vnew ARecord(this, 'AliasRecord', { - // zone, - // target: RecordTarget.fromAlias(new Route53RecordTarget(props.config.domainBase), - // deleteExisting: true, - // ttl: Duration.minutes(5), - // }); - // record.applyRemovalPolicy(RemovalPolicy.DESTROY); - - // const cname = new CnameRecord(this, `${props.config.stage}CnameRecord`, { - // recordName: props.config.stage, - // zone, - // domainName: props.config.domainBase, - // deleteExisting: true, - // ttl: Duration.minutes(5), - // }); - // cname.applyRemovalPolicy(RemovalPolicy.DESTROY); - - // const ns = new NsRecord(this, 'NSRecord', { - // zone, - // recordName: props.config.domainBase, - // values: [ - // // Get these from the AWS > Route53 > Registered domains > > Name servers - // 'ns-1214.awsdns-23.org.', - // 'ns-191.awsdns-23.com.', - // 'ns-1640.awsdns-13.co.uk.', - // 'ns-790.awsdns-34.net.', - // ], - // deleteExisting: true, - // ttl: Duration.minutes(5), - // }); - // ns.applyRemovalPolicy(RemovalPolicy.DESTROY); const certificate = new Certificate(this, `${id}Certificate`, { domainName: props.config.domainStage,