Skip to content

Commit

Permalink
Add additional configuration variable includeWWW (default=true) which…
Browse files Browse the repository at this point in the history
… will trigger additional resources to be created in order to support a www subdomain in addition to the root target domain
  • Loading branch information
beeekind committed Apr 12, 2021
1 parent 905c63c commit b0d671b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 5 deletions.
1 change: 1 addition & 0 deletions aws-ts-static-website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pulumi.ts3.yaml
3 changes: 3 additions & 0 deletions aws-ts-static-website/Pulumi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
62 changes: 57 additions & 5 deletions aws-ts-static-website/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ 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"),
// targetDomain is the domain/host to serve content at.
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.
Expand Down Expand Up @@ -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 });
validationMethod: "DNS",
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);
Expand All @@ -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
Expand All @@ -123,20 +148,23 @@ 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
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: [
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit b0d671b

Please sign in to comment.