diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index 6fa422aee3775..23feb3e48658b 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -1,3 +1,4 @@ +import lambda = require('@aws-cdk/aws-lambda'); import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/cdk'); import { CfnDistribution } from './cloudfront.generated'; @@ -344,6 +345,48 @@ export interface Behavior { */ readonly maxTtlSeconds?: number; + /** + * Declares associated lambda@edge functions for this distribution behaviour. + * + * @default No lambda function associated + */ + readonly lambdaFunctionAssociations?: LambdaFunctionAssociation[]; + +} + +export interface LambdaFunctionAssociation { + + /** + * The lambda event type defines at which event the lambda + * is called during the request lifecycle + */ + readonly eventType: LambdaEdgeEventType; + + /** + * A version of the lambda to associate + */ + readonly lambdaFunction: lambda.IVersion; +} + +export enum LambdaEdgeEventType { + /** + * The origin-request specifies the request to the + * origin location (e.g. S3) + */ + OriginRequest = "origin-request", + /** + * The origin-response specifies the response from the + * origin location (e.g. S3) + */ + OriginResponse = "origin-response", + /** + * The viewer-request specifies the incoming request + */ + ViewerRequest = "viewer-request", + /** + * The viewer-response specifies the outgoing reponse + */ + ViewerResponse = "viewer-response", } export interface ErrorConfiguration { @@ -691,6 +734,15 @@ export class CloudFrontWebDistribution extends cdk.Construct implements IDistrib if (!input.isDefaultBehavior) { toReturn = Object.assign(toReturn, { pathPattern: input.pathPattern }); } + if (input.lambdaFunctionAssociations) { + toReturn = Object.assign(toReturn, { + lambdaFunctionAssociations: input.lambdaFunctionAssociations + .map(fna => ({ + eventType: fna.eventType, + lambdaFunctionArn: fna.lambdaFunction && fna.lambdaFunction.versionArn, + })) + }); + } return toReturn; } } diff --git a/packages/@aws-cdk/aws-cloudfront/package.json b/packages/@aws-cdk/aws-cloudfront/package.json index 9425af35d4cc4..dc7baada25389 100644 --- a/packages/@aws-cdk/aws-cloudfront/package.json +++ b/packages/@aws-cdk/aws-cloudfront/package.json @@ -74,6 +74,7 @@ "@aws-cdk/aws-certificatemanager": "^0.34.0", "@aws-cdk/aws-iam": "^0.34.0", "@aws-cdk/aws-kms": "^0.34.0", + "@aws-cdk/aws-lambda": "^0.34.0", "@aws-cdk/aws-s3": "^0.34.0", "@aws-cdk/cdk": "^0.34.0" }, @@ -82,6 +83,7 @@ "@aws-cdk/aws-certificatemanager": "^0.34.0", "@aws-cdk/aws-iam": "^0.34.0", "@aws-cdk/aws-kms": "^0.34.0", + "@aws-cdk/aws-lambda": "^0.34.0", "@aws-cdk/aws-s3": "^0.34.0", "@aws-cdk/cdk": "^0.34.0" }, @@ -89,4 +91,4 @@ "node": ">= 8.10.0" }, "stability": "experimental" -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json new file mode 100644 index 0000000000000..8c91845416ef1 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json @@ -0,0 +1,129 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket" + }, + "LambdaServiceRoleA8ED4D3B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": { + "Fn::Join": [ + "", + [ + "lambda.", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + } + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "LambdaD247545B": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "foo" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaServiceRoleA8ED4D3B", + "Arn" + ] + }, + "Runtime": "nodejs8.10" + }, + "DependsOn": [ + "LambdaServiceRoleA8ED4D3B" + ] + }, + "LambdaVersionFA49E61E": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "LambdaD247545B" + } + } + }, + "MyDistributionCFDistributionDE147309": { + "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", + "LambdaFunctionAssociations": [ + { + "EventType": "origin-request", + "LambdaFunctionARN": { + "Ref": "LambdaVersionFA49E61E" + } + } + ] + }, + "DefaultRootObject": "index.html", + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "DomainName": { + "Fn::GetAtt": [ + "Bucket83908E77", + "RegionalDomainName" + ] + }, + "Id": "origin1", + "S3OriginConfig": {} + } + ], + "PriceClass": "PriceClass_100", + "ViewerCertificate": { + "CloudFrontDefaultCertificate": true + } + } + } + } + } +} diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.ts new file mode 100644 index 0000000000000..d02adde784341 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.ts @@ -0,0 +1,38 @@ +import lambda = require('@aws-cdk/aws-lambda'); +import s3 = require('@aws-cdk/aws-s3'); +import cdk = require('@aws-cdk/cdk'); +import cloudfront = require('../lib'); + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-cloudfront'); + +const sourceBucket = new s3.Bucket(stack, 'Bucket', { + removalPolicy: cdk.RemovalPolicy.Destroy +}); + +const lambdaFunction = new lambda.Function(stack, 'Lambda', { + code: lambda.Code.inline('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NodeJS810 +}); + +const lambdaVersion = new lambda.Version(stack, 'LambdaVersion', { + lambda: lambdaFunction +}); + +new cloudfront.CloudFrontWebDistribution(stack, 'MyDistribution', { + originConfigs: [ + { + s3OriginSource: { + s3BucketSource: sourceBucket + }, + behaviors : [ {isDefaultBehavior: true, lambdaFunctionAssociations: [{ + eventType: cloudfront.LambdaEdgeEventType.OriginRequest, + lambdaFunction: lambdaVersion + }]}] + } + ] + }); + +app.run(); diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index 800062141a052..c0ee1a3c1cce1 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -9,6 +9,12 @@ export interface IVersion extends IResource { */ readonly version: string; + /** + * The ARN of this version. + * @attribute + */ + readonly versionArn?: string; + /** * The underlying AWS Lambda function. */ @@ -47,6 +53,11 @@ export interface VersionAttributes { */ readonly version: string; + /** + * The version arn. + */ + readonly versionArn?: string; + /** * The lambda function. */ @@ -80,6 +91,7 @@ export class Version extends Resource implements IVersion { } public readonly version: string; + public readonly versionArn?: string; public readonly lambda: IFunction; constructor(scope: Construct, id: string, props: VersionProps) { @@ -92,6 +104,7 @@ export class Version extends Resource implements IVersion { }); this.version = version.version; + this.versionArn = version.versionArn; this.lambda = props.lambda; } }