Skip to content

Commit

Permalink
1) Updated MediaStoreContainer reference to @aws-cdk/core
Browse files Browse the repository at this point in the history
2) Added HTTP security header prop for CloudFront
3) Changed scope to this to create resources in the pattern
4) Updated the unit tests
  • Loading branch information
beomseoklee committed Dec 10, 2020
1 parent 51a7ace commit 0f5c185
Show file tree
Hide file tree
Showing 17 changed files with 1,437 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ _Parameters_
|existingMediaStoreContainerObj?|[`mediastore.CfnContainer`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-mediastore.CfnContainer.html)|Optional user provided MediaStore container to override the default MediaStore container.|
|mediaStoreContainerProps?|[`mediastore.CfnContainerProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-mediastore.CfnContainerProps.html)|Optional user provided props to override the default props for the MediaStore Container.|
|cloudFrontDistributionProps?|[`cloudfront.DistributionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.DistributionProps.html)\|`any`|Optional user provided props to override the default props for the CloudFront Distribution.|
|insertHttpSecurityHeaders?|`boolean`|Optional user provided props to turn on/off the automatic injection of best practice HTTP security headers in all responses from CloudFront|

## Pattern Properties

Expand All @@ -64,6 +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.|

## Default settings

Expand All @@ -73,13 +75,15 @@ Out of the box implementation of the Construct without any override will set the
* Configure access logging for CloudFront Web Distribution
* Enable CloudFront Origin Request Policy for AWS Elemental MediaStore Container
* Set `User-Agent` custom header with CloudFront Origin Access Identity
* Enable automatic injection of best practice HTTP security headers in all responses from CloudFront WebDistribution

