Skip to content

Commit

Permalink
fix(aws-cloudfront): Add sslSupportMethod (#19737)
Browse files Browse the repository at this point in the history
- Modified to allow selection of sslSupportMethod

closes #19476

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [ ] Did you use `cdk-integ` to deploy the infrastructure and generate the snapshot (i.e. `cdk-integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
dayjournal authored Apr 7, 2022
1 parent ccfbcf6 commit c5a9679
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-cloudfront/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ new cloudfront.Distribution(this, 'myDist', {
defaultBehavior: { origin: new origins.S3Origin(myBucket) },
domainNames: ['www.example.com'],
minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2016,
sslSupportMethod: cloudfront.SSLMethod.SNI,
});
```

Expand Down
27 changes: 24 additions & 3 deletions packages/@aws-cdk/aws-cloudfront/lib/distribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,25 @@ export interface DistributionProps {
* @default - SecurityPolicyProtocol.TLS_V1_2_2021 if the '@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021' feature flag is set; otherwise, SecurityPolicyProtocol.TLS_V1_2_2019.
*/
readonly minimumProtocolVersion?: SecurityPolicyProtocol;

/**
* The SSL method CloudFront will use for your distribution.
*
* Server Name Indication (SNI) - is an extension to the TLS computer networking protocol by which a client indicates
* which hostname it is attempting to connect to at the start of the handshaking process. This allows a server to present
* multiple certificates on the same IP address and TCP port number and hence allows multiple secure (HTTPS) websites
* (or any other service over TLS) to be served by the same IP address without requiring all those sites to use the same certificate.
*
* CloudFront can use SNI to host multiple distributions on the same IP - which a large majority of clients will support.
*
* If your clients cannot support SNI however - CloudFront can use dedicated IPs for your distribution - but there is a prorated monthly charge for
* using this feature. By default, we use SNI - but you can optionally enable dedicated IPs (VIP).
*
* See the CloudFront SSL for more details about pricing : https://aws.amazon.com/cloudfront/custom-ssl-domains/
*
* @default SSLMethod.SNI
*/
readonly sslSupportMethod?: SSLMethod;
}

/**
Expand Down Expand Up @@ -304,7 +323,8 @@ export class Distribution extends Resource implements IDistribution {
logging: this.renderLogging(props),
priceClass: props.priceClass ?? undefined,
restrictions: this.renderRestrictions(props.geoRestriction),
viewerCertificate: this.certificate ? this.renderViewerCertificate(this.certificate, props.minimumProtocolVersion) : undefined,
viewerCertificate: this.certificate ? this.renderViewerCertificate(this.certificate,
props.minimumProtocolVersion, props.sslSupportMethod) : undefined,
webAclId: props.webAclId,
},
});
Expand Down Expand Up @@ -450,16 +470,17 @@ export class Distribution extends Resource implements IDistribution {
}

private renderViewerCertificate(certificate: acm.ICertificate,
minimumProtocolVersionProp?: SecurityPolicyProtocol): CfnDistribution.ViewerCertificateProperty {
minimumProtocolVersionProp?: SecurityPolicyProtocol, sslSupportMethodProp?: SSLMethod): CfnDistribution.ViewerCertificateProperty {

const defaultVersion = FeatureFlags.of(this).isEnabled(CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021)
? SecurityPolicyProtocol.TLS_V1_2_2021 : SecurityPolicyProtocol.TLS_V1_2_2019;
const minimumProtocolVersion = minimumProtocolVersionProp ?? defaultVersion;
const sslSupportMethod = sslSupportMethodProp ?? SSLMethod.SNI;

return {
acmCertificateArn: certificate.certificateArn,
sslSupportMethod: SSLMethod.SNI,
minimumProtocolVersion: minimumProtocolVersion,
sslSupportMethod: sslSupportMethod,
};
}
}
Expand Down
136 changes: 135 additions & 1 deletion packages/@aws-cdk/aws-cloudfront/test/distribution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
LambdaEdgeEventType,
PriceClass,
SecurityPolicyProtocol,
SSLMethod,
} from '../lib';
import { defaultOrigin, defaultOriginGroup } from './test-origin';

Expand Down Expand Up @@ -56,7 +57,139 @@ test('minimal example renders correctly', () => {
});
});

test('exhaustive example of props renders correctly', () => {
test('exhaustive example of props renders correctly and SSL method sni-only', () => {
const origin = defaultOrigin();
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012');

new Distribution(stack, 'MyDist', {
defaultBehavior: { origin },
certificate,
comment: 'a test',
defaultRootObject: 'index.html',
domainNames: ['example.com'],
enabled: false,
enableIpv6: false,
enableLogging: true,
geoRestriction: GeoRestriction.denylist('US', 'GB'),
httpVersion: HttpVersion.HTTP1_1,
logFilePrefix: 'logs/',
logIncludesCookies: true,
sslSupportMethod: SSLMethod.SNI,
minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2019,
priceClass: PriceClass.PRICE_CLASS_100,
webAclId: '473e64fd-f30b-4765-81a0-62ad96dd167a',
});

Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', {
DistributionConfig: {
Aliases: ['example.com'],
DefaultCacheBehavior: {
CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6',
Compress: true,
TargetOriginId: 'StackMyDistOrigin1D6D5E535',
ViewerProtocolPolicy: 'allow-all',
},
Comment: 'a test',
DefaultRootObject: 'index.html',
Enabled: false,
HttpVersion: 'http1.1',
IPV6Enabled: false,
Logging: {
Bucket: { 'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName'] },
IncludeCookies: true,
Prefix: 'logs/',
},
Origins: [{
DomainName: 'www.example.com',
Id: 'StackMyDistOrigin1D6D5E535',
CustomOriginConfig: {
OriginProtocolPolicy: 'https-only',
},
}],
PriceClass: 'PriceClass_100',
Restrictions: {
GeoRestriction: {
Locations: ['US', 'GB'],
RestrictionType: 'blacklist',
},
},
ViewerCertificate: {
AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012',
SslSupportMethod: 'sni-only',
MinimumProtocolVersion: 'TLSv1.2_2019',
},
WebACLId: '473e64fd-f30b-4765-81a0-62ad96dd167a',
},
});
});

test('exhaustive example of props renders correctly and SSL method vip', () => {
const origin = defaultOrigin();
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012');

new Distribution(stack, 'MyDist', {
defaultBehavior: { origin },
certificate,
comment: 'a test',
defaultRootObject: 'index.html',
domainNames: ['example.com'],
enabled: false,
enableIpv6: false,
enableLogging: true,
geoRestriction: GeoRestriction.denylist('US', 'GB'),
httpVersion: HttpVersion.HTTP1_1,
logFilePrefix: 'logs/',
logIncludesCookies: true,
sslSupportMethod: SSLMethod.VIP,
minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2019,
priceClass: PriceClass.PRICE_CLASS_100,
webAclId: '473e64fd-f30b-4765-81a0-62ad96dd167a',
});

Template.fromStack(stack).hasResourceProperties('AWS::CloudFront::Distribution', {
DistributionConfig: {
Aliases: ['example.com'],
DefaultCacheBehavior: {
CachePolicyId: '658327ea-f89d-4fab-a63d-7e88639e58f6',
Compress: true,
TargetOriginId: 'StackMyDistOrigin1D6D5E535',
ViewerProtocolPolicy: 'allow-all',
},
Comment: 'a test',
DefaultRootObject: 'index.html',
Enabled: false,
HttpVersion: 'http1.1',
IPV6Enabled: false,
Logging: {
Bucket: { 'Fn::GetAtt': ['MyDistLoggingBucket9B8976BC', 'RegionalDomainName'] },
IncludeCookies: true,
Prefix: 'logs/',
},
Origins: [{
DomainName: 'www.example.com',
Id: 'StackMyDistOrigin1D6D5E535',
CustomOriginConfig: {
OriginProtocolPolicy: 'https-only',
},
}],
PriceClass: 'PriceClass_100',
Restrictions: {
GeoRestriction: {
Locations: ['US', 'GB'],
RestrictionType: 'blacklist',
},
},
ViewerCertificate: {
AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012',
SslSupportMethod: 'vip',
MinimumProtocolVersion: 'TLSv1.2_2019',
},
WebACLId: '473e64fd-f30b-4765-81a0-62ad96dd167a',
},
});
});

test('exhaustive example of props renders correctly and SSL method default', () => {
const origin = defaultOrigin();
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012');

Expand Down Expand Up @@ -404,6 +537,7 @@ describe('certificates', () => {
new Distribution(stack, 'Dist', {
defaultBehavior: { origin: defaultOrigin() },
domainNames: ['www.example.com'],
sslSupportMethod: SSLMethod.SNI,
minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2016,
certificate: certificate,
});
Expand Down

0 comments on commit c5a9679

Please sign in to comment.