@aws-solutions-constructs/core
Version:
Core CDK Construct for patterns library
916 lines • 105 kB
JavaScript
"use strict";
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
* with the License. A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const assertions_1 = require("aws-cdk-lib/assertions");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const cloudfront = require("aws-cdk-lib/aws-cloudfront");
const lambda = require("aws-cdk-lib/aws-lambda");
const cloudfront_distribution_helper_1 = require("../lib/cloudfront-distribution-helper");
const s3_bucket_helper_1 = require("../lib/s3-bucket-helper");
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
const origins = require("aws-cdk-lib/aws-cloudfront-origins");
const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
const acm = require("aws-cdk-lib/aws-certificatemanager");
const defaults = require("../");
test('check bucket policy metadata', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket
});
const template = assertions_1.Template.fromStack(stack);
template.hasResource('AWS::S3::BucketPolicy', {
Metadata: {
cfn_nag: {
rules_to_suppress: [
{
id: "F16",
reason: "Public website bucket policy requires a wildcard principal"
}
]
}
}
});
});
test('test cloudfront check bucket policy', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::S3::BucketPolicy", {
PolicyDocument: {
Statement: [
{
Action: "s3:*",
Condition: {
Bool: {
"aws:SecureTransport": "false"
}
},
Effect: "Deny",
Principal: {
AWS: "*"
},
Resource: [
{
"Fn::GetAtt": [
"S3Bucket07682993",
"Arn"
]
},
{
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"S3Bucket07682993",
"Arn"
]
},
"/*"
]
]
}
]
}
],
Version: "2012-10-17"
}
});
});
test('test cloudfront with no security headers ', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: {},
httpSecurityHeaders: false
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
Compress: true,
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
}
}
});
});
test('test cloudfront override cloudfront logging bucket ', () => {
const stack = new aws_cdk_lib_1.Stack();
const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}, 'content-bucket');
const logBucket = new aws_s3_1.Bucket(stack, 'cloudfront-log-bucket');
const myprops = {
enableLogging: true,
logBucket
};
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: contentBucketResponse.bucket,
cloudFrontDistributionProps: myprops
});
const template = assertions_1.Template.fromStack(stack);
// Should be content bucket and it's associated S3 logging bucket, plus simple CloudFront log bucket
template.resourceCountIs("AWS::S3::Bucket", 3);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
Logging: {
Bucket: {
"Fn::GetAtt": [
"cloudfrontlogbucketDF7058FB",
"RegionalDomainName"
]
}
}
}
});
});
test('test cloudfront with logging disabled', () => {
const stack = new aws_cdk_lib_1.Stack();
const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const cfDistroProps = {
enableLogging: false,
};
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: contentBucketResponse.bucket,
cloudFrontDistributionProps: cfDistroProps
});
const template = assertions_1.Template.fromStack(stack);
// Should only be content bucket and it's associated S3 logging bucket
template.resourceCountIs("AWS::S3::Bucket", 2);
// There should be no logging of distribution
template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
Logging: assertions_1.Match.anyValue()
}
}
}, 0);
});
test('test cloudfront override properties', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const props = {
defaultBehavior: {
origin: new origins.S3Origin(buildS3BucketResponse.bucket, { originPath: '/testPath' }),
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS
},
};
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: props
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
AllowedMethods: [
"GET",
"HEAD",
"OPTIONS",
"PUT",
"PATCH",
"POST",
"DELETE"
],
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
CachedMethods: [
"GET",
"HEAD",
"OPTIONS"
],
Compress: true,
FunctionAssociations: [
{
EventType: "viewer-response",
FunctionARN: {
"Fn::GetAtt": [
"SetHttpSecurityHeadersEE936115",
"FunctionARN"
]
}
}
],
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
},
Origins: [
{
DomainName: {
"Fn::GetAtt": [
"S3Bucket07682993",
"RegionalDomainName"
]
},
Id: "CloudFrontDistributionOrigin176EC3A12",
OriginPath: '/testPath',
S3OriginConfig: {
OriginAccessIdentity: {
"Fn::Join": [
"",
[
"origin-access-identity/cloudfront/",
{
Ref: "CloudFrontDistributionOrigin1S3Origin3D9CA0E9"
}
]
]
}
}
}
]
}
});
});
test('test override cloudfront with custom cloudfront function', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
// custom cloudfront function
const cloudfrontFunction = new cloudfront.Function(stack, "MyFunction", {
code: cloudfront.FunctionCode.fromInline("exports.handler = (event, context, callback) => {}")
});
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: {
defaultBehavior: {
functionAssociations: [
{
eventType: cloudfront.FunctionEventType.VIEWER_RESPONSE,
function: cloudfrontFunction
}
],
}
}
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
Compress: true,
FunctionAssociations: [
{
EventType: "viewer-response",
FunctionARN: {
"Fn::GetAtt": [
"MyFunction3BAA72D1",
"FunctionARN"
]
}
}
],
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
}
}
});
});
test('test override cloudfront replace custom lambda@edge', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
// custom lambda@edg function
const handler = new lambda.Function(stack, 'SomeHandler', {
functionName: 'SomeHandler',
runtime: defaults.COMMERCIAL_REGION_LAMBDA_NODE_RUNTIME,
handler: 'index.handler',
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
});
const handlerVersion = new lambda.Version(stack, 'SomeHandlerVersion', {
lambda: handler,
});
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: {
defaultBehavior: {
edgeLambdas: [
{
eventType: aws_cloudfront_1.LambdaEdgeEventType.VIEWER_REQUEST,
includeBody: false,
functionVersion: handlerVersion,
}
]
}
},
httpSecurityHeaders: false
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
Compress: true,
LambdaFunctionAssociations: [
{
EventType: "viewer-request",
IncludeBody: false,
LambdaFunctionARN: {
Ref: "SomeHandlerVersionDA986E41"
}
}
],
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
}
}
});
});
test('test cloudfront override cloudfront custom domain names ', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012');
const myprops = {
domainNames: ['mydomains'],
certificate
};
(0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: myprops
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
Aliases: [
"mydomains"
],
}
});
});
test('Are cloudfront log bucket access log bucket properties used', () => {
const stack = new aws_cdk_lib_1.Stack();
const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const testName = 'random-name-avcb';
const response = (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: contentBucketResponse.bucket,
cloudFrontLoggingBucketS3AccessLogBucketProps: { bucketName: testName }
});
expect(response.loggingBucket).toBeDefined();
expect(response.loggingBucketS3AccesssLogBucket).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
// Content Bucket, Content Bucket Access Log, CloudFront Log, CloudFront Log Access Log
template.resourceCountIs("AWS::S3::Bucket", 4);
template.hasResourceProperties("AWS::S3::Bucket", {
BucketName: testName
});
});
test('Is logCloudFrontAccessLog observed', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const response = (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', {
sourceBucket: buildS3BucketResponse.bucket,
logCloudFrontAccessLog: false,
cloudFrontDistributionProps: {},
});
expect(response.loggingBucket).toBeDefined();
expect(response.loggingBucketS3AccesssLogBucket).not.toBeDefined();
const template = assertions_1.Template.fromStack(stack);
// Content Bucket, Content Bucket Access Log, CloudFront Log, NO CloudFront Log Access Log
template.resourceCountIs("AWS::S3::Bucket", 3);
});
// ---------------------------
// Duplicate tests for createCloudFrontOaiDistributinForS3
// ---------------------------
test('check bucket policy metadata - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket
});
const template = assertions_1.Template.fromStack(stack);
template.hasResource('AWS::S3::BucketPolicy', {
Metadata: {
cfn_nag: {
rules_to_suppress: [
{
id: "F16",
reason: "Public website bucket policy requires a wildcard principal"
}
]
}
}
});
});
test('check createCloudFrontOaiDistributionForS3 response', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const response = (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket
});
expect(response.originAccessIdentity).toBeDefined();
expect(response.distribution).toBeDefined();
expect(response.loggingBucket).toBeDefined();
expect(response.cloudfrontFunction).toBeDefined();
expect(response.loggingBucketS3AccesssLogBucket).toBeDefined();
});
test('test cloudfront check bucket policy - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::S3::BucketPolicy", {
PolicyDocument: {
Statement: [
{
Action: "s3:*",
Condition: {
Bool: {
"aws:SecureTransport": "false"
}
},
Effect: "Deny",
Principal: {
AWS: "*"
},
Resource: [
{
"Fn::GetAtt": [
"S3Bucket07682993",
"Arn"
]
},
{
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"S3Bucket07682993",
"Arn"
]
},
"/*"
]
]
}
]
},
{
Action: "s3:GetObject",
Effect: "Allow",
Principal: {
CanonicalUser: {
"Fn::GetAtt": [
"constructsGeneratedOai6A430BBF",
"S3CanonicalUserId"
]
}
},
Resource: {
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"S3Bucket07682993",
"Arn"
]
},
"/*"
]
]
}
}
],
Version: "2012-10-17"
}
});
});
test('test cloudfront with no security headers - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: {},
httpSecurityHeaders: false
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
Compress: true,
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
}
}
});
});
test('test cloudfront override cloudfront logging bucket - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}, 'content-bucket');
const logBucket = new aws_s3_1.Bucket(stack, 'cloudfront-log-bucket');
const myprops = {
enableLogging: true,
logBucket
};
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: contentBucketResponse.bucket,
cloudFrontDistributionProps: myprops
});
const template = assertions_1.Template.fromStack(stack);
// Should be content bucket and it's associated S3 logging bucket, plus simple CloudFront log bucket
template.resourceCountIs("AWS::S3::Bucket", 3);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
Logging: {
Bucket: {
"Fn::GetAtt": [
"cloudfrontlogbucketDF7058FB",
"RegionalDomainName"
]
}
}
}
});
});
test('test cloudfront with logging disabled - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const cfDistroProps = {
enableLogging: false,
};
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: contentBucketResponse.bucket,
cloudFrontDistributionProps: cfDistroProps
});
const template = assertions_1.Template.fromStack(stack);
// Should only be content bucket and it's associated S3 logging bucket
template.resourceCountIs("AWS::S3::Bucket", 2);
// There should be no logging of distribution
template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
Logging: assertions_1.Match.anyValue()
}
}
}, 0);
});
test('test cloudfront override properties - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const props = {
defaultBehavior: {
origin: new origins.S3Origin(buildS3BucketResponse.bucket, { originPath: '/testPath' }),
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS
},
};
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: props
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
AllowedMethods: [
"GET",
"HEAD",
"OPTIONS",
"PUT",
"PATCH",
"POST",
"DELETE"
],
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
CachedMethods: [
"GET",
"HEAD",
"OPTIONS"
],
Compress: true,
FunctionAssociations: [
{
EventType: "viewer-response",
FunctionARN: {
"Fn::GetAtt": [
"SetHttpSecurityHeadersEE936115",
"FunctionARN"
]
}
}
],
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
},
Origins: [
{
DomainName: {
"Fn::GetAtt": [
"S3Bucket07682993",
"RegionalDomainName"
]
},
Id: "CloudFrontDistributionOrigin176EC3A12",
OriginPath: '/testPath',
S3OriginConfig: {
OriginAccessIdentity: {
"Fn::Join": [
"",
[
"origin-access-identity/cloudfront/",
{
Ref: "CloudFrontDistributionOrigin1S3Origin3D9CA0E9"
}
]
]
}
}
}
]
}
});
});
test('test override cloudfront with custom cloudfront function - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
// custom cloudfront function
const cloudfrontFunction = new cloudfront.Function(stack, "MyFunction", {
code: cloudfront.FunctionCode.fromInline("exports.handler = (event, context, callback) => {}")
});
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: {
defaultBehavior: {
functionAssociations: [
{
eventType: cloudfront.FunctionEventType.VIEWER_RESPONSE,
function: cloudfrontFunction
}
],
}
}
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
Compress: true,
FunctionAssociations: [
{
EventType: "viewer-response",
FunctionARN: {
"Fn::GetAtt": [
"MyFunction3BAA72D1",
"FunctionARN"
]
}
}
],
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
}
}
});
});
test('test override cloudfront replace custom lambda@edge - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
// custom lambda@edg function
const handler = new lambda.Function(stack, 'SomeHandler', {
functionName: 'SomeHandler',
runtime: defaults.COMMERCIAL_REGION_LAMBDA_NODE_RUNTIME,
handler: 'index.handler',
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
});
const handlerVersion = new lambda.Version(stack, 'SomeHandlerVersion', {
lambda: handler,
});
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: {
defaultBehavior: {
edgeLambdas: [
{
eventType: aws_cloudfront_1.LambdaEdgeEventType.VIEWER_REQUEST,
includeBody: false,
functionVersion: handlerVersion,
}
]
}
},
httpSecurityHeaders: false
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
DefaultCacheBehavior: {
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
Compress: true,
LambdaFunctionAssociations: [
{
EventType: "viewer-request",
IncludeBody: false,
LambdaFunctionARN: {
Ref: "SomeHandlerVersionDA986E41"
}
}
],
TargetOriginId: "CloudFrontDistributionOrigin176EC3A12",
ViewerProtocolPolicy: "redirect-to-https"
},
DefaultRootObject: "index.html",
Enabled: true,
HttpVersion: "http2",
IPV6Enabled: true,
Logging: {
Bucket: {
"Fn::GetAtt": [
"CloudfrontLoggingBucket3C3EFAA7",
"RegionalDomainName"
]
}
}
}
});
});
test('test cloudfront override cloudfront custom domain names - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012');
const myprops = {
domainNames: ['mydomains'],
certificate
};
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
cloudFrontDistributionProps: myprops
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::CloudFront::Distribution", {
DistributionConfig: {
Aliases: [
"mydomains"
],
}
});
});
test('Are cloudfront log bucket access log bucket properties used - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const testName = 'random-name-avcb';
const response = (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: contentBucketResponse.bucket,
cloudFrontLoggingBucketS3AccessLogBucketProps: { bucketName: testName }
});
expect(response.loggingBucket).toBeDefined();
expect(response.loggingBucketS3AccesssLogBucket).toBeDefined();
const template = assertions_1.Template.fromStack(stack);
// Content Bucket, Content Bucket Access Log, CloudFront Log, CloudFront Log Access Log
template.resourceCountIs("AWS::S3::Bucket", 4);
template.hasResourceProperties("AWS::S3::Bucket", {
BucketName: testName
});
});
test('Is logCloudFrontAccessLog observed - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {});
const response = (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
logCloudFrontAccessLog: false,
cloudFrontDistributionProps: {},
});
expect(response.loggingBucket).toBeDefined();
expect(response.loggingBucketS3AccesssLogBucket).not.toBeDefined();
const template = assertions_1.Template.fromStack(stack);
// Content Bucket, Content Bucket Access Log, CloudFront Log, NO CloudFront Log Access Log
template.resourceCountIs("AWS::S3::Bucket", 3);
});
test('Test that web site enabled buckets throw an error - oai', () => {
const stack = new aws_cdk_lib_1.Stack();
const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {
bucketProps: {
websiteIndexDocument: "index.html"
}
});
const app = () => {
(0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, {
sourceBucket: buildS3BucketResponse.bucket,
logCloudFrontAccessLog: false,
cloudFrontDistributionProps: {},
});
};
// Assertion
expect(app).toThrowError();
});
// ---------------------------
// Prop Tests
// ---------------------------
test('Test CloudFront insertHttpHeaders bad props', () => {
const props = {
insertHttpSecurityHeaders: true,
responseHeadersPolicyProps: {
securityHeadersBehavior: {}
}
};
const app = () => {
defaults.CheckCloudFrontProps(props);
};
// Assertion
expect(app).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.');
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmcm9udC1kaXN0cmlidXRpb24tczMtaGVscGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbG91ZGZyb250LWRpc3RyaWJ1dGlvbi1zMy1oZWxwZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7O0dBV0c7O0FBRUgsdURBQXlEO0FBQ3pELDZDQUFvQztBQUNwQyx5REFBeUQ7QUFDekQsaURBQWlEO0FBQ2pELDBGQUFnSTtBQUNoSSw4REFBd0Q7QUFDeEQsK0NBQTRDO0FBQzVDLDhEQUE4RDtBQUM5RCwrREFBaUU7QUFDakUsMERBQTBEO0FBQzFELGdDQUFnQztBQUVoQyxJQUFJLENBQUMsOEJBQThCLEVBQUUsR0FBRyxFQUFFO0lBQ3hDLE1BQU0sS0FBSyxHQUFHLElBQUksbUJBQUssRUFBRSxDQUFDO0lBQzFCLE1BQU0scUJBQXFCLEdBQUcsSUFBQSxnQ0FBYSxFQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN2RCxJQUFBLGtFQUFpQyxFQUFDLEtBQUssRUFBRSxrQkFBa0IsRUFBRTtRQUMzRCxZQUFZLEVBQUUscUJBQXFCLENBQUMsTUFBTTtLQUMzQyxDQUFDLENBQUM7SUFDSCxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzQyxRQUFRLENBQUMsV0FBVyxDQUFDLHVCQUF1QixFQUFFO1FBQzVDLFFBQVEsRUFBRTtZQUNSLE9BQU8sRUFBRTtnQkFDUCxpQkFBaUIsRUFBRTtvQkFDakI7d0JBQ0UsRUFBRSxFQUFFLEtBQUs7d0JBQ1QsTUFBTSxFQUFFLDREQUE0RDtxQkFDckU7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMscUNBQXFDLEVBQUUsR0FBRyxFQUFFO0lBQy9DLE1BQU0sS0FBSyxHQUFHLElBQUksbUJBQUssRUFBRSxDQUFDO0lBQzFCLE1B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