~aws-ts-static-website: Create certificate if certificateArn is omitted.
If certificateArn is omitted from the configuration, create an ACM certificate and associated DNS records for certificate verification.
MODIFY
aws-ts-static-website/Pulumi.yaml
aws-ts-static-website/Pulumi.yaml
@@ -6,9 +6,9 @@ template:
aws:region:
description: The AWS region to deploy into
default: us-east-1
- static-website:certificateArn:
- description: ACM certificate ARN for the target domain; must be in the us-east-1 region
static-website:targetDomain:
description: The domain to serve the website at (e.g. www.example.com)
static-website:pathToWebsiteContents:
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.

MODIFY
aws-ts-static-website/index.ts
aws-ts-static-website/index.ts
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
-import { Output } from "@pulumi/pulumi";
import * as fs from "fs";
import * as mime from "mime";
@@ -15,8 +14,8 @@ const config = {
pathToWebsiteContents: stackConfig.require("pathToWebsiteContents"),
// targetDomain is the domain/host to serve content at.
targetDomain: stackConfig.require("targetDomain"),
- // ACM certificate for the target domain. Must be in the us-east-1 region.
- certificateArn: stackConfig.require("certificateArn"),
+ // (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"),
};
// contentBucket is the S3 bucket that the website's contents will be stored in.
@@ -79,11 +78,61 @@ const logsBucket = new aws.s3.Bucket("requestLogs",
const tenMinutes = 60 * 10;
+let certificateArn: pulumi.Input<string> = config.certificateArn!;
+
+/**
+ * Only provision a certificate (and related resources) if a certificateArn is _not_ provided via configuration.
+ */
+if (config.certificateArn === undefined) {
+
+ const eastRegion = new aws.Provider("east", {
+ region: "us-east-1", // Per AWS, ACM certificate must be in the us-east-1 region.
+ });
+
+ const certificate = new aws.acm.Certificate("certificate", {
+ domainName: config.targetDomain,
+ validationMethod: "DNS",
+ }, { provider: eastRegion });
+
+ const domainParts = getDomainAndSubdomain(config.targetDomain);
+ const hostedZoneId = aws.route53.getZone({ name: domainParts.parentDomain }).then(zone => zone.id);
+
+ /**
+ * Create a DNS record to prove that we _own_ the domain we're requesting a certificate for.
+ * See https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html for more info.
+ */
+ const certificateValidationDomain = new aws.route53.Record(`${config.targetDomain}-validation`, {
+ name: certificate.domainValidationOptions.apply(d => d[0].resourceRecordName),
+ zoneId: hostedZoneId,
+ type: certificate.domainValidationOptions.apply(d => d[0].resourceRecordType),
+ records: [certificate.domainValidationOptions.apply(d => d[0].resourceRecordValue)],
+ ttl: tenMinutes,
+ });
+
+ /**
+ * 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
+ * created (or updated or deleted).
+ *
+ * See https://www.terraform.io/docs/providers/aws/r/acm_certificate_validation.html for slightly more detail
+ * and https://github.com/terraform-providers/terraform-provider-aws/blob/master/aws/resource_aws_acm_certificate_validation.go
+ * for the actual implementation.
+ */
+ const certificateValidation = new aws.acm.CertificateValidation("certificateValidation", {
+ certificateArn: certificate.arn,
+ validationRecordFqdns: [certificateValidationDomain.fqdn],
+ }, { provider: eastRegion });
+
+ certificateArn = certificateValidation.certificateArn;
+}
+
// 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 ],
// We only specify one origin for this distribution, the S3 content bucket.
@@ -139,9 +188,8 @@ const distributionArgs: aws.cloudfront.DistributionArgs = {
},
},
- // CloudFront certs must be in us-east-1, just like API Gateway.
viewerCertificate: {
- acmCertificateArn: config.certificateArn,
+ acmCertificateArn: certificateArn, // Per AWS, ACM certificate must be in the us-east-1 region.
sslSupportMethod: "sni-only",
},
@@ -203,3 +251,4 @@ const aRecord = createAliasRecord(config.targetDomain, cdn);
export const contentBucketUri = contentBucket.bucket.apply(b => `s3://${b}`);
export const contentBucketWebsiteEndpoint = contentBucket.websiteEndpoint;
export const cloudFrontDomain = cdn.domainName;
+export const targetDomainEndpoint = `https://${config.targetDomain}/`;

~aws-ts-static-website: Create certificate if certificateArn is omitted. (#199)

If certificateArn is omitted from the configuration, create an ACM certificate and associated DNS records for certificate verification.