diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index c13af4ace9e05..7865d7881fda6 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -97,7 +97,9 @@ new cloudfront.Distribution(this, 'myDist', { When you create a distribution, CloudFront assigns a domain name for the distribution, for example: `d111111abcdef8.cloudfront.net`; this value can be retrieved from `distribution.distributionDomainName`. CloudFront distributions use a default certificate (`*.cloudfront.net`) to support HTTPS by default. If you want to use your own domain name, such as `www.example.com`, you must associate a certificate with your distribution that contains -your domain name. The certificate must be present in the AWS Certificate Manager (ACM) service in the US East (N. Virginia) region; the certificate +your domain name, and provide one (or more) domain names from the certificate for the distribution. + +The certificate must be present in the AWS Certificate Manager (ACM) service in the US East (N. Virginia) region; the certificate may either be created by ACM, or created elsewhere and imported into ACM. When a certificate is used, the distribution will support HTTPS connections from SNI only and a minimum protocol version of TLSv1.2_2018. @@ -108,6 +110,7 @@ const myCertificate = new acm.DnsValidatedCertificate(this, 'mySiteCert', { }); new cloudfront.Distribution(this, 'myDist', { defaultBehavior: { origin: new origins.S3Origin(myBucket) }, + domainNames: ['www.example.com'], certificate: myCertificate, }); ``` diff --git a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts index b600c9177b2d4..de2316ad245ac 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/distribution.ts @@ -101,6 +101,17 @@ export interface DistributionProps { */ readonly defaultRootObject?: string; + /** + * Alternative domain names for this distribution. + * + * If you want to use your own domain name, such as www.example.com, instead of the cloudfront.net domain name, + * you can add an alternate domain name to your distribution. If you attach a certificate to the distribution, + * you must add (at least one of) the domain names of the certificate to this list. + * + * @default - The distribution will only support the default generated name (e.g., d111111abcdef8.cloudfront.net) + */ + readonly domainNames?: string[]; + /** * Enable or disable the distribution. * @@ -239,6 +250,10 @@ export class Distribution extends Resource implements IDistribution { if (!Token.isUnresolved(certificateRegion) && certificateRegion !== 'us-east-1') { throw new Error(`Distribution certificates must be in the us-east-1 region and the certificate you provided is in ${certificateRegion}.`); } + + if ((props.domainNames ?? []).length === 0) { + throw new Error('Must specify at least one domain name to use a certificate with a distribution'); + } } const originId = this.addOrigin(props.defaultBehavior.origin); @@ -258,6 +273,7 @@ export class Distribution extends Resource implements IDistribution { origins: Lazy.anyValue({ produce: () => this.renderOrigins() }), originGroups: Lazy.anyValue({ produce: () => this.renderOriginGroups() }), defaultCacheBehavior: this.defaultBehavior._renderBehavior(), + aliases: props.domainNames, cacheBehaviors: Lazy.anyValue({ produce: () => this.renderCacheBehaviors() }), comment: props.comment, customErrorResponses: this.renderErrorResponses(), diff --git a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts index d0105db39f9d2..71b547e862553 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts @@ -51,6 +51,7 @@ test('exhaustive example of props renders correctly', () => { certificate, comment: 'a test', defaultRootObject: 'index.html', + domainNames: ['example.com'], enabled: false, enableIpv6: false, enableLogging: true, @@ -64,6 +65,7 @@ test('exhaustive example of props renders correctly', () => { expect(stack).toHaveResource('AWS::CloudFront::Distribution', { DistributionConfig: { + Aliases: ['example.com'], DefaultCacheBehavior: { ForwardedValues: { QueryString: false }, TargetOriginId: 'StackMyDistOrigin1D6D5E535', @@ -263,16 +265,37 @@ describe('certificates', () => { }).toThrow(/Distribution certificates must be in the us-east-1 region and the certificate you provided is in eu-west-1./); }); - test('adding a certificate renders the correct ViewerCertificate property', () => { + test('adding a certificate without a domain name throws', () => { + const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012'); + + expect(() => { + new Distribution(stack, 'Dist1', { + defaultBehavior: { origin: defaultOrigin() }, + certificate, + }); + }).toThrow(/Must specify at least one domain name/); + + expect(() => { + new Distribution(stack, 'Dist2', { + defaultBehavior: { origin: defaultOrigin() }, + domainNames: [], + certificate, + }); + }).toThrow(/Must specify at least one domain name/); + }); + + test('adding a certificate and domain renders the correct ViewerCertificate and Aliases property', () => { const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012'); new Distribution(stack, 'Dist', { defaultBehavior: { origin: defaultOrigin() }, + domainNames: ['example.com', 'www.example.com'], certificate, }); expect(stack).toHaveResourceLike('AWS::CloudFront::Distribution', { DistributionConfig: { + Aliases: ['example.com', 'www.example.com'], ViewerCertificate: { AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012', SslSupportMethod: 'sni-only',