Skip to content

Commit

Permalink
feat(aws-cloudfront): Support Security Policy (#804)
Browse files Browse the repository at this point in the history
Adds support for changing the default Security Policy (minimumProtocolVersion) with logic to ensure the proper one is being set for your SSLMethod.

Fixes #795
  • Loading branch information
ZeldoKavira authored and rix0rrr committed Sep 28, 2018
1 parent 2a2b7a1 commit 8a5299a
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 12 deletions.
85 changes: 73 additions & 12 deletions packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,45 @@ export enum ViewerProtocolPolicy {
}

/**
* CloudFront can use a custom domain that you provide instead of a "cloudfront.net" domain.
* To use this feature - you must provide the list of additional domains,
* and the ACM Certificate that CloudFront should use for these additional domains.
* Configuration for custom domain names
*
* Note - CloudFront only accepts one additional certificate - therefore the certificate *must*
* use have SANs (Subject Alternative Names) for all domains listed.
*
* sslMethod is optional - we default to SNI if not specified. See the notes on SSLMethod if you wish to use other SSL termination types.
*
* @default sslMethod: SNI by default
* CloudFront can use a custom domain that you provide instead of a
* "cloudfront.net" domain. To use this feature you must provide the list of
* additional domains, and the ACM Certificate that CloudFront should use for
* these additional domains.
*/
export interface AliasConfiguration {
readonly names: string[],
readonly acmCertRef: string,
readonly sslMethod?: SSLMethod,
/**
* ARN of an AWS Certificate Manager (ACM) certificate.
*/
readonly acmCertRef: string;

/**
* Domain names on the certificate
*
* Both main domain name and Subject Alternative Names.
*/
readonly names: string[];

/**
* How CloudFront should serve HTTPS requests.
*
* See the notes on SSLMethod if you wish to use other SSL termination types.
*
* @default SNI
* @see https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ViewerCertificate.html
*/
readonly sslMethod?: SSLMethod;

/**
* The minimum version of the SSL protocol that you want CloudFront to use for HTTPS connections.
*
* CloudFront serves your objects only to browsers or devices that support at
* least the SSL version that you specify.
*
* @default securityPolicy: SSLv3 if sslMethod VIP, TLSv1 if sslMethod SNI
*/
readonly securityPolicy?: SecurityPolicyProtocol;
}

/**
Expand All @@ -64,6 +88,18 @@ export enum SSLMethod {
VIP = "vip"
}

/**
* The minimum version of the SSL protocol that you want CloudFront to use for HTTPS connections.
* CloudFront serves your objects only to browsers or devices that support at least the SSL version that you specify.
*/
export enum SecurityPolicyProtocol {
SSLv3 = "SSLv3",
TLSv1 = "TLSv1",
TLSv1_2016 = "TLSv1_2016",
TLSv1_1_2016 = "TLSv1.1_2016",
TLSv1_2_2018 = "TLSv1.2_2018"
}

/**
* CloudFront supports logging of incoming requests and can log details to a given S3 Bucket.
*
Expand Down Expand Up @@ -453,6 +489,17 @@ export class CloudFrontWebDistribution extends cdk.Construct {
ALL: ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"],
};

/**
* Maps for which SecurityPolicyProtocol are available to which SSLMethods
*/
private readonly VALID_SSL_PROTOCOLS: { [key: string]: string[] } = {
"sni-only": [
SecurityPolicyProtocol.TLSv1, SecurityPolicyProtocol.TLSv1_1_2016,
SecurityPolicyProtocol.TLSv1_2016, SecurityPolicyProtocol.TLSv1_2_2018
],
"vip": [SecurityPolicyProtocol.SSLv3, SecurityPolicyProtocol.TLSv1],
};

constructor(parent: cdk.Construct, name: string, props: CloudFrontWebDistributionProps) {
super(parent, name);

Expand Down Expand Up @@ -554,7 +601,21 @@ export class CloudFrontWebDistribution extends cdk.Construct {
distributionConfig.viewerCertificate = {
acmCertificateArn: props.aliasConfiguration.acmCertRef,
sslSupportMethod: props.aliasConfiguration.sslMethod || SSLMethod.SNI,
minimumProtocolVersion: props.aliasConfiguration.securityPolicy
};

if (distributionConfig.viewerCertificate.minimumProtocolVersion !== undefined) {
const validProtocols = this.VALID_SSL_PROTOCOLS[distributionConfig.viewerCertificate.sslSupportMethod!.toString()];

if (validProtocols === undefined) {
throw new Error(`Invalid sslMethod. ${distributionConfig.viewerCertificate.sslSupportMethod!.toString()} is not fully implemented yet.`);
}

if (validProtocols.indexOf(distributionConfig.viewerCertificate.minimumProtocolVersion.toString()) === -1) {
// tslint:disable-next-line:max-line-length
throw new Error(`${distributionConfig.viewerCertificate.minimumProtocolVersion} is not compabtible with sslMethod ${distributionConfig.viewerCertificate.sslSupportMethod}.\n\tValid Protocols are: ${validProtocols.join(", ")}`);
}
}
} else {
distributionConfig.viewerCertificate = {
cloudFrontDefaultCertificate: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"Resources": {
"AnAmazingWebsiteProbablyCFDistribution47E3983B": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"CacheBehaviors": [],
"DefaultCacheBehavior": {
"AllowedMethods": [
"GET",
"HEAD"
],
"CachedMethods": [
"GET",
"HEAD"
],
"ForwardedValues": {
"Cookies": {
"Forward": "none"
},
"QueryString": false
},
"TargetOriginId": "origin1",
"ViewerProtocolPolicy": "redirect-to-https"
},
"DefaultRootObject": "index.html",
"Enabled": true,
"HttpVersion": "http2",
"IPV6Enabled": true,
"Origins": [
{
"CustomOriginConfig": {
"HTTPPort": 80,
"HTTPSPort": 443,
"OriginKeepaliveTimeout": 5,
"OriginProtocolPolicy": "https-only",
"OriginReadTimeout": 30,
"OriginSSLProtocols": [
"TLSv1.2"
]
},
"DomainName": "brelandm.a2z.com",
"Id": "origin1",
"OriginCustomHeaders": [
{
"HeaderName": "X-Custom-Header",
"HeaderValue": "somevalue"
}
]
}
],
"PriceClass": "PriceClass_100",
"ViewerCertificate": {
"AcmCertificateArn": "testACM",
"MinimumProtocolVersion": "TLSv1",
"SslSupportMethod": "sni-only"
},
"Aliases": [
"test.test.com"
]
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

import cdk = require('@aws-cdk/cdk');
import cloudfront = require('../lib');

const app = new cdk.App(process.argv);

const stack = new cdk.Stack(app, 'aws-cdk-cloudfront-custom');

new cloudfront.CloudFrontWebDistribution(stack, 'AnAmazingWebsiteProbably', {
originConfigs: [
{
originHeaders: {
"X-Custom-Header": "somevalue",
},
customOriginSource: {
domainName: "brelandm.a2z.com",
},
behaviors: [
{
isDefaultBehavior: true,
}
]
}
],
aliasConfiguration: {
acmCertRef: 'testACM',
names: ['test.test.com'],
sslMethod: cloudfront.SSLMethod.SNI,
securityPolicy: cloudfront.SecurityPolicyProtocol.TLSv1
}
});

process.stdout.write(app.run());

0 comments on commit 8a5299a

Please sign in to comment.