### AWS Elemental MediaStore
* Set the deletion policy to retain the resource
* Set the container name with the CloudFormation stack name
* Set the default [Container Cross-origin resource sharing (CORS) policy](https://docs.aws.amazon.com/mediastore/latest/ug/cors-policy.html)
* Set the default [Object Life Cycle policy](https://docs.aws.amazon.com/mediastore/latest/ug/policies-object-lifecycle.html)
* Set the default [Container Policy](https://docs.aws.amazon.com/mediastore/latest/ug/policies.html) to allow only `aws:UserAgent` with CloudFront Origin Access Identity
* Set the default [Metric Policy](https://docs.aws.amazon.com/mediastore/latest/ug/policies-metric.html)
* Enable the access logging

## Architecture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
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';
import { MediaStoreContainer } from '../../core/lib/mediastore-helper';

/**
* @summary The properties for the CloudFrontToMediaStore Construct
Expand All @@ -40,6 +40,13 @@ export interface CloudFrontToMediaStoreProps {
* @default - Default props are used
*/
readonly cloudFrontDistributionProps?: cloudfront.DistributionProps | any;
/**
* Optional user provided props to turn on/off the automatic injection of best practice HTTP
* security headers in all responses from cloudfront
*
* @default - true
*/
readonly insertHttpSecurityHeaders?: boolean;
}

export class CloudFrontToMediaStore extends Construct {
Expand All @@ -48,6 +55,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;

/**
* @summary Constructs a new instance of CloudFrontToMediaStore class.
Expand All @@ -70,7 +78,7 @@ export class CloudFrontToMediaStore extends Construct {
if (props.mediaStoreContainerProps) {
mediaStoreProps = props.mediaStoreContainerProps;
} else {
this.cloudFrontOriginAccessIdentity = defaults.CloudFrontOriginAccessIdentity(scope);
this.cloudFrontOriginAccessIdentity = defaults.CloudFrontOriginAccessIdentity(this);

mediaStoreProps = {
containerName: Aws.STACK_NAME,
Expand Down Expand Up @@ -108,10 +116,10 @@ export class CloudFrontToMediaStore extends Construct {
}
}

this.mediaStoreContainer = MediaStoreContainer(scope, mediaStoreProps);
this.mediaStoreContainer = defaults.MediaStoreContainer(this, mediaStoreProps);
}

[this.cloudFrontWebDistribution, this.cloudFrontLoggingBucket, this.cloudFrontOriginRequestPolicy]
= defaults.CloudFrontDistributionForMediaStore(scope, this.mediaStoreContainer, cloudFrontDistributionProps);
[this.cloudFrontWebDistribution, this.cloudFrontLoggingBucket, this.cloudFrontOriginRequestPolicy, this.edgeLambdaFunctionVersion]
= defaults.CloudFrontDistributionForMediaStore(this, this.mediaStoreContainer, cloudFrontDistributionProps, props.insertHttpSecurityHeaders);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@aws-cdk/aws-cloudfront": "0.0.0",
"@aws-cdk/aws-mediastore": "0.0.0",
"@aws-cdk/aws-s3": "0.0.0",
"@aws-cdk/aws-lambda": "0.0.0",
"@aws-solutions-constructs/core": "0.0.0",
"constructs": "^3.2.27"
},
Expand All @@ -75,6 +76,7 @@
"@aws-cdk/aws-cloudfront": "0.0.0",
"@aws-cdk/aws-mediastore": "0.0.0",
"@aws-cdk/aws-s3": "0.0.0",
"@aws-cdk/aws-lambda": "0.0.0",
"@aws-solutions-constructs/core": "0.0.0",
"constructs": "^3.2.27"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Test the default deployment snapshot 1`] = `
Object {
"Resources": Object {
"CloudFrontDistributionBA64CE3A": Object {
"testcloudfrontmediastoreCloudFrontDistributionED9265B1": Object {
"Metadata": Object {
"cfn_nag": Object {
"rules_to_suppress": Array [
Expand All @@ -29,10 +29,18 @@ Object {
"OPTIONS",
],
"Compress": true,
"LambdaFunctionAssociations": Array [
Object {
"EventType": "origin-response",
"LambdaFunctionARN": Object {
"Ref": "testcloudfrontmediastoreSetHttpSecurityHeadersVersionE87B65C3",
},
},
],
"OriginRequestPolicyId": Object {
"Ref": "CloudfrontOriginRequestPolicy299A10DB",
"Ref": "testcloudfrontmediastoreCloudfrontOriginRequestPolicyA1D988D3",
},
"TargetOriginId": "CloudFrontDistributionOrigin176EC3A12",
"TargetOriginId": "testcloudfrontmediastoreCloudFrontDistributionOrigin1BBFA2A4D",
"ViewerProtocolPolicy": "redirect-to-https",
},
"Enabled": true,
Expand All @@ -41,7 +49,7 @@ Object {
"Logging": Object {
"Bucket": Object {
"Fn::GetAtt": Array [
"CloudfrontLoggingBucket3C3EFAA7",
"testcloudfrontmediastoreCloudfrontLoggingBucketA3A51E6A",
"RegionalDomainName",
],
},
Expand All @@ -65,7 +73,7 @@ Object {
"://",
Object {
"Fn::GetAtt": Array [
"MediaStoreContainer",
"testcloudfrontmediastoreMediaStoreContainerF60A96BB",
"Endpoint",
],
},
Expand All @@ -77,12 +85,12 @@ Object {
},
],
},
"Id": "CloudFrontDistributionOrigin176EC3A12",
"Id": "testcloudfrontmediastoreCloudFrontDistributionOrigin1BBFA2A4D",
"OriginCustomHeaders": Array [
Object {
"HeaderName": "User-Agent",
"HeaderValue": Object {
"Ref": "CloudFrontOriginAccessIdentity04EB66DA",
"Ref": "testcloudfrontmediastoreCloudFrontOriginAccessIdentity966405A0",
},
},
],
Expand All @@ -92,7 +100,7 @@ Object {
},
"Type": "AWS::CloudFront::Distribution",
},
"CloudFrontOriginAccessIdentity04EB66DA": Object {
"testcloudfrontmediastoreCloudFrontOriginAccessIdentity966405A0": Object {
"Properties": Object {
"CloudFrontOriginAccessIdentityConfig": Object {
"Comment": Object {
Expand All @@ -114,7 +122,7 @@ Object {
},
"Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity",
},
"CloudfrontLoggingBucket3C3EFAA7": Object {
"testcloudfrontmediastoreCloudfrontLoggingBucketA3A51E6A": Object {
"DeletionPolicy": "Retain",
"Metadata": Object {
"cfn_nag": Object {
Expand Down Expand Up @@ -147,10 +155,10 @@ Object {
"Type": "AWS::S3::Bucket",
"UpdateReplacePolicy": "Retain",
},
"CloudfrontLoggingBucketPolicy8FC0956D": Object {
"testcloudfrontmediastoreCloudfrontLoggingBucketPolicyF3B44DFD": Object {
"Properties": Object {
"Bucket": Object {
"Ref": "CloudfrontLoggingBucket3C3EFAA7",
"Ref": "testcloudfrontmediastoreCloudfrontLoggingBucketA3A51E6A",
},
"PolicyDocument": Object {
"Statement": Array [
Expand All @@ -169,7 +177,7 @@ Object {
Array [
Object {
"Fn::GetAtt": Array [
"CloudfrontLoggingBucket3C3EFAA7",
"testcloudfrontmediastoreCloudfrontLoggingBucketA3A51E6A",
"Arn",
],
},
Expand All @@ -185,7 +193,7 @@ Object {
},
"Type": "AWS::S3::BucketPolicy",
},
"CloudfrontOriginRequestPolicy299A10DB": Object {
"testcloudfrontmediastoreCloudfrontOriginRequestPolicyA1D988D3": Object {
"Properties": Object {
"OriginRequestPolicyConfig": Object {
"Comment": "Policy for Constructs CloudFrontDistributionForMediaStore",
Expand Down Expand Up @@ -223,7 +231,7 @@ Object {
},
"Type": "AWS::CloudFront::OriginRequestPolicy",
},
"MediaStoreContainer": Object {
"testcloudfrontmediastoreMediaStoreContainerF60A96BB": Object {
"DeletionPolicy": "Retain",
"Properties": Object {
"AccessLoggingEnabled": true,
Expand All @@ -248,6 +256,9 @@ Object {
},
],
"LifecyclePolicy": "{\\"rules\\":[{\\"definition\\":{\\"path\\":[{\\"wildcard\\":\\"*\\"}],\\"days_since_create\\":[{\\"numeric\\":[\\">\\",30]}]},\\"action\\":\\"EXPIRE\\"}]}",
"MetricPolicy": Object {
"ContainerLevelMetrics": "ENABLED",
},
"Policy": Object {
"Fn::Join": Array [
"",
Expand All @@ -270,7 +281,7 @@ Object {
},
"/*\\",\\"Condition\\":{\\"Bool\\":{\\"aws:UserAgent\\":\\"",
Object {
"Ref": "CloudFrontOriginAccessIdentity04EB66DA",
"Ref": "testcloudfrontmediastoreCloudFrontOriginAccessIdentity966405A0",
},
"\\",\\"aws:SecureTransport\\":\\"true\\"}}}]}",
],
Expand All @@ -279,6 +290,143 @@ 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 more tighter permissions.",
},
],
},
},
"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",
},
},
"Type": "AWS::Lambda::Version",
},
},
}
`;
Loading

0 comments on commit 0f5c185

Please sign in to comment.