diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md index b3c1631b5..2b2528629 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/README.md @@ -65,7 +65,7 @@ _Parameters_ |cloudFrontLoggingBucket|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of s3.Bucket as the logging bucket for the CloudFront Web Distribution.| |cloudFrontOriginRequestPolicy|[`cloudfront.OriginRequestPolicy`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.OriginRequestPolicy.html)|Returns an instance of cloudfront.OriginRequestPolicy created by the construct for the CloudFront Web Distribution.| |cloudFrontOriginAccessIdentity?|[`cloudfront.OriginAccessIdentity`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.OriginAccessIdentity.html)|Returns an instance of cloudfront.OriginAccessIdentity created by the construct for the CloudFront Web Distribution origin custom headers and the MediaStore Container policy.| -|edgeLambdaFunctionVersion|[`lambda.Version`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Version.html)|Returns an instance of the edge Lambda function version created by the pattern.| +|cloudFrontFunction?|[`cloudfront.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.Function.html)|Returns an instance of the Cloudfront function created by the pattern.| ## Default settings diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts index de23dd844..fa26509aa 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/lib/index.ts @@ -14,7 +14,6 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as mediastore from '@aws-cdk/aws-mediastore'; import * as s3 from '@aws-cdk/aws-s3'; -import * as lambda from '@aws-cdk/aws-lambda'; import * as defaults from '@aws-solutions-constructs/core'; import { Construct, Aws} from '@aws-cdk/core'; @@ -55,7 +54,7 @@ export class CloudFrontToMediaStore extends Construct { public readonly cloudFrontLoggingBucket: s3.Bucket; public readonly cloudFrontOriginRequestPolicy: cloudfront.OriginRequestPolicy; public readonly cloudFrontOriginAccessIdentity?: cloudfront.OriginAccessIdentity; - public readonly edgeLambdaFunctionVersion?: lambda.Version; + public readonly cloudFrontFunction?: cloudfront.Function; /** * @summary Constructs a new instance of CloudFrontToMediaStore class. @@ -122,7 +121,7 @@ export class CloudFrontToMediaStore extends Construct { this.mediaStoreContainer = defaults.MediaStoreContainer(this, mediaStoreProps); } - [this.cloudFrontWebDistribution, this.cloudFrontLoggingBucket, this.cloudFrontOriginRequestPolicy, this.edgeLambdaFunctionVersion] + [this.cloudFrontWebDistribution, this.cloudFrontLoggingBucket, this.cloudFrontOriginRequestPolicy, this.cloudFrontFunction] = defaults.CloudFrontDistributionForMediaStore(this, this.mediaStoreContainer, cloudFrontDistributionProps, props.insertHttpSecurityHeaders); } } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/__snapshots__/cloudfront-mediastore.test.js.snap b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/__snapshots__/cloudfront-mediastore.test.js.snap index c7b148fb1..310436630 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/__snapshots__/cloudfront-mediastore.test.js.snap +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/__snapshots__/cloudfront-mediastore.test.js.snap @@ -29,11 +29,14 @@ Object { "OPTIONS", ], "Compress": true, - "LambdaFunctionAssociations": Array [ + "FunctionAssociations": Array [ Object { - "EventType": "origin-response", - "LambdaFunctionARN": Object { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3", + "EventType": "viewer-response", + "FunctionARN": Object { + "Fn::GetAtt": Array [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN", + ], }, }, ], @@ -307,149 +310,16 @@ Object { "Type": "AWS::MediaStore::Container", }, "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D": Object { - "DependsOn": Array [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449", - ], - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions.", - }, - Object { - "id": "W89", - "reason": "This is not a rule for the general case, just for specific use cases/industries", - }, - Object { - "id": "W92", - "reason": "Impossible for us to define the correct concurrency for clients", - }, - ], - }, - }, - "Properties": Object { - "Code": Object { - "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449", - "Arn", - ], - }, - "Runtime": "nodejs12.x", - "TracingConfig": Object { - "Mode": "Active", - }, - }, - "Type": "AWS::Lambda::Function", - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "edgelambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/lambda/*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407": Object { - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W12", - "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC.", - }, - ], - }, - }, - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "xray:PutTraceSegments", - "xray:PutTelemetryRecords", - ], - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "Roles": Array [ - Object { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3": Object { "Properties": Object { - "FunctionName": Object { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "AutoPublish": true, + "FunctionCode": "function handler(event) { var response = event.response; var headers = response.headers; headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload'}; headers['content-security-policy'] = { value: \\"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'\\"}; headers['x-content-type-options'] = { value: 'nosniff'}; headers['x-frame-options'] = {value: 'DENY'}; headers['x-xss-protection'] = {value: '1; mode=block'}; return response; }", + "FunctionConfig": Object { + "Comment": "SetHttpSecurityHeadersc82c7d803c8b3899ab37eeee5cc2bce7beb7673c36", + "Runtime": "cloudfront-js-1.0", }, + "Name": "SetHttpSecurityHeadersc82c7d803c8b3899ab37eeee5cc2bce7beb7673c36", }, - "Type": "AWS::Lambda::Version", + "Type": "AWS::CloudFront::Function", }, }, } diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts index 78581be68..ffc81e8d1 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/cloudfront-mediastore.test.ts @@ -45,7 +45,7 @@ test('Test the default deployment pattern variables', () => { expect(cloudFrontToMediaStore.cloudFrontLoggingBucket).not.toEqual(undefined); expect(cloudFrontToMediaStore.cloudFrontOriginRequestPolicy).not.toEqual(undefined); expect(cloudFrontToMediaStore.cloudFrontOriginAccessIdentity).not.toEqual(undefined); - expect(cloudFrontToMediaStore.edgeLambdaFunctionVersion).not.toEqual(undefined); + expect(cloudFrontToMediaStore.cloudFrontFunction).not.toEqual(undefined); }); // -------------------------------------------------------------- @@ -135,7 +135,7 @@ test('Test the deployment without HTTP security headers', () => { ] } }); - expect(cloudFrontToMediaStore.edgeLambdaFunctionVersion).toEqual(undefined); + expect(cloudFrontToMediaStore.cloudFrontFunction).toEqual(undefined); }); // -------------------------------------------------------------- @@ -167,11 +167,14 @@ test('Test the deployment with existing MediaStore container', () => { 'OPTIONS' ], Compress: true, - LambdaFunctionAssociations: [ + FunctionAssociations: [ { - EventType: 'origin-response', - LambdaFunctionARN: { - Ref: 'testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3' + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN" + ] } } ], @@ -303,11 +306,14 @@ test('Test the deployment with the user provided MediaStore properties', () => { 'OPTIONS' ], Compress: true, - LambdaFunctionAssociations: [ + FunctionAssociations: [ { - EventType: 'origin-response', - LambdaFunctionARN: { - Ref: 'testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3' + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN" + ] } } ], @@ -446,11 +452,14 @@ test('Test the deployment with the user provided CloudFront properties', () => { 'HEAD' ], Compress: true, - LambdaFunctionAssociations: [ + FunctionAssociations: [ { - EventType: 'origin-response', - LambdaFunctionARN: { - Ref: 'testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3' + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN" + ] } } ], diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.default.expected.json b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.default.expected.json index e542136bc..69c2e9139 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.default.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.default.expected.json @@ -82,148 +82,15 @@ }, "DeletionPolicy": "Retain" }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/lambda/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "LambdaFunctionServiceRolePolicy" - } - ] - } - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "xray:PutTraceSegments", - "xray:PutTelemetryRecords" - ], - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "Roles": [ - { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449" - } - ] - }, - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W12", - "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC." - } - ] - } - } - }, "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" - }, - "Role": { - "Fn::GetAtt": [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs12.x", - "TracingConfig": { - "Mode": "Active" - } - }, - "DependsOn": [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449" - ], - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions." - }, - { - "id": "W89", - "reason": "This is not a rule for the general case, just for specific use cases/industries" - }, - { - "id": "W92", - "reason": "Impossible for us to define the correct concurrency for clients" - } - ] - } - } - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3": { - "Type": "AWS::Lambda::Version", + "Type": "AWS::CloudFront::Function", "Properties": { - "FunctionName": { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D" + "Name": "SetHttpSecurityHeadersc85e0befbf4ed85d473981453c3bd34f0a97efbe49", + "AutoPublish": true, + "FunctionCode": "function handler(event) { var response = event.response; var headers = response.headers; headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload'}; headers['content-security-policy'] = { value: \"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'\"}; headers['x-content-type-options'] = { value: 'nosniff'}; headers['x-frame-options'] = {value: 'DENY'}; headers['x-xss-protection'] = {value: '1; mode=block'}; return response; }", + "FunctionConfig": { + "Comment": "SetHttpSecurityHeadersc85e0befbf4ed85d473981453c3bd34f0a97efbe49", + "Runtime": "cloudfront-js-1.0" } } }, @@ -366,11 +233,14 @@ "OPTIONS" ], "Compress": true, - "LambdaFunctionAssociations": [ + "FunctionAssociations": [ { - "EventType": "origin-response", - "LambdaFunctionARN": { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3" + "EventType": "viewer-response", + "FunctionARN": { + "Fn::GetAtt": [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN" + ] } } ], diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.existingContainer.expected.json b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.existingContainer.expected.json index d18536a04..efaf5cd9c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.existingContainer.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.existingContainer.expected.json @@ -7,148 +7,15 @@ "ContainerName": "MyExistingMediaStoreContainer" } }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/lambda/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "LambdaFunctionServiceRolePolicy" - } - ] - } - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "xray:PutTraceSegments", - "xray:PutTelemetryRecords" - ], - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "Roles": [ - { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449" - } - ] - }, - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W12", - "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC." - } - ] - } - } - }, "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::CloudFront::Function", "Properties": { - "Code": { - "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" - }, - "Role": { - "Fn::GetAtt": [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs12.x", - "TracingConfig": { - "Mode": "Active" - } - }, - "DependsOn": [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449" - ], - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions." - }, - { - "id": "W89", - "reason": "This is not a rule for the general case, just for specific use cases/industries" - }, - { - "id": "W92", - "reason": "Impossible for us to define the correct concurrency for clients" - } - ] - } - } - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3": { - "Type": "AWS::Lambda::Version", - "Properties": { - "FunctionName": { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D" + "Name": "SetHttpSecurityHeadersc8671d40ce388b672e8795a9218fe7e3f368379f42", + "AutoPublish": true, + "FunctionCode": "function handler(event) { var response = event.response; var headers = response.headers; headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload'}; headers['content-security-policy'] = { value: \"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'\"}; headers['x-content-type-options'] = { value: 'nosniff'}; headers['x-frame-options'] = {value: 'DENY'}; headers['x-xss-protection'] = {value: '1; mode=block'}; return response; }", + "FunctionConfig": { + "Comment": "SetHttpSecurityHeadersc8671d40ce388b672e8795a9218fe7e3f368379f42", + "Runtime": "cloudfront-js-1.0" } } }, @@ -291,11 +158,14 @@ "OPTIONS" ], "Compress": true, - "LambdaFunctionAssociations": [ + "FunctionAssociations": [ { - "EventType": "origin-response", - "LambdaFunctionARN": { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3" + "EventType": "viewer-response", + "FunctionARN": { + "Fn::GetAtt": [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN" + ] } } ], diff --git a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.overrideProperties.expected.json b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.overrideProperties.expected.json index 86b274a89..a4e4c61d3 100644 --- a/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.overrideProperties.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-cloudfront-mediastore/test/integ.overrideProperties.expected.json @@ -46,148 +46,15 @@ }, "DeletionPolicy": "Retain" }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com" - } - }, - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "edgelambda.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/lambda/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "LambdaFunctionServiceRolePolicy" - } - ] - } - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "xray:PutTraceSegments", - "xray:PutTelemetryRecords" - ], - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "Roles": [ - { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449" - } - ] - }, - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W12", - "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC." - } - ] - } - } - }, "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" } ]; callback(null, response); };" - }, - "Role": { - "Fn::GetAtt": [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449", - "Arn" - ] - }, - "Handler": "index.handler", - "Runtime": "nodejs12.x", - "TracingConfig": { - "Mode": "Active" - } - }, - "DependsOn": [ - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRoleDefaultPolicy73DF1407", - "testcloudfrontmediastoreSetHttpSecurityHeadersServiceRole2F1F5449" - ], - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions." - }, - { - "id": "W89", - "reason": "This is not a rule for the general case, just for specific use cases/industries" - }, - { - "id": "W92", - "reason": "Impossible for us to define the correct concurrency for clients" - } - ] - } - } - }, - "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3": { - "Type": "AWS::Lambda::Version", + "Type": "AWS::CloudFront::Function", "Properties": { - "FunctionName": { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D" + "Name": "SetHttpSecurityHeadersc8f338626119f90653fe964a54eb18cb4a8d6406ce", + "AutoPublish": true, + "FunctionCode": "function handler(event) { var response = event.response; var headers = response.headers; headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload'}; headers['content-security-policy'] = { value: \"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'\"}; headers['x-content-type-options'] = { value: 'nosniff'}; headers['x-frame-options'] = {value: 'DENY'}; headers['x-xss-protection'] = {value: '1; mode=block'}; return response; }", + "FunctionConfig": { + "Comment": "SetHttpSecurityHeadersc8f338626119f90653fe964a54eb18cb4a8d6406ce", + "Runtime": "cloudfront-js-1.0" } } }, @@ -333,11 +200,14 @@ "HEAD" ], "Compress": true, - "LambdaFunctionAssociations": [ + "FunctionAssociations": [ { - "EventType": "origin-response", - "LambdaFunctionARN": { - "Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3" + "EventType": "viewer-response", + "FunctionARN": { + "Fn::GetAtt": [ + "testcloudfrontmediastoreSetHttpSecurityHeaders9995A63D", + "FunctionARN" + ] } } ], diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts index b07ebc1ef..b56695ea6 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-defaults.ts @@ -15,7 +15,6 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as origins from '@aws-cdk/aws-cloudfront-origins'; import * as s3 from '@aws-cdk/aws-s3'; import * as api from '@aws-cdk/aws-apigateway'; -import * as lambda from '@aws-cdk/aws-lambda'; import * as mediastore from '@aws-cdk/aws-mediastore'; import * as cdk from '@aws-cdk/core'; import { FunctionEventType } from '@aws-cdk/aws-cloudfront'; @@ -97,7 +96,7 @@ export function DefaultCloudFrontDisributionForMediaStoreProps(mediastoreContain originRequestPolicy: cloudfront.OriginRequestPolicy, setHttpSecurityHeaders: boolean, customHeaders?: Record, - edgeLambda?: lambda.Version): cloudfront.DistributionProps { + cfFunction?: cloudfront.IFunction): cloudfront.DistributionProps { const mediaStoreContainerUrlWithoutProtocol = cdk.Fn.select(1, cdk.Fn.split('://', mediastoreContainer.attrEndpoint)); const mediaStoreContainerDomainName = cdk.Fn.select(0, cdk.Fn.split('/', mediaStoreContainerUrlWithoutProtocol)); @@ -110,10 +109,10 @@ export function DefaultCloudFrontDisributionForMediaStoreProps(mediastoreContain return { defaultBehavior: { origin: httpOrigin, - edgeLambdas: [ + functionAssociations: [ { - eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, - functionVersion: edgeLambda + eventType: FunctionEventType.VIEWER_RESPONSE, + function: cfFunction } ], viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, diff --git a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts index 85cc25ff1..f4a4bdcfd 100644 --- a/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts +++ b/source/patterns/@aws-solutions-constructs/core/lib/cloudfront-distribution-helper.ts @@ -14,9 +14,7 @@ import * as cloudfront from '@aws-cdk/aws-cloudfront'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import * as iam from '@aws-cdk/aws-iam'; import * as api from '@aws-cdk/aws-apigateway'; -import * as lambda from '@aws-cdk/aws-lambda'; import * as mediastore from '@aws-cdk/aws-mediastore'; import { DefaultCloudFrontWebDistributionForS3Props, @@ -24,7 +22,6 @@ import { DefaultCloudFrontDisributionForMediaStoreProps } from './cloudfront-distribution-defaults'; import { overrideProps, addCfnSuppressRules } from './utils'; -import { deployLambdaFunction } from './lambda-helper'; import { createLoggingBucket } from './s3-bucket-helper'; // Override Cfn_Nag rule: Cloudfront TLS-1.2 rule (https://github.com/stelligent/cfn_nag/issues/384) @@ -39,67 +36,6 @@ function updateSecurityPolicy(cfDistribution: cloudfront.Distribution) { return cfDistribution; } -// Lambda@Edge function to insert the HTTP Security Headers into the response coming from the origin servers -// and before it is sent to the client -function defaultLambdaEdgeFunction(scope: cdk.Construct): lambda.Function { - const edgeLambdaFunc = deployLambdaFunction(scope, { - code: new lambda.InlineCode("exports.handler = (event, context, callback) => { \ - const response = event.Records[0].cf.response; \ - const headers = response.headers; \ - headers['x-xss-protection'] = [ \ - { \ - key: 'X-XSS-Protection', \ - value: '1; mode=block' \ - } \ - ]; \ - headers['x-frame-options'] = [ \ - { \ - key: 'X-Frame-Options', \ - value: 'DENY' \ - } \ - ]; \ - headers['x-content-type-options'] = [ \ - { \ - key: 'X-Content-Type-Options', \ - value: 'nosniff' \ - } \ - ]; \ - headers['strict-transport-security'] = [ \ - { \ - key: 'Strict-Transport-Security', \ - value: 'max-age=63072000; includeSubdomains; preload' \ - } \ - ]; \ - headers['referrer-policy'] = [ \ - { \ - key: 'Referrer-Policy', \ - value: 'same-origin' \ - } \ - ]; \ - headers['content-security-policy'] = [ \ - { \ - key: 'Content-Security-Policy', \ - value: \"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\" \ - } \ - ]; \ - callback(null, response); \ - };"), - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler' - }, 'SetHttpSecurityHeaders'); - - // Switching from cloudfront.CloudFrontWebDistribution -> cloudfront.Distribution breaks the Lamba@Edge as it does not automatically update - // the lambda role AssumePolicy for 'edgelambda.amazonaws.com' - if (edgeLambdaFunc.role && edgeLambdaFunc.role instanceof iam.Role && edgeLambdaFunc.role.assumeRolePolicy) { - edgeLambdaFunc.role.assumeRolePolicy.addStatements(new iam.PolicyStatement({ - actions: [ 'sts:AssumeRole' ], - principals: [ new iam.ServicePrincipal('edgelambda.amazonaws.com') ], - })); - } - - return edgeLambdaFunc; -} - // Cloudfront function to insert the HTTP Security Headers into the response coming from the origin servers // and before it is sent to the client function defaultCloudfrontFunction(scope: cdk.Construct): cloudfront.Function { @@ -165,7 +101,6 @@ export function CloudFrontDistributionForS3(scope: cdk.Construct, cloudfront.Function?, s3.Bucket?] { let defaultprops: cloudfront.DistributionProps; - // let edgeLambdaVersion; let cloudfrontFunction; let loggingBucket; const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; @@ -204,18 +139,16 @@ export function CloudFrontDistributionForMediaStore(scope: cdk.Construct, mediaStoreContainer: mediastore.CfnContainer, cloudFrontDistributionProps?: cloudfront.DistributionProps | any, httpSecurityHeaders?: boolean): [cloudfront.Distribution, - s3.Bucket, cloudfront.OriginRequestPolicy, lambda.Version?] { + s3.Bucket, cloudfront.OriginRequestPolicy, cloudfront.Function?] { let defaultprops: cloudfront.DistributionProps; let originRequestPolicy: cloudfront.OriginRequestPolicy; let loggingBucket: s3.Bucket; - let edgeLambdaVersion: lambda.Version | undefined; + let cloudfrontFunction; const _httpSecurityHeaders = (httpSecurityHeaders !== undefined && httpSecurityHeaders === false) ? false : true; if (_httpSecurityHeaders) { - edgeLambdaVersion = new lambda.Version(scope, 'SetHttpSecurityHeadersVersion', { - lambda: defaultLambdaEdgeFunction(scope) - }); + cloudfrontFunction = defaultCloudfrontFunction(scope); } if (cloudFrontDistributionProps && cloudFrontDistributionProps.enableLogging && cloudFrontDistributionProps.logBucket) { @@ -258,13 +191,13 @@ export function CloudFrontDistributionForMediaStore(scope: cdk.Construct, originRequestPolicy, _httpSecurityHeaders, cloudFrontDistributionProps?.customHeaders, - edgeLambdaVersion + cloudfrontFunction ); let cfprops: cloudfront.DistributionProps; if (cloudFrontDistributionProps) { - cfprops = overrideProps(defaultprops, cloudFrontDistributionProps, true); + cfprops = overrideProps(defaultprops, cloudFrontDistributionProps, false); } else { cfprops = defaultprops; } @@ -273,7 +206,7 @@ export function CloudFrontDistributionForMediaStore(scope: cdk.Construct, const cfDistribution: cloudfront.Distribution = new cloudfront.Distribution(scope, 'CloudFrontDistribution', cfprops); updateSecurityPolicy(cfDistribution); - return [cfDistribution, loggingBucket, originRequestPolicy, edgeLambdaVersion]; + return [cfDistribution, loggingBucket, originRequestPolicy, cloudfrontFunction]; } export function CloudFrontOriginAccessIdentity(scope: cdk.Construct, comment?: string) { diff --git a/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/cloudfront-distribution-mediastore-helper.test.js.snap b/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/cloudfront-distribution-mediastore-helper.test.js.snap index d7eb0b28c..c2d7bf604 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/cloudfront-distribution-mediastore-helper.test.js.snap +++ b/source/patterns/@aws-solutions-constructs/core/test/__snapshots__/cloudfront-distribution-mediastore-helper.test.js.snap @@ -29,11 +29,14 @@ Object { "OPTIONS", ], "Compress": true, - "LambdaFunctionAssociations": Array [ + "FunctionAssociations": Array [ Object { - "EventType": "origin-response", - "LambdaFunctionARN": Object { - "Ref": "SetHttpSecurityHeadersVersion660E2F72", + "EventType": "viewer-response", + "FunctionARN": Object { + "Fn::GetAtt": Array [ + "SetHttpSecurityHeadersEE936115", + "FunctionARN", + ], }, }, ], @@ -224,149 +227,16 @@ Object { "Type": "AWS::MediaStore::Container", }, "SetHttpSecurityHeadersEE936115": Object { - "DependsOn": Array [ - "SetHttpSecurityHeadersServiceRoleDefaultPolicyD336F67B", - "SetHttpSecurityHeadersServiceRoleAF063E32", - ], - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W58", - "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions.", - }, - Object { - "id": "W89", - "reason": "This is not a rule for the general case, just for specific use cases/industries", - }, - Object { - "id": "W92", - "reason": "Impossible for us to define the correct concurrency for clients", - }, - ], - }, - }, - "Properties": Object { - "Code": Object { - "ZipFile": "exports.handler = (event, context, callback) => { const response = event.Records[0].cf.response; const headers = response.headers; headers['x-xss-protection'] = [ { key: 'X-XSS-Protection', value: '1; mode=block' } ]; headers['x-frame-options'] = [ { key: 'X-Frame-Options', value: 'DENY' } ]; headers['x-content-type-options'] = [ { key: 'X-Content-Type-Options', value: 'nosniff' } ]; headers['strict-transport-security'] = [ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload' } ]; headers['referrer-policy'] = [ { key: 'Referrer-Policy', value: 'same-origin' } ]; headers['content-security-policy'] = [ { key: 'Content-Security-Policy', value: \\"default-src 'none'; base-uri 'self'; img-src 'self'; script-src 'self'; style-src 'self' https:; object-src 'none'; frame-ancestors 'none'; font-src 'self' https:; form-action 'self'; manifest-src 'self'; connect-src 'self'\\" } ]; callback(null, response); };", - }, - "Handler": "index.handler", - "Role": Object { - "Fn::GetAtt": Array [ - "SetHttpSecurityHeadersServiceRoleAF063E32", - "Arn", - ], - }, - "Runtime": "nodejs12.x", - "TracingConfig": Object { - "Mode": "Active", - }, - }, - "Type": "AWS::Lambda::Function", - }, - "SetHttpSecurityHeadersServiceRoleAF063E32": Object { - "Properties": Object { - "AssumeRolePolicyDocument": Object { - "Statement": Array [ - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "lambda.amazonaws.com", - }, - }, - Object { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": Object { - "Service": "edgelambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "Policies": Array [ - Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents", - ], - "Effect": "Allow", - "Resource": Object { - "Fn::Join": Array [ - "", - Array [ - "arn:", - Object { - "Ref": "AWS::Partition", - }, - ":logs:", - Object { - "Ref": "AWS::Region", - }, - ":", - Object { - "Ref": "AWS::AccountId", - }, - ":log-group:/aws/lambda/*", - ], - ], - }, - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LambdaFunctionServiceRolePolicy", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, - "SetHttpSecurityHeadersServiceRoleDefaultPolicyD336F67B": Object { - "Metadata": Object { - "cfn_nag": Object { - "rules_to_suppress": Array [ - Object { - "id": "W12", - "reason": "Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC.", - }, - ], - }, - }, - "Properties": Object { - "PolicyDocument": Object { - "Statement": Array [ - Object { - "Action": Array [ - "xray:PutTraceSegments", - "xray:PutTelemetryRecords", - ], - "Effect": "Allow", - "Resource": "*", - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "SetHttpSecurityHeadersServiceRoleDefaultPolicyD336F67B", - "Roles": Array [ - Object { - "Ref": "SetHttpSecurityHeadersServiceRoleAF063E32", - }, - ], - }, - "Type": "AWS::IAM::Policy", - }, - "SetHttpSecurityHeadersVersion660E2F72": Object { "Properties": Object { - "FunctionName": Object { - "Ref": "SetHttpSecurityHeadersEE936115", + "AutoPublish": true, + "FunctionCode": "function handler(event) { var response = event.response; var headers = response.headers; headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload'}; headers['content-security-policy'] = { value: \\"default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'\\"}; headers['x-content-type-options'] = { value: 'nosniff'}; headers['x-frame-options'] = {value: 'DENY'}; headers['x-xss-protection'] = {value: '1; mode=block'}; return response; }", + "FunctionConfig": Object { + "Comment": "SetHttpSecurityHeadersc8adc83b19e793491b1c6ea0fd8b46cd9f32e592fc", + "Runtime": "cloudfront-js-1.0", }, + "Name": "SetHttpSecurityHeadersc8adc83b19e793491b1c6ea0fd8b46cd9f32e592fc", }, - "Type": "AWS::Lambda::Version", + "Type": "AWS::CloudFront::Function", }, }, } diff --git a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-mediastore-helper.test.ts b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-mediastore-helper.test.ts index edc541dbc..cdca6f698 100644 --- a/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-mediastore-helper.test.ts +++ b/source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-mediastore-helper.test.ts @@ -17,10 +17,8 @@ import { Stack } from '@aws-cdk/core'; import * as s3 from '@aws-cdk/aws-s3'; import * as mediastore from '@aws-cdk/aws-mediastore'; import * as cloudfront from '@aws-cdk/aws-cloudfront'; -import * as lambda from '@aws-cdk/aws-lambda'; import * as origins from '@aws-cdk/aws-cloudfront-origins'; import { CloudFrontDistributionForMediaStore, CloudFrontOriginAccessIdentity } from '../lib/cloudfront-distribution-helper'; -import { LambdaEdgeEventType } from '@aws-cdk/aws-cloudfront'; test('CloudFront distribution for MediaStore with default params', () => { const stack = new Stack(); @@ -61,11 +59,14 @@ test('CloudFront distribution for MediaStore with user provided log bucket', () 'OPTIONS' ], Compress: true, - LambdaFunctionAssociations: [ + FunctionAssociations: [ { - EventType: 'origin-response', - LambdaFunctionARN: { - Ref: 'SetHttpSecurityHeadersVersion660E2F72' + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "SetHttpSecurityHeadersEE936115", + "FunctionARN" + ] } } ], @@ -164,11 +165,14 @@ test('CloudFront distribution for MediaStore with user provided origin request p 'OPTIONS' ], Compress: true, - LambdaFunctionAssociations: [ + FunctionAssociations: [ { - EventType: 'origin-response', - LambdaFunctionARN: { - Ref: 'SetHttpSecurityHeadersVersion660E2F72' + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "SetHttpSecurityHeadersEE936115", + "FunctionARN" + ] } } ], @@ -270,11 +274,14 @@ test('CloudFront distribution for MediaStore with user provided custom headers w 'OPTIONS' ], Compress: true, - LambdaFunctionAssociations: [ + FunctionAssociations: [ { - EventType: 'origin-response', - LambdaFunctionARN: { - Ref: 'SetHttpSecurityHeadersVersion660E2F72' + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "SetHttpSecurityHeadersEE936115", + "FunctionARN" + ] } } ], @@ -509,34 +516,26 @@ test('CloudFront distribution for MediaStore override params', () => { }); }); -test('test override cloudfront add custom lambda@edge', () => { +test('test override cloudfront with custom cloudfront function', () => { const stack = new Stack(); const mediaStoreContainerProps: mediastore.CfnContainerProps = { containerName: 'TestContainer' }; const mediaStoreContainer = new mediastore.CfnContainer(stack, 'MediaStoreContainer', mediaStoreContainerProps); - // custom lambda@edg function - const handler = new lambda.Function(stack, 'SomeHandler', { - functionName: 'SomeHandler', - runtime: lambda.Runtime.NODEJS_12_X, - handler: 'index.handler', - code: lambda.Code.fromAsset(`${__dirname}/lambda`), - }); - - const handlerVersion = new lambda.Version(stack, 'SomeHandlerVersion', { - lambda: handler, + // custom cloudfront function + const cloudfrontFunction = new cloudfront.Function(stack, "MyFunction", { + code: cloudfront.FunctionCode.fromInline("exports.handler = (event, context, callback) => {}") }); CloudFrontDistributionForMediaStore(stack, mediaStoreContainer, { defaultBehavior: { - edgeLambdas: [ + functionAssociations: [ { - eventType: LambdaEdgeEventType.VIEWER_REQUEST, - includeBody: false, - functionVersion: handlerVersion, + eventType: cloudfront.FunctionEventType.VIEWER_RESPONSE, + function: cloudfrontFunction } - ] + ], } }); @@ -555,18 +554,14 @@ test('test override cloudfront add custom lambda@edge', () => { "OPTIONS" ], Compress: true, - LambdaFunctionAssociations: [ - { - EventType: "origin-response", - LambdaFunctionARN: { - Ref: "SetHttpSecurityHeadersVersion660E2F72" - } - }, + FunctionAssociations: [ { - EventType: "viewer-request", - IncludeBody: false, - LambdaFunctionARN: { - Ref: "SomeHandlerVersionDA986E41" + EventType: "viewer-response", + FunctionARN: { + "Fn::GetAtt": [ + "MyFunction3BAA72D1", + "FunctionARN" + ] } } ],