Skip to content

Commit 8a5299a

Browse files
ZeldoKavirarix0rrr
authored andcommitted
feat(aws-cloudfront): Support Security Policy (#804)
Adds support for changing the default Security Policy (minimumProtocolVersion) with logic to ensure the proper one is being set for your SSLMethod. Fixes #795
1 parent 2a2b7a1 commit 8a5299a

File tree

3 files changed

+171
-12
lines changed

3 files changed

+171
-12
lines changed

packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts

+73-12
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,45 @@ export enum ViewerProtocolPolicy {
2626
}
2727

2828
/**
29-
* CloudFront can use a custom domain that you provide instead of a "cloudfront.net" domain.
30-
* To use this feature - you must provide the list of additional domains,
31-
* and the ACM Certificate that CloudFront should use for these additional domains.
29+
* Configuration for custom domain names
3230
*
33-
* Note - CloudFront only accepts one additional certificate - therefore the certificate *must*
34-
* use have SANs (Subject Alternative Names) for all domains listed.
35-
*
36-
* sslMethod is optional - we default to SNI if not specified. See the notes on SSLMethod if you wish to use other SSL termination types.
37-
*
38-
* @default sslMethod: SNI by default
31+
* CloudFront can use a custom domain that you provide instead of a
32+
* "cloudfront.net" domain. To use this feature you must provide the list of
33+
* additional domains, and the ACM Certificate that CloudFront should use for
34+
* these additional domains.
3935
*/
4036
export interface AliasConfiguration {
41-
readonly names: string[],
42-
readonly acmCertRef: string,
43-
readonly sslMethod?: SSLMethod,
37+
/**
38+
* ARN of an AWS Certificate Manager (ACM) certificate.
39+
*/
40+
readonly acmCertRef: string;
41+
42+
/**
43+
* Domain names on the certificate
44+
*
45+
* Both main domain name and Subject Alternative Names.
46+
*/
47+
readonly names: string[];
48+
49+
/**
50+
* How CloudFront should serve HTTPS requests.
51+
*
52+
* See the notes on SSLMethod if you wish to use other SSL termination types.
53+
*
54+
* @default SNI
55+
* @see https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ViewerCertificate.html
56+
*/
57+
readonly sslMethod?: SSLMethod;
58+
59+
/**
60+
* The minimum version of the SSL protocol that you want CloudFront to use for HTTPS connections.
61+
*
62+
* CloudFront serves your objects only to browsers or devices that support at
63+
* least the SSL version that you specify.
64+
*
65+
* @default securityPolicy: SSLv3 if sslMethod VIP, TLSv1 if sslMethod SNI
66+
*/
67+
readonly securityPolicy?: SecurityPolicyProtocol;
4468
}
4569

4670
/**
@@ -64,6 +88,18 @@ export enum SSLMethod {
6488
VIP = "vip"
6589
}
6690

91+
/**
92+
* The minimum version of the SSL protocol that you want CloudFront to use for HTTPS connections.
93+
* CloudFront serves your objects only to browsers or devices that support at least the SSL version that you specify.
94+
*/
95+
export enum SecurityPolicyProtocol {
96+
SSLv3 = "SSLv3",
97+
TLSv1 = "TLSv1",
98+
TLSv1_2016 = "TLSv1_2016",
99+
TLSv1_1_2016 = "TLSv1.1_2016",
100+
TLSv1_2_2018 = "TLSv1.2_2018"
101+
}
102+
67103
/**
68104
* CloudFront supports logging of incoming requests and can log details to a given S3 Bucket.
69105
*
@@ -453,6 +489,17 @@ export class CloudFrontWebDistribution extends cdk.Construct {
453489
ALL: ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"],
454490
};
455491

492+
/**
493+
* Maps for which SecurityPolicyProtocol are available to which SSLMethods
494+
*/
495+
private readonly VALID_SSL_PROTOCOLS: { [key: string]: string[] } = {
496+
"sni-only": [
497+
SecurityPolicyProtocol.TLSv1, SecurityPolicyProtocol.TLSv1_1_2016,
498+
SecurityPolicyProtocol.TLSv1_2016, SecurityPolicyProtocol.TLSv1_2_2018
499+
],
500+
"vip": [SecurityPolicyProtocol.SSLv3, SecurityPolicyProtocol.TLSv1],
501+
};
502+
456503
constructor(parent: cdk.Construct, name: string, props: CloudFrontWebDistributionProps) {
457504
super(parent, name);
458505

@@ -554,7 +601,21 @@ export class CloudFrontWebDistribution extends cdk.Construct {
554601
distributionConfig.viewerCertificate = {
555602
acmCertificateArn: props.aliasConfiguration.acmCertRef,
556603
sslSupportMethod: props.aliasConfiguration.sslMethod || SSLMethod.SNI,
604+
minimumProtocolVersion: props.aliasConfiguration.securityPolicy
557605
};
606+
607+
if (distributionConfig.viewerCertificate.minimumProtocolVersion !== undefined) {
608+
const validProtocols = this.VALID_SSL_PROTOCOLS[distributionConfig.viewerCertificate.sslSupportMethod!.toString()];
609+
610+
if (validProtocols === undefined) {
611+
throw new Error(`Invalid sslMethod. ${distributionConfig.viewerCertificate.sslSupportMethod!.toString()} is not fully implemented yet.`);
612+
}
613+
614+
if (validProtocols.indexOf(distributionConfig.viewerCertificate.minimumProtocolVersion.toString()) === -1) {
615+
// tslint:disable-next-line:max-line-length
616+
throw new Error(`${distributionConfig.viewerCertificate.minimumProtocolVersion} is not compabtible with sslMethod ${distributionConfig.viewerCertificate.sslSupportMethod}.\n\tValid Protocols are: ${validProtocols.join(", ")}`);
617+
}
618+
}
558619
} else {
559620
distributionConfig.viewerCertificate = {
560621
cloudFrontDefaultCertificate: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"Resources": {
3+
"AnAmazingWebsiteProbablyCFDistribution47E3983B": {
4+
"Type": "AWS::CloudFront::Distribution",
5+
"Properties": {
6+
"DistributionConfig": {
7+
"CacheBehaviors": [],
8+
"DefaultCacheBehavior": {
9+
"AllowedMethods": [
10+
"GET",
11+
"HEAD"
12+
],
13+
"CachedMethods": [
14+
"GET",
15+
"HEAD"
16+
],
17+
"ForwardedValues": {
18+
"Cookies": {
19+
"Forward": "none"
20+
},
21+
"QueryString": false
22+
},
23+
"TargetOriginId": "origin1",
24+
"ViewerProtocolPolicy": "redirect-to-https"
25+
},
26+
"DefaultRootObject": "index.html",
27+
"Enabled": true,
28+
"HttpVersion": "http2",
29+
"IPV6Enabled": true,
30+
"Origins": [
31+
{
32+
"CustomOriginConfig": {
33+
"HTTPPort": 80,
34+
"HTTPSPort": 443,
35+
"OriginKeepaliveTimeout": 5,
36+
"OriginProtocolPolicy": "https-only",
37+
"OriginReadTimeout": 30,
38+
"OriginSSLProtocols": [
39+
"TLSv1.2"
40+
]
41+
},
42+
"DomainName": "brelandm.a2z.com",
43+
"Id": "origin1",
44+
"OriginCustomHeaders": [
45+
{
46+
"HeaderName": "X-Custom-Header",
47+
"HeaderValue": "somevalue"
48+
}
49+
]
50+
}
51+
],
52+
"PriceClass": "PriceClass_100",
53+
"ViewerCertificate": {
54+
"AcmCertificateArn": "testACM",
55+
"MinimumProtocolVersion": "TLSv1",
56+
"SslSupportMethod": "sni-only"
57+
},
58+
"Aliases": [
59+
"test.test.com"
60+
]
61+
}
62+
}
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
import cdk = require('@aws-cdk/cdk');
3+
import cloudfront = require('../lib');
4+
5+
const app = new cdk.App(process.argv);
6+
7+
const stack = new cdk.Stack(app, 'aws-cdk-cloudfront-custom');
8+
9+
new cloudfront.CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', {
10+
originConfigs: [
11+
{
12+
originHeaders: {
13+
"X-Custom-Header": "somevalue",
14+
},
15+
customOriginSource: {
16+
domainName: "brelandm.a2z.com",
17+
},
18+
behaviors: [
19+
{
20+
isDefaultBehavior: true,
21+
}
22+
]
23+
}
24+
],
25+
aliasConfiguration: {
26+
acmCertRef: 'testACM',
27+
names: ['test.test.com'],
28+
sslMethod: cloudfront.SSLMethod.SNI,
29+
securityPolicy: cloudfront.SecurityPolicyProtocol.TLSv1
30+
}
31+
});
32+
33+
process.stdout.write(app.run());

0 commit comments

Comments
 (0)