Add additional configuration variable includeWWW (default=true) which will trigger additional resources to be created in order to support a www subdomain in addition to the root target domain
ADD
aws-ts-static-website/.gitignore
+Pulumi.ts3.yaml
\ No newline at end of file

MODIFY
aws-ts-static-website/Pulumi.yaml
aws-ts-static-website/Pulumi.yaml
@@ -12,3 +12,6 @@ template:
description: Relative path to the website's contents (e.g. the `./www` folder)
static-website:certificateArn:
description: (Optional) ACM certificate ARN for the target domain; must be in the us-east-1 region. If omitted, a certificate will be created.
+ static-website:includeWWW:
+ description: If true create an A record for the www subdomain of targetDomain pointing to the generated cloudfront distribution. If a certificate was generated it will support this subdomain.
+ default: true

MODIFY
aws-ts-static-website/index.ts
aws-ts-static-website/index.ts
@@ -11,6 +11,7 @@ import * as path from "path";
// so that different Pulumi Stacks can be brought up using the same code.
const stackConfig = new pulumi.Config("static-website");
+
const config = {
// pathToWebsiteContents is a relativepath to the website's contents.
pathToWebsiteContents: stackConfig.require("pathToWebsiteContents"),
@@ -18,6 +19,10 @@ const config = {
targetDomain: stackConfig.require("targetDomain"),
// (Optional) ACM certificate ARN for the target domain; must be in the us-east-1 region. If omitted, an ACM certificate will be created.
certificateArn: stackConfig.get("certificateArn"),
+ // If true create an A record for the www subdomain of targetDomain pointing to the generated cloudfront distribution.
+ // If a certificate was generated it will support this subdomain.
+ // default: true
+ includeWWW: stackConfig.getBoolean("includeWWW") || true
};
// contentBucket is the S3 bucket that the website's contents will be stored in.
@@ -92,10 +97,14 @@ if (config.certificateArn === undefined) {
region: "us-east-1", // Per AWS, ACM certificate must be in the us-east-1 region.
});
- const certificate = new aws.acm.Certificate("certificate", {
+ // if config.includeWWW include required subjectAlternativeNames to support the www subdomain
+ let certificateConfig:aws.acm.CertificateArgs = {
domainName: config.targetDomain,
validationMethod: "DNS",
- }, { provider: eastRegion });
+ subjectAlternativeNames: config.includeWWW ? [`www.${config.targetDomain}`]: []
+ }
+
+ const certificate = new aws.acm.Certificate("certificate", certificateConfig, { provider: eastRegion });
const domainParts = getDomainAndSubdomain(config.targetDomain);
const hostedZoneId = aws.route53.getZone({ name: domainParts.parentDomain }, { async: true }).then(zone => zone.zoneId);
@@ -112,6 +121,22 @@ if (config.certificateArn === undefined) {
ttl: tenMinutes,
});
+ // if config.includeWWW ensure we validate the www subdomain as well
+ var subdomainCertificateValidationDomain;
+ if (config.includeWWW) {
+ subdomainCertificateValidationDomain = new aws.route53.Record(`${config.targetDomain}-validation2`, {
+ name: certificate.domainValidationOptions[1].resourceRecordName,
+ zoneId: hostedZoneId,
+ type: certificate.domainValidationOptions[1].resourceRecordType,
+ records: [certificate.domainValidationOptions[1].resourceRecordValue],
+ ttl: tenMinutes,
+ });
+ }
+
+ // if config.includeWWW include the validation record for the www subdomain
+ const validationRecordFqdns = subdomainCertificateValidationDomain === undefined ?
+ [certificateValidationDomain.fqdn] : [certificateValidationDomain.fqdn, subdomainCertificateValidationDomain.fqdn]
+
/**
* This is a _special_ resource that waits for ACM to complete validation via the DNS record
* checking for a status of "ISSUED" on the certificate itself. No actual resources are
@@ -123,12 +148,15 @@ if (config.certificateArn === undefined) {
*/
const certificateValidation = new aws.acm.CertificateValidation("certificateValidation", {
certificateArn: certificate.arn,
- validationRecordFqdns: [certificateValidationDomain.fqdn],
+ validationRecordFqdns: validationRecordFqdns,
}, { provider: eastRegion });
certificateArn = certificateValidation.certificateArn;
}
+// if config.includeWWW include an alias for the www subdomain
+const distributionAliases = config.includeWWW ? [config.targetDomain, `www.${config.targetDomain}`]:[config.targetDomain]
+
// distributionArgs configures the CloudFront distribution. Relevant documentation:
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html
// https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html
@@ -136,7 +164,7 @@ const distributionArgs: aws.cloudfront.DistributionArgs = {
enabled: true,
// Alternate aliases the CloudFront distribution can be reached at, in addition to https://xxxx.cloudfront.net.
// Required if you want to access the distribution via config.targetDomain as well.
- aliases: [ config.targetDomain ],
+ aliases: distributionAliases,
// We only specify one origin for this distribution, the S3 content bucket.
origins: [
@@ -247,7 +275,31 @@ function createAliasRecord(
});
}
+function createWWWAliasRecord(targetDomain: string, distribution: aws.cloudfront.Distribution): aws.route53.Record {
+ const domainParts = getDomainAndSubdomain(targetDomain);
+ const hostedZoneId = aws.route53.getZone({ name: domainParts.parentDomain }, { async: true }).then(zone => zone.zoneId);
+
+ return new aws.route53.Record(
+ `${targetDomain}-www-alias`,
+ {
+ name: `www.${targetDomain}`,
+ zoneId: hostedZoneId,
+ type: "A",
+ aliases: [
+ {
+ name: distribution.domainName,
+ zoneId: distribution.hostedZoneId,
+ evaluateTargetHealth: true,
+ },
+ ],
+ }
+ )
+}
+
const aRecord = createAliasRecord(config.targetDomain, cdn);
+if (config.includeWWW){
+ const cnameRecord = createWWWAliasRecord(config.targetDomain, cdn);
+}
// Export properties from this stack. This prints them at the end of `pulumi up` and
// makes them easier to access from the pulumi.com.

Add additional configuration variable includeWWW (default=true) which will trigger additional resources to be created in order to support a www subdomain in addition to the root target domain