diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/CMCMK-Stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/CMCMK-Stack.assets.json new file mode 100644 index 0000000000000..c26d906b4b628 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/CMCMK-Stack.assets.json @@ -0,0 +1,97 @@ +{ + "version": "38.0.1", + "files": { + "cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d": { + "source": { + "path": "asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61": { + "source": { + "path": "asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410": { + "source": { + "path": "asset.f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762": { + "source": { + "path": "asset.c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8": { + "source": { + "path": "asset.285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051": { + "source": { + "path": "asset.bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "494c79217eb979e7fb6591a5381b466597a58cfa5673958b5ed08a5d37cd08d3": { + "source": { + "path": "CMCMK-Stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "494c79217eb979e7fb6591a5381b466597a58cfa5673958b5ed08a5d37cd08d3.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/CMCMK-Stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/CMCMK-Stack.template.json new file mode 100644 index 0000000000000..ad436a43d09cb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/CMCMK-Stack.template.json @@ -0,0 +1,739 @@ +{ + "Resources": { + "LambdaExecutionRoleD5C26073": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "LambdaExecutionRoleDefaultPolicy6D69732F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "LambdaExecutionRoleDefaultPolicy6D69732F", + "Roles": [ + { + "Ref": "LambdaExecutionRoleD5C26073" + } + ] + } + }, + "myImportedKey10DE2890": { + "Type": "AWS::KMS::Key", + "Properties": { + "EnableKeyRotation": true, + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:GenerateDataKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "Service": "lambda.amazonaws.com" + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "myFunction156294E5D": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d.zip", + "SourceKMSKeyArn": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "LambdaExecutionRoleDefaultPolicy6D69732F", + "LambdaExecutionRoleD5C26073" + ] + }, + "S3486F821D": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketName": "s3sourcekmskeyarnbucket", + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + }, + { + "Key": "aws-cdk:cr-owned:c0b774e4", + "Value": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "S3Policy2E4AA1D6": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "S3486F821D" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "S3AutoDeleteObjectsCustomResource5A4102C9": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "S3486F821D" + } + }, + "DependsOn": [ + "S3Policy2E4AA1D6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": { + "Fn::FindInMap": [ + "LatestNodeRuntimeMap", + { + "Ref": "AWS::Region" + }, + "value" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "S3486F821D" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + }, + "DeployLambdaCodeAwsCliLayer8743C498": { + "Type": "AWS::Lambda::LayerVersion", + "Properties": { + "Content": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip" + }, + "Description": "/opt/awscli/aws" + } + }, + "DeployLambdaCodeCustomResource0564AA4B": { + "Type": "Custom::CDKBucketDeployment", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536", + "Arn" + ] + }, + "SourceBucketNames": [ + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ], + "SourceObjectKeys": [ + "285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8.zip" + ], + "DestinationBucketName": { + "Ref": "S3486F821D" + }, + "Prune": true, + "OutputObjectKeys": true + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + } + ] + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", + "Roles": [ + { + "Ref": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + } + ] + } + }, + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762.zip" + }, + "Environment": { + "Variables": { + "AWS_CA_BUNDLE": "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" + } + }, + "Handler": "index.handler", + "Layers": [ + { + "Ref": "DeployLambdaCodeAwsCliLayer8743C498" + } + ], + "Role": { + "Fn::GetAtt": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", + "Arn" + ] + }, + "Runtime": "python3.11", + "Timeout": 900 + }, + "DependsOn": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + ] + }, + "myFunction2CB7FFFBF": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "S3486F821D" + }, + "S3Key": "python-lambda-handler.zip", + "SourceKMSKeyArn": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + }, + "Environment": { + "Variables": { + "SOURCE_KMS_KEY_ARN": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "DeployLambdaCodeAwsCliLayer8743C498", + "DeployLambdaCodeCustomResource0564AA4B", + "LambdaExecutionRoleDefaultPolicy6D69732F", + "LambdaExecutionRoleD5C26073" + ] + }, + "myFunction343849752": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip", + "SourceKMSKeyArn": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + }, + "Environment": { + "Variables": { + "SOURCE_KMS_KEY_ARN": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + } + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "Runtime": "python3.11" + }, + "DependsOn": [ + "LambdaExecutionRoleDefaultPolicy6D69732F", + "LambdaExecutionRoleD5C26073" + ] + } + }, + "Mappings": { + "LatestNodeRuntimeMap": { + "af-south-1": { + "value": "nodejs20.x" + }, + "ap-east-1": { + "value": "nodejs20.x" + }, + "ap-northeast-1": { + "value": "nodejs20.x" + }, + "ap-northeast-2": { + "value": "nodejs20.x" + }, + "ap-northeast-3": { + "value": "nodejs20.x" + }, + "ap-south-1": { + "value": "nodejs20.x" + }, + "ap-south-2": { + "value": "nodejs20.x" + }, + "ap-southeast-1": { + "value": "nodejs20.x" + }, + "ap-southeast-2": { + "value": "nodejs20.x" + }, + "ap-southeast-3": { + "value": "nodejs20.x" + }, + "ap-southeast-4": { + "value": "nodejs20.x" + }, + "ap-southeast-5": { + "value": "nodejs20.x" + }, + "ap-southeast-7": { + "value": "nodejs20.x" + }, + "ca-central-1": { + "value": "nodejs20.x" + }, + "ca-west-1": { + "value": "nodejs20.x" + }, + "cn-north-1": { + "value": "nodejs18.x" + }, + "cn-northwest-1": { + "value": "nodejs18.x" + }, + "eu-central-1": { + "value": "nodejs20.x" + }, + "eu-central-2": { + "value": "nodejs20.x" + }, + "eu-isoe-west-1": { + "value": "nodejs18.x" + }, + "eu-north-1": { + "value": "nodejs20.x" + }, + "eu-south-1": { + "value": "nodejs20.x" + }, + "eu-south-2": { + "value": "nodejs20.x" + }, + "eu-west-1": { + "value": "nodejs20.x" + }, + "eu-west-2": { + "value": "nodejs20.x" + }, + "eu-west-3": { + "value": "nodejs20.x" + }, + "il-central-1": { + "value": "nodejs20.x" + }, + "me-central-1": { + "value": "nodejs20.x" + }, + "me-south-1": { + "value": "nodejs20.x" + }, + "mx-central-1": { + "value": "nodejs20.x" + }, + "sa-east-1": { + "value": "nodejs20.x" + }, + "us-east-1": { + "value": "nodejs20.x" + }, + "us-east-2": { + "value": "nodejs20.x" + }, + "us-gov-east-1": { + "value": "nodejs18.x" + }, + "us-gov-west-1": { + "value": "nodejs18.x" + }, + "us-iso-east-1": { + "value": "nodejs18.x" + }, + "us-iso-west-1": { + "value": "nodejs18.x" + }, + "us-isob-east-1": { + "value": "nodejs18.x" + }, + "us-west-1": { + "value": "nodejs20.x" + }, + "us-west-2": { + "value": "nodejs20.x" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets.json new file mode 100644 index 0000000000000..d4c9d8b22e44b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "SourceKMSKeyArnDefaultTestDeployAssertA9940761.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/SourceKMSKeyArnDefaultTestDeployAssertA9940761.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/SourceKMSKeyArnDefaultTestDeployAssertA9940761.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/SourceKMSKeyArnDefaultTestDeployAssertA9940761.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8/python-lambda-handler.zip b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8/python-lambda-handler.zip new file mode 100644 index 0000000000000..a9b5d0d55f1f2 Binary files /dev/null and b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.285f23e3fdafa13515eca3640773e339319628e600ff07e6a6f228748a1ac3e8/python-lambda-handler.zip differ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js new file mode 100644 index 0000000000000..1002ba018e9fb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js @@ -0,0 +1 @@ +"use strict";var f=Object.create;var i=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var A=(t,e)=>{for(var o in e)i(t,o,{get:e[o],enumerable:!0})},d=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of C(e))!P.call(t,s)&&s!==o&&i(t,s,{get:()=>e[s],enumerable:!(r=I(e,s))||r.enumerable});return t};var l=(t,e,o)=>(o=t!=null?f(w(t)):{},d(e||!t||!t.__esModule?i(o,"default",{value:t,enumerable:!0}):o,t)),B=t=>d(i({},"__esModule",{value:!0}),t);var q={};A(q,{autoDeleteHandler:()=>S,handler:()=>H});module.exports=B(q);var h=require("@aws-sdk/client-s3");var y=l(require("https")),m=l(require("url")),a={sendHttpRequest:D,log:T,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",L="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function R(t){return async(e,o)=>{let r={...e,ResponseURL:"..."};if(a.log(JSON.stringify(r,void 0,2)),e.RequestType==="Delete"&&e.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await u("SUCCESS",e);return}try{let s=await t(r,o),n=k(e,s);await u("SUCCESS",n)}catch(s){let n={...e,Reason:a.includeStackTraces?s.stack:s.message};n.PhysicalResourceId||(e.RequestType==="Create"?(a.log("CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored"),n.PhysicalResourceId=p):a.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(e)}`)),await u("FAILED",n)}}}function k(t,e={}){let o=e.PhysicalResourceId??t.PhysicalResourceId??t.RequestId;if(t.RequestType==="Delete"&&o!==t.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${t.PhysicalResourceId}" to "${e.PhysicalResourceId}" during deletion`);return{...t,...e,PhysicalResourceId:o}}async function u(t,e){let o={Status:t,Reason:e.Reason??t,StackId:e.StackId,RequestId:e.RequestId,PhysicalResourceId:e.PhysicalResourceId||L,LogicalResourceId:e.LogicalResourceId,NoEcho:e.NoEcho,Data:e.Data},r=m.parse(e.ResponseURL),s=`${r.protocol}//${r.hostname}/${r.pathname}?***`;a.log("submit response to cloudformation",s,o);let n=JSON.stringify(o),E={hostname:r.hostname,path:r.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(n,"utf8")}};await O({attempts:5,sleep:1e3},a.sendHttpRequest)(E,n)}async function D(t,e){return new Promise((o,r)=>{try{let s=y.request(t,n=>{n.resume(),!n.statusCode||n.statusCode>=400?r(new Error(`Unsuccessful HTTP response: ${n.statusCode}`)):o()});s.on("error",r),s.write(e),s.end()}catch(s){r(s)}})}function T(t,...e){console.log(t,...e)}function O(t,e){return async(...o)=>{let r=t.attempts,s=t.sleep;for(;;)try{return await e(...o)}catch(n){if(r--<=0)throw n;await b(Math.floor(Math.random()*s)),s*=2}}}async function b(t){return new Promise(e=>setTimeout(e,t))}var g="aws-cdk:auto-delete-objects",x=JSON.stringify({Version:"2012-10-17",Statement:[]}),c=new h.S3({}),H=R(S);async function S(t){switch(t.RequestType){case"Create":return;case"Update":return{PhysicalResourceId:(await F(t)).PhysicalResourceId};case"Delete":return N(t.ResourceProperties?.BucketName)}}async function F(t){let e=t,o=e.OldResourceProperties?.BucketName;return{PhysicalResourceId:e.ResourceProperties?.BucketName??o}}async function _(t){try{let e=(await c.getBucketPolicy({Bucket:t}))?.Policy??x,o=JSON.parse(e);o.Statement.push({Principal:"*",Effect:"Deny",Action:["s3:PutObject"],Resource:[`arn:aws:s3:::${t}/*`]}),await c.putBucketPolicy({Bucket:t,Policy:JSON.stringify(o)})}catch(e){if(e.name==="NoSuchBucket")throw e;console.log(`Could not set new object deny policy on bucket '${t}' prior to deletion.`)}}async function U(t){let e;do{e=await c.listObjectVersions({Bucket:t});let o=[...e.Versions??[],...e.DeleteMarkers??[]];if(o.length===0)return;let r=o.map(s=>({Key:s.Key,VersionId:s.VersionId}));await c.deleteObjects({Bucket:t,Delete:{Objects:r}})}while(e?.IsTruncated)}async function N(t){if(!t)throw new Error("No BucketName was provided.");try{if(!await W(t)){console.log(`Bucket does not have '${g}' tag, skipping cleaning.`);return}await _(t),await U(t)}catch(e){if(e.name==="NoSuchBucket"){console.log(`Bucket '${t}' does not exist.`);return}throw e}}async function W(t){return(await c.getBucketTagging({Bucket:t})).TagSet?.some(o=>o.Key===g&&o.Value==="true")}0&&(module.exports={autoDeleteHandler,handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip new file mode 100644 index 0000000000000..a9b5d0d55f1f2 Binary files /dev/null and b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip differ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762/index.py b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762/index.py new file mode 100644 index 0000000000000..8a7928a4c350d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762/index.py @@ -0,0 +1,336 @@ +import contextlib +import json +import logging +import os +import shutil +import subprocess +import tempfile +import urllib.parse +from urllib.request import Request, urlopen +from uuid import uuid4 +from zipfile import ZipFile + +import boto3 + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +cloudfront = boto3.client('cloudfront') +s3 = boto3.client('s3') + +CFN_SUCCESS = "SUCCESS" +CFN_FAILED = "FAILED" +ENV_KEY_MOUNT_PATH = "MOUNT_PATH" +ENV_KEY_SKIP_CLEANUP = "SKIP_CLEANUP" + +AWS_CLI_CONFIG_FILE = "/tmp/aws_cli_config" +CUSTOM_RESOURCE_OWNER_TAG = "aws-cdk:cr-owned" + +os.putenv('AWS_CONFIG_FILE', AWS_CLI_CONFIG_FILE) + +def handler(event, context): + + def cfn_error(message=None): + if message: + logger.error("| cfn_error: %s" % message.encode()) + cfn_send(event, context, CFN_FAILED, reason=message, physicalResourceId=event.get('PhysicalResourceId', None)) + + + try: + # We are not logging ResponseURL as this is a pre-signed S3 URL, and could be used to tamper + # with the response CloudFormation sees from this Custom Resource execution. + logger.info({ key:value for (key, value) in event.items() if key != 'ResponseURL'}) + + # cloudformation request type (create/update/delete) + request_type = event['RequestType'] + + # extract resource properties + props = event['ResourceProperties'] + old_props = event.get('OldResourceProperties', {}) + physical_id = event.get('PhysicalResourceId', None) + + try: + source_bucket_names = props['SourceBucketNames'] + source_object_keys = props['SourceObjectKeys'] + source_markers = props.get('SourceMarkers', None) + dest_bucket_name = props['DestinationBucketName'] + dest_bucket_prefix = props.get('DestinationBucketKeyPrefix', '') + extract = props.get('Extract', 'true') == 'true' + retain_on_delete = props.get('RetainOnDelete', "true") == "true" + distribution_id = props.get('DistributionId', '') + user_metadata = props.get('UserMetadata', {}) + system_metadata = props.get('SystemMetadata', {}) + prune = props.get('Prune', 'true').lower() == 'true' + exclude = props.get('Exclude', []) + include = props.get('Include', []) + sign_content = props.get('SignContent', 'false').lower() == 'true' + output_object_keys = props.get('OutputObjectKeys', 'true') == 'true' + + # backwards compatibility - if "SourceMarkers" is not specified, + # assume all sources have an empty market map + if source_markers is None: + source_markers = [{} for i in range(len(source_bucket_names))] + + default_distribution_path = dest_bucket_prefix + if not default_distribution_path.endswith("/"): + default_distribution_path += "/" + if not default_distribution_path.startswith("/"): + default_distribution_path = "/" + default_distribution_path + default_distribution_path += "*" + + distribution_paths = props.get('DistributionPaths', [default_distribution_path]) + except KeyError as e: + cfn_error("missing request resource property %s. props: %s" % (str(e), props)) + return + + # configure aws cli options after resetting back to the defaults for each request + if os.path.exists(AWS_CLI_CONFIG_FILE): + os.remove(AWS_CLI_CONFIG_FILE) + if sign_content: + aws_command("configure", "set", "default.s3.payload_signing_enabled", "true") + + # treat "/" as if no prefix was specified + if dest_bucket_prefix == "/": + dest_bucket_prefix = "" + + s3_source_zips = list(map(lambda name, key: "s3://%s/%s" % (name, key), source_bucket_names, source_object_keys)) + s3_dest = "s3://%s/%s" % (dest_bucket_name, dest_bucket_prefix) + old_s3_dest = "s3://%s/%s" % (old_props.get("DestinationBucketName", ""), old_props.get("DestinationBucketKeyPrefix", "")) + + + # obviously this is not + if old_s3_dest == "s3:///": + old_s3_dest = None + + logger.info("| s3_dest: %s" % sanitize_message(s3_dest)) + logger.info("| old_s3_dest: %s" % sanitize_message(old_s3_dest)) + + # if we are creating a new resource, allocate a physical id for it + # otherwise, we expect physical id to be relayed by cloudformation + if request_type == "Create": + physical_id = "aws.cdk.s3deployment.%s" % str(uuid4()) + else: + if not physical_id: + cfn_error("invalid request: request type is '%s' but 'PhysicalResourceId' is not defined" % request_type) + return + + # delete or create/update (only if "retain_on_delete" is false) + if request_type == "Delete" and not retain_on_delete: + if not bucket_owned(dest_bucket_name, dest_bucket_prefix): + aws_command("s3", "rm", s3_dest, "--recursive") + + # if we are updating without retention and the destination changed, delete first + if request_type == "Update" and not retain_on_delete and old_s3_dest != s3_dest: + if not old_s3_dest: + logger.warn("cannot delete old resource without old resource properties") + return + + aws_command("s3", "rm", old_s3_dest, "--recursive") + + if request_type == "Update" or request_type == "Create": + s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers, extract) + + if distribution_id: + cloudfront_invalidate(distribution_id, distribution_paths) + + cfn_send(event, context, CFN_SUCCESS, physicalResourceId=physical_id, responseData={ + # Passing through the ARN sequences dependencees on the deployment + 'DestinationBucketArn': props.get('DestinationBucketArn'), + **({'SourceObjectKeys': props.get('SourceObjectKeys')} if output_object_keys else {'SourceObjectKeys': []}) + }) + except KeyError as e: + cfn_error("invalid request. Missing key %s" % str(e)) + except Exception as e: + logger.exception(e) + cfn_error(str(e)) + +#--------------------------------------------------------------------------------------------------- +# Sanitize the message to mitigate CWE-117 and CWE-93 vulnerabilities +def sanitize_message(message): + if not message: + return message + + # Sanitize the message to prevent log injection and HTTP response splitting + sanitized_message = message.replace('\n', '').replace('\r', '') + + # Encode the message to handle special characters + encoded_message = urllib.parse.quote(sanitized_message) + + return encoded_message + +#--------------------------------------------------------------------------------------------------- +# populate all files from s3_source_zips to a destination bucket +def s3_deploy(s3_source_zips, s3_dest, user_metadata, system_metadata, prune, exclude, include, source_markers, extract): + # list lengths are equal + if len(s3_source_zips) != len(source_markers): + raise Exception("'source_markers' and 's3_source_zips' must be the same length") + + # create a temporary working directory in /tmp or if enabled an attached efs volume + if ENV_KEY_MOUNT_PATH in os.environ: + workdir = os.getenv(ENV_KEY_MOUNT_PATH) + "/" + str(uuid4()) + os.mkdir(workdir) + else: + workdir = tempfile.mkdtemp() + + logger.info("| workdir: %s" % workdir) + + # create a directory into which we extract the contents of the zip file + contents_dir=os.path.join(workdir, 'contents') + os.mkdir(contents_dir) + + try: + # download the archive from the source and extract to "contents" + for i in range(len(s3_source_zips)): + s3_source_zip = s3_source_zips[i] + markers = source_markers[i] + + if extract: + archive=os.path.join(workdir, str(uuid4())) + logger.info("archive: %s" % archive) + aws_command("s3", "cp", s3_source_zip, archive) + logger.info("| extracting archive to: %s\n" % contents_dir) + logger.info("| markers: %s" % markers) + extract_and_replace_markers(archive, contents_dir, markers) + else: + logger.info("| copying archive to: %s\n" % contents_dir) + aws_command("s3", "cp", s3_source_zip, contents_dir) + + # sync from "contents" to destination + + s3_command = ["s3", "sync"] + + if prune: + s3_command.append("--delete") + + if exclude: + for filter in exclude: + s3_command.extend(["--exclude", filter]) + + if include: + for filter in include: + s3_command.extend(["--include", filter]) + + s3_command.extend([contents_dir, s3_dest]) + s3_command.extend(create_metadata_args(user_metadata, system_metadata)) + aws_command(*s3_command) + finally: + if not os.getenv(ENV_KEY_SKIP_CLEANUP): + shutil.rmtree(workdir) + +#--------------------------------------------------------------------------------------------------- +# invalidate files in the CloudFront distribution edge caches +def cloudfront_invalidate(distribution_id, distribution_paths): + invalidation_resp = cloudfront.create_invalidation( + DistributionId=distribution_id, + InvalidationBatch={ + 'Paths': { + 'Quantity': len(distribution_paths), + 'Items': distribution_paths + }, + 'CallerReference': str(uuid4()), + }) + # by default, will wait up to 10 minutes + cloudfront.get_waiter('invalidation_completed').wait( + DistributionId=distribution_id, + Id=invalidation_resp['Invalidation']['Id']) + +#--------------------------------------------------------------------------------------------------- +# set metadata +def create_metadata_args(raw_user_metadata, raw_system_metadata): + if len(raw_user_metadata) == 0 and len(raw_system_metadata) == 0: + return [] + + format_system_metadata_key = lambda k: k.lower() + format_user_metadata_key = lambda k: k.lower() + + system_metadata = { format_system_metadata_key(k): v for k, v in raw_system_metadata.items() } + user_metadata = { format_user_metadata_key(k): v for k, v in raw_user_metadata.items() } + + flatten = lambda l: [item for sublist in l for item in sublist] + system_args = flatten([[f"--{k}", v] for k, v in system_metadata.items()]) + user_args = ["--metadata", json.dumps(user_metadata, separators=(',', ':'))] if len(user_metadata) > 0 else [] + + return system_args + user_args + ["--metadata-directive", "REPLACE"] + +#--------------------------------------------------------------------------------------------------- +# executes an "aws" cli command +def aws_command(*args): + aws="/opt/awscli/aws" # from AwsCliLayer + logger.info("| aws %s" % ' '.join(args)) + subprocess.check_call([aws] + list(args)) + +#--------------------------------------------------------------------------------------------------- +# sends a response to cloudformation +def cfn_send(event, context, responseStatus, responseData={}, physicalResourceId=None, noEcho=False, reason=None): + + responseUrl = event['ResponseURL'] + + responseBody = {} + responseBody['Status'] = responseStatus + responseBody['Reason'] = reason or ('See the details in CloudWatch Log Stream: ' + context.log_stream_name) + responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name + responseBody['StackId'] = event['StackId'] + responseBody['RequestId'] = event['RequestId'] + responseBody['LogicalResourceId'] = event['LogicalResourceId'] + responseBody['NoEcho'] = noEcho + responseBody['Data'] = responseData + + body = json.dumps(responseBody) + logger.info("| response body:\n" + body) + + headers = { + 'content-type' : '', + 'content-length' : str(len(body)) + } + + try: + request = Request(responseUrl, method='PUT', data=bytes(body.encode('utf-8')), headers=headers) + with contextlib.closing(urlopen(request)) as response: + logger.info("| status code: " + response.reason) + except Exception as e: + logger.error("| unable to send response to CloudFormation") + logger.exception(e) + + +#--------------------------------------------------------------------------------------------------- +# check if bucket is owned by a custom resource +# if it is then we don't want to delete content +def bucket_owned(bucketName, keyPrefix): + tag = CUSTOM_RESOURCE_OWNER_TAG + if keyPrefix != "": + tag = tag + ':' + keyPrefix + try: + request = s3.get_bucket_tagging( + Bucket=bucketName, + ) + return any((x["Key"].startswith(tag)) for x in request["TagSet"]) + except Exception as e: + logger.info("| error getting tags from bucket") + logger.exception(e) + return False + +# extract archive and replace markers in output files +def extract_and_replace_markers(archive, contents_dir, markers): + with ZipFile(archive, "r") as zip: + zip.extractall(contents_dir) + + # replace markers for this source + for file in zip.namelist(): + file_path = os.path.join(contents_dir, file) + if os.path.isdir(file_path): continue + replace_markers(file_path, markers) + +def replace_markers(filename, markers): + # convert the dict of string markers to binary markers + replace_tokens = dict([(k.encode('utf-8'), v.encode('utf-8')) for k, v in markers.items()]) + + outfile = filename + '.new' + with open(filename, 'rb') as fi, open(outfile, 'wb') as fo: + for line in fi: + for token in replace_tokens: + line = line.replace(token, replace_tokens[token]) + fo.write(line) + + # # delete the original file and rename the new one to the original + os.remove(filename) + os.rename(outfile, filename) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d/index.py b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d/index.py new file mode 100644 index 0000000000000..175a36616590a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d/index.py @@ -0,0 +1,8 @@ +import requests + +def handler(event, context): + r = requests.get('https://aws.amazon.com') + + print(r.status_code) + + return r.status_code diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d/requirements.txt b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d/requirements.txt new file mode 100644 index 0000000000000..2c24336eb3167 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d/requirements.txt @@ -0,0 +1 @@ +requests==2.31.0 diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip new file mode 100644 index 0000000000000..bff4656ba5dcb Binary files /dev/null and b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/asset.f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip differ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/cdk.out new file mode 100644 index 0000000000000..c6e612584e352 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/integ.json new file mode 100644 index 0000000000000..4788939f892d3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "38.0.1", + "testCases": { + "SourceKMSKeyArn/DefaultTest": { + "stacks": [ + "CMCMK-Stack" + ], + "assertionStack": "SourceKMSKeyArn/DefaultTest/DeployAssert", + "assertionStackName": "SourceKMSKeyArnDefaultTestDeployAssertA9940761" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/manifest.json new file mode 100644 index 0000000000000..96fba3ce3eac0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/manifest.json @@ -0,0 +1,227 @@ +{ + "version": "38.0.1", + "artifacts": { + "CMCMK-Stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CMCMK-Stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CMCMK-Stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "CMCMK-Stack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/494c79217eb979e7fb6591a5381b466597a58cfa5673958b5ed08a5d37cd08d3.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "CMCMK-Stack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "CMCMK-Stack.assets" + ], + "metadata": { + "/CMCMK-Stack/LambdaExecutionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LambdaExecutionRoleD5C26073" + } + ], + "/CMCMK-Stack/LambdaExecutionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LambdaExecutionRoleDefaultPolicy6D69732F" + } + ], + "/CMCMK-Stack/myImportedKey/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myImportedKey10DE2890" + } + ], + "/CMCMK-Stack/myFunction1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myFunction156294E5D" + } + ], + "/CMCMK-Stack/S3/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "S3486F821D" + } + ], + "/CMCMK-Stack/S3/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "S3Policy2E4AA1D6" + } + ], + "/CMCMK-Stack/S3/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "S3AutoDeleteObjectsCustomResource5A4102C9" + } + ], + "/CMCMK-Stack/LatestNodeRuntimeMap": [ + { + "type": "aws:cdk:logicalId", + "data": "LatestNodeRuntimeMap" + } + ], + "/CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider": [ + { + "type": "aws:cdk:is-custom-resource-handler-customResourceProvider", + "data": true + } + ], + "/CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/CMCMK-Stack/DeployLambdaCode/AwsCliLayer/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DeployLambdaCodeAwsCliLayer8743C498" + } + ], + "/CMCMK-Stack/DeployLambdaCode/CustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "DeployLambdaCodeCustomResource0564AA4B" + } + ], + "/CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C": [ + { + "type": "aws:cdk:is-custom-resource-handler-singleton", + "data": true + }, + { + "type": "aws:cdk:is-custom-resource-handler-runtime-family", + "data": 2 + } + ], + "/CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + } + ], + "/CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF" + } + ], + "/CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536" + } + ], + "/CMCMK-Stack/myFunction2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myFunction2CB7FFFBF" + } + ], + "/CMCMK-Stack/myFunction3/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "myFunction343849752" + } + ], + "/CMCMK-Stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CMCMK-Stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CMCMK-Stack" + }, + "SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "SourceKMSKeyArnDefaultTestDeployAssertA9940761": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "SourceKMSKeyArnDefaultTestDeployAssertA9940761.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "SourceKMSKeyArnDefaultTestDeployAssertA9940761.assets" + ], + "metadata": { + "/SourceKMSKeyArn/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/SourceKMSKeyArn/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "SourceKMSKeyArn/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/tree.json new file mode 100644 index 0000000000000..ae761d486d410 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.js.snapshot/tree.json @@ -0,0 +1,1003 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "CMCMK-Stack": { + "id": "CMCMK-Stack", + "path": "CMCMK-Stack", + "children": { + "LambdaExecutionRole": { + "id": "LambdaExecutionRole", + "path": "CMCMK-Stack/LambdaExecutionRole", + "children": { + "ImportLambdaExecutionRole": { + "id": "ImportLambdaExecutionRole", + "path": "CMCMK-Stack/LambdaExecutionRole/ImportLambdaExecutionRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/LambdaExecutionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "CMCMK-Stack/LambdaExecutionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/LambdaExecutionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "LambdaExecutionRoleDefaultPolicy6D69732F", + "roles": [ + { + "Ref": "LambdaExecutionRoleD5C26073" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "myImportedKey": { + "id": "myImportedKey", + "path": "CMCMK-Stack/myImportedKey", + "children": { + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/myImportedKey/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "enableKeyRotation": true, + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + }, + { + "Action": [ + "kms:Decrypt", + "kms:GenerateDataKey" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "Service": "lambda.amazonaws.com" + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.Key", + "version": "0.0.0" + } + }, + "myFunction1": { + "id": "myFunction1", + "path": "CMCMK-Stack/myFunction1", + "children": { + "Code": { + "id": "Code", + "path": "CMCMK-Stack/myFunction1/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "CMCMK-Stack/myFunction1/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "CMCMK-Stack/myFunction1/Code/AssetBucket", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3_assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/myFunction1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "cab53c59addd4362c71a39b96e04505d5f53fa854b2ff7cbc6cd5925f5afca9d.zip", + "sourceKmsKeyArn": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + }, + "handler": "index.handler", + "role": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "runtime": "nodejs18.x" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "S3": { + "id": "S3", + "path": "CMCMK-Stack/S3", + "children": { + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/S3/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketName": "s3sourcekmskeyarnbucket", + "tags": [ + { + "key": "aws-cdk:auto-delete-objects", + "value": "true" + }, + { + "key": "aws-cdk:cr-owned:c0b774e4", + "value": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "CMCMK-Stack/S3/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/S3/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "S3486F821D" + }, + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "0.0.0" + } + }, + "AutoDeleteObjectsCustomResource": { + "id": "AutoDeleteObjectsCustomResource", + "path": "CMCMK-Stack/S3/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "CMCMK-Stack/S3/AutoDeleteObjectsCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "0.0.0" + } + }, + "LatestNodeRuntimeMap": { + "id": "LatestNodeRuntimeMap", + "path": "CMCMK-Stack/LatestNodeRuntimeMap", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnMapping", + "version": "0.0.0" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "CMCMK-Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "0.0.0" + } + }, + "DeployLambdaCode": { + "id": "DeployLambdaCode", + "path": "CMCMK-Stack/DeployLambdaCode", + "children": { + "AwsCliLayer": { + "id": "AwsCliLayer", + "path": "CMCMK-Stack/DeployLambdaCode/AwsCliLayer", + "children": { + "Code": { + "id": "Code", + "path": "CMCMK-Stack/DeployLambdaCode/AwsCliLayer/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "CMCMK-Stack/DeployLambdaCode/AwsCliLayer/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "CMCMK-Stack/DeployLambdaCode/AwsCliLayer/Code/AssetBucket", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3_assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/DeployLambdaCode/AwsCliLayer/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::LayerVersion", + "aws:cdk:cloudformation:props": { + "content": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "f24ba5e516d9d80b64bc7b0f406eedd12c36b20e7461f3e7719b7ffbdad72410.zip" + }, + "description": "/opt/awscli/aws" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnLayerVersion", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.lambda_layer_awscli.AwsCliLayer", + "version": "0.0.0" + } + }, + "CustomResourceHandler": { + "id": "CustomResourceHandler", + "path": "CMCMK-Stack/DeployLambdaCode/CustomResourceHandler", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.SingletonFunction", + "version": "0.0.0" + } + }, + "Asset1": { + "id": "Asset1", + "path": "CMCMK-Stack/DeployLambdaCode/Asset1", + "children": { + "Stage": { + "id": "Stage", + "path": "CMCMK-Stack/DeployLambdaCode/Asset1/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "CMCMK-Stack/DeployLambdaCode/Asset1/AssetBucket", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3_assets.Asset", + "version": "0.0.0" + } + }, + "CustomResource": { + "id": "CustomResource", + "path": "CMCMK-Stack/DeployLambdaCode/CustomResource", + "children": { + "Default": { + "id": "Default", + "path": "CMCMK-Stack/DeployLambdaCode/CustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3_deployment.BucketDeployment", + "version": "0.0.0" + } + }, + "Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C": { + "id": "Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + } + ] + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "S3486F821D", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", + "roles": [ + { + "Ref": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Code/AssetBucket", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3_assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "c6358465bf49dfae556bb430bf9c81fa578c221b82c308e3707901b1dd654762.zip" + }, + "environment": { + "variables": { + "AWS_CA_BUNDLE": "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" + } + }, + "handler": "index.handler", + "layers": [ + { + "Ref": "DeployLambdaCodeAwsCliLayer8743C498" + } + ], + "role": { + "Fn::GetAtt": [ + "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", + "Arn" + ] + }, + "runtime": "python3.11", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "myFunction2": { + "id": "myFunction2", + "path": "CMCMK-Stack/myFunction2", + "children": { + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/myFunction2/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Ref": "S3486F821D" + }, + "s3Key": "python-lambda-handler.zip", + "sourceKmsKeyArn": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + }, + "environment": { + "variables": { + "SOURCE_KMS_KEY_ARN": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + } + }, + "handler": "index.handler", + "role": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "runtime": "nodejs18.x" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "myFunction3": { + "id": "myFunction3", + "path": "CMCMK-Stack/myFunction3", + "children": { + "Code": { + "id": "Code", + "path": "CMCMK-Stack/myFunction3/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "CMCMK-Stack/myFunction3/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "CMCMK-Stack/myFunction3/Code/AssetBucket", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3_assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "CMCMK-Stack/myFunction3/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "bfb85829d4e929cc311029ef8f4408970030d737cc6d4c1911f7abd2991fa051.zip", + "sourceKmsKeyArn": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + }, + "environment": { + "variables": { + "SOURCE_KMS_KEY_ARN": { + "Fn::GetAtt": [ + "myImportedKey10DE2890", + "Arn" + ] + } + } + }, + "handler": "index.handler", + "role": { + "Fn::GetAtt": [ + "LambdaExecutionRoleD5C26073", + "Arn" + ] + }, + "runtime": "python3.11" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "CMCMK-Stack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "CMCMK-Stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "SourceKMSKeyArn": { + "id": "SourceKMSKeyArn", + "path": "SourceKMSKeyArn", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "SourceKMSKeyArn/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "SourceKMSKeyArn/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "SourceKMSKeyArn/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "SourceKMSKeyArn/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "SourceKMSKeyArn/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.ts new file mode 100644 index 0000000000000..90a6474c383ae --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda-sourceKMSKeyArn.ts @@ -0,0 +1,111 @@ +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import { Construct } from 'constructs'; +import * as path from 'path'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import * as cdk from 'aws-cdk-lib'; +import * as kms from 'aws-cdk-lib/aws-kms'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); + +class TestStack extends Stack { + public readonly functionName1: string; + public readonly functionName2: string; + public readonly functionName3: string; + + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const lambdaExecutionRole = new iam.Role(this, 'LambdaExecutionRole', { + assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + managedPolicies: [ + iam.ManagedPolicy.fromAwsManagedPolicyName( + 'service-role/AWSLambdaBasicExecutionRole', + ), + ], + }); + const key = new kms.Key(this, 'myImportedKey', { + enableKeyRotation: true, + }); + key.addToResourcePolicy(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.ServicePrincipal('lambda.amazonaws.com')], + actions: [ + 'kms:GenerateDataKey', + 'kms:Decrypt', + ], + resources: ['*'], + })); + key.addToResourcePolicy( + new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [lambdaExecutionRole], + actions: ['kms:GenerateDataKey', 'kms:Decrypt'], + resources: ['*'], + }), + ); + lambdaExecutionRole.addToPolicy( + new iam.PolicyStatement({ + actions: ['kms:Decrypt', 'kms:GenerateDataKey'], + resources: [key.keyArn], + }), + ); + const option = { + sourceKMSKey: key, + }; + + // Using Asset + const assetPath = path.join(__dirname, 'python-lambda-handler'); + const fnAsset = new lambda.Function(this, 'myFunction1', { + code: lambda.Code.fromAsset(assetPath, option), + runtime: lambda.Runtime.NODEJS_LATEST, + handler: 'index.handler', + role: lambdaExecutionRole, + }); + key.grantEncryptDecrypt(lambdaExecutionRole), + + this.functionName1 = fnAsset.functionName; + + // Using Bucket + const bucket = new s3.Bucket(this, 'S3', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, + bucketName: 's3sourcekmskeyarnbucket', + }); + const deployment = new s3deploy.BucketDeployment(this, 'DeployLambdaCode', { + sources: [s3deploy.Source.asset('lambda-zip')], + destinationBucket: bucket, + }); + const fnBucket = new lambda.Function(this, 'myFunction2', { + runtime: lambda.Runtime.NODEJS_LATEST, + handler: 'index.handler', + role: lambdaExecutionRole, + code: lambda.Code.fromBucketV2(bucket, 'python-lambda-handler.zip', option), + environment: { + SOURCE_KMS_KEY_ARN: key.keyArn, + }, + }); + fnBucket.node.addDependency(deployment); + this.functionName2 = fnBucket.functionName; + + // Using Custom Command + const command = 'lambda-zip/python-lambda-handler.zip'; + const fnCustom = new lambda.Function(this, 'myFunction3', { + runtime: lambda.Runtime.PYTHON_3_11, + handler: 'index.handler', + role: lambdaExecutionRole, + code: lambda.Code.fromCustomCommand(command, ['node'], option), + environment: { + SOURCE_KMS_KEY_ARN: key.keyArn, + }, + }); + this.functionName3 = fnCustom.functionName; + }; +} + +new IntegTest(app, 'SourceKMSKeyArn', { + testCases: [new TestStack(app, 'CMCMK-Stack')], +}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/lambda-zip/python-lambda-handler.zip b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/lambda-zip/python-lambda-handler.zip new file mode 100644 index 0000000000000..a9b5d0d55f1f2 Binary files /dev/null and b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/lambda-zip/python-lambda-handler.zip differ diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 368e99ccd144b..af183a80139e7 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -16,8 +16,25 @@ const fn = new lambda.Function(this, 'MyFunction', { The `lambda.Code` class includes static convenience methods for various types of runtime code. - * `lambda.Code.fromBucket(bucket, key[, objectVersion])` - specify an S3 object + * `lambda.Code.fromBucket(bucket, key, objectVersion)` - specify an S3 object that contains the archive of your runtime code. + * `lambda.Code.fromBucketV2(bucket, key, {objectVersion: version, sourceKMSKey: key})` - specify an S3 object + that contains the archive of your runtime code. + + ```ts + const bucketName = `${your-s3-bucket-name}` + const s3Key = `${your-s3-object-key}` + const option = { + sourceKMSKey: key, + }; + const fnBucket = new lambda.Function(this, 'myFunction2', { + runtime: lambda.Runtime.NODEJS_LATEST, + handler: 'index.handler', + role: lambdaExecutionRole, + code: lambda.Code.fromBucketV2(bucketName, s3Key, option), + }); + + ``` * `lambda.Code.fromInline(code)` - inline the handle code as a string. This is limited to supported runtimes. * `lambda.Code.fromAsset(path)` - specify a directory or a .zip file in the local diff --git a/packages/aws-cdk-lib/aws-lambda/lib/code.ts b/packages/aws-cdk-lib/aws-lambda/lib/code.ts index dd7fc905da36f..d9a7c875d3c2d 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/code.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/code.ts @@ -3,6 +3,7 @@ import { Construct } from 'constructs'; import * as ecr from '../../aws-ecr'; import * as ecr_assets from '../../aws-ecr-assets'; import * as iam from '../../aws-iam'; +import { IKey } from '../../aws-kms'; import * as s3 from '../../aws-s3'; import * as s3_assets from '../../aws-s3-assets'; import * as cdk from '../../core'; @@ -21,6 +22,18 @@ export abstract class Code { return new S3Code(bucket, key, objectVersion); } + /** + * Lambda handler code as an S3 object. + * @param bucket The S3 bucket + * @param key The object key + * @param options Optional parameters for setting the code, current optional parameters to set here are + * 1. `objectVersion` to set S3 object version + * 2. `sourceKMSKey` to set KMS Key for encryption of code + */ + public static fromBucketV2 (bucket: s3.IBucket, key: string, options?: BucketOptions): S3CodeV2 { + return new S3CodeV2(bucket, key, options); + } + /** * DEPRECATED * @deprecated use `fromBucket` @@ -208,6 +221,12 @@ export interface CodeConfig { * @default - code is not an ECR container image */ readonly image?: CodeImageConfig; + + /** + * The ARN of the KMS key used to encrypt the handler code. + * @default - the default server-side encryption with Amazon S3 managed keys(SSE-S3) key will be used. + */ + readonly sourceKMSKeyArn?: string; } /** @@ -260,6 +279,7 @@ export class S3Code extends Code { } this.bucketName = bucket.bucketName; + } public bind(_scope: Construct): CodeConfig { @@ -273,6 +293,35 @@ export class S3Code extends Code { } } +/** + * Lambda code from an S3 archive. With option to set KMSKey for encryption. + */ +export class S3CodeV2 extends Code { + public readonly isInline = false; + private bucketName: string; + + constructor(bucket: s3.IBucket, private key: string, private options?: BucketOptions) { + super(); + if (!bucket.bucketName) { + throw new Error('bucketName is undefined for the provided bucket'); + } + + this.bucketName = bucket.bucketName; + + } + + public bind(_scope: Construct): CodeConfig { + return { + s3Location: { + bucketName: this.bucketName, + objectKey: this.key, + objectVersion: this.options?.objectVersion, + }, + sourceKMSKeyArn: this.options?.sourceKMSKey?.keyArn, + }; + } +} + /** * Lambda code from an inline string. */ @@ -330,6 +379,7 @@ export class AssetCode extends Code { bucketName: this.asset.s3BucketName, objectKey: this.asset.s3ObjectKey, }, + sourceKMSKeyArn: this.options.sourceKMSKey?.keyArn, }; } @@ -375,6 +425,11 @@ export interface CfnParametersCodeProps { * @default a new parameter will be created */ readonly objectKeyParam?: cdk.CfnParameter; + /** + * The ARN of the KMS key used to encrypt the handler code. + * @default - the default server-side encryption with Amazon S3 managed keys(SSE-S3) key will be used. + */ + readonly sourceKMSKey?: IKey; } /** @@ -387,12 +442,14 @@ export class CfnParametersCode extends Code { public readonly isInline = false; private _bucketNameParam?: cdk.CfnParameter; private _objectKeyParam?: cdk.CfnParameter; + private _sourceKMSKey?: IKey; constructor(props: CfnParametersCodeProps = {}) { super(); this._bucketNameParam = props.bucketNameParam; this._objectKeyParam = props.objectKeyParam; + this._sourceKMSKey = props.sourceKMSKey; } public bind(scope: Construct): CodeConfig { @@ -413,6 +470,7 @@ export class CfnParametersCode extends Code { bucketName: this._bucketNameParam.valueAsString, objectKey: this._objectKeyParam.valueAsString, }, + sourceKMSKeyArn: this._sourceKMSKey?.keyArn, }; } @@ -493,6 +551,7 @@ export interface EcrImageCodeProps { * @default 'latest' */ readonly tagOrDigest?: string; + } /** @@ -626,4 +685,19 @@ export interface CustomCommandOptions extends s3_assets.AssetOptions { * @default: see `child_process.SpawnSyncOptions` (https://nodejs.org/api/child_process.html#child_processspawnsynccommand-args-options). */ readonly commandOptions?: { [options: string]: any }; +} + +/** + * Optional parameters for creating code using bucket + */ +export interface BucketOptions { + /** + * Optional S3 object version + */ + readonly objectVersion?: string; + /** + * The ARN of the KMS key used to encrypt the handler code. + * @default - the default server-side encryption with Amazon S3 managed keys(SSE-S3) key will be used. + */ + readonly sourceKMSKey?: IKey; } \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index c8061020ad04c..fffdb6ae11ae6 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -1040,6 +1040,7 @@ export class Function extends FunctionBase { s3ObjectVersion: code.s3Location && code.s3Location.objectVersion, zipFile: code.inlineCode, imageUri: code.image?.imageUri, + sourceKmsKeyArn: code.sourceKMSKeyArn, }, layers: Lazy.list({ produce: () => this.renderLayers() }), // Evaluated on synthesis handler: props.handler === Handler.FROM_IMAGE ? undefined : props.handler, diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index 15e8465086bef..4246ccb52b6cf 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { testDeprecated } from '@aws-cdk/cdk-build-tools'; +import { testDeprecated, bockfs } from '@aws-cdk/cdk-build-tools'; import * as constructs from 'constructs'; import * as _ from 'lodash'; import { Annotations, Match, Template } from '../../assertions'; @@ -4514,6 +4514,235 @@ describe('latest Lambda node runtime', () => { }); }); +// Test sourceKMSKeyArn feature +describe('CMCMK', () => { + test('set sourceKMSKeyArn using fromAsset', () => { + const stack = new cdk.Stack(); + const key = new kms.Key(stack, 'myImportedKey', { + enableKeyRotation: true, + }); + const option = { + sourceKMSKey: key, + }; + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip'), option), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_9, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: { 'Fn::GetAtt': ['myImportedKey10DE2890', 'Arn'] }, + }, + Runtime: 'python3.9', + Handler: 'index.handler', + }, + }); + }); + + test('no sourceKMSKey provided using fromAsset', () => { + const stack = new cdk.Stack(); + + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_9, + }); + + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: Match.absent(), + }, + }, + }); + }); + + test('set sourceKMSKeyArn using fromBucket', () => { + const stack = new cdk.Stack(); + // S3 Bucket + const key = 'script'; + let bucket: s3.IBucket; + bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketname'); + + // KMS + const KMSkey = new kms.Key(stack, 'myImportedKey', { + enableKeyRotation: true, + }); + const option = { + sourceKMSKey: KMSkey, + }; + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromBucketV2(bucket, key, option), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_9, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: { 'Fn::GetAtt': ['myImportedKey10DE2890', 'Arn'] }, + }, + Runtime: 'python3.9', + Handler: 'index.handler', + }, + }); + }); + + test('no sourceKMSKey provided using fromBucket', () => { + const stack = new cdk.Stack(); + // S3 Bucket + const key = 'script'; + let bucket: s3.IBucket; + bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketname'); + + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromBucketV2(bucket, key), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_9, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: Match.absent(), + }, + Runtime: 'python3.9', + Handler: 'index.handler', + }, + }); + }); + + test('set sourceKMSKeyArn using fromCfnParameters', () => { + const stack = new cdk.Stack(); + // KMS + const KMSkey = new kms.Key(stack, 'myImportedKey', { + enableKeyRotation: true, + }); + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromCfnParameters({ + sourceKMSKey: KMSkey, + }), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_9, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: { 'Fn::GetAtt': ['myImportedKey10DE2890', 'Arn'] }, + }, + Runtime: 'python3.9', + Handler: 'index.handler', + }, + }); + }); + + test('no sourceKMSKey provided using fromCfnParameters', () => { + const stack = new cdk.Stack(); + + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromCfnParameters(), + handler: 'index.handler', + runtime: lambda.Runtime.PYTHON_3_9, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: Match.absent(), + }, + Runtime: 'python3.9', + Handler: 'index.handler', + }, + }); + }); + + test('set sourceKMSKeyArn using fromCustomCommand', () => { + const mockCallsites = jest.fn(); + jest.mock('../lib/util', () => ({ + ...jest.requireActual('../lib/util'), + callsites: () => mockCallsites(), + })); + bockfs({ + '/home/project/function.test.handler7.zip': '// nothing', + }); + const bockPath = bockfs.workingDirectory('/home/project'); + mockCallsites.mockImplementation(() => [ + { getFunctionName: () => 'NodejsFunction' }, + { getFileName: () => bockPath`function.test.ts` }, + ]); + + const stack = new cdk.Stack(); + // KMS + const KMSkey = new kms.Key(stack, 'myImportedKey', { + enableKeyRotation: true, + }); + // const command = ; + const commandOptions = { sourceKMSKey: KMSkey }; + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromCustomCommand('function.test.handler7.zip', ['node'], commandOptions), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: { 'Fn::GetAtt': ['myImportedKey10DE2890', 'Arn'] }, + }, + Runtime: 'nodejs18.x', + Handler: 'index.handler', + }, + }); + bockfs.restore(); + }); + + test('no sourceKMSKey provided using fromCustomCommand', () => { + const mockCallsites = jest.fn(); + jest.mock('../lib/util', () => ({ + ...jest.requireActual('../lib/util'), + callsites: () => mockCallsites(), + })); + bockfs({ + '/home/project/function.test.handler7.zip': '// nothing', + }); + const bockPath = bockfs.workingDirectory('/home/project'); + mockCallsites.mockImplementation(() => [ + { getFunctionName: () => 'NodejsFunction' }, + { getFileName: () => bockPath`function.test.ts` }, + ]); + + const stack = new cdk.Stack(); + // WHEN + new lambda.Function(stack, 'Lambda', { + code: lambda.Code.fromCustomCommand('function.test.handler7.zip', ['node']), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + }); + // THEN + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: { + Code: { + SourceKMSKeyArn: Match.absent(), + }, + Runtime: 'nodejs18.x', + Handler: 'index.handler', + }, + }); + bockfs.restore(); + }); +}); + function newTestLambda(scope: constructs.Construct) { return new lambda.Function(scope, 'MyLambda', { code: new lambda.InlineCode('foo'), diff --git a/packages/aws-cdk-lib/aws-s3-assets/lib/asset.ts b/packages/aws-cdk-lib/aws-s3-assets/lib/asset.ts index 5993a9a2a06e9..6f07fffa6d9c0 100644 --- a/packages/aws-cdk-lib/aws-s3-assets/lib/asset.ts +++ b/packages/aws-cdk-lib/aws-s3-assets/lib/asset.ts @@ -49,6 +49,11 @@ export interface AssetOptions extends CopyOptions, cdk.FileCopyOptions, cdk.Asse * @default false */ readonly deployTime?: boolean; + /** + * The ARN of the KMS key used to encrypt the handler code. + * @default - the default server-side encryption with Amazon S3 managed keys(SSE-S3) key will be used. + */ + readonly sourceKMSKey?: kms.IKey; } export interface AssetProps extends AssetOptions { diff --git a/packages/aws-cdk-lib/awslint.json b/packages/aws-cdk-lib/awslint.json index 987770519230f..ffc97a8a2609d 100644 --- a/packages/aws-cdk-lib/awslint.json +++ b/packages/aws-cdk-lib/awslint.json @@ -367,6 +367,18 @@ "docs-public-apis:aws-cdk-lib.aws_lambda.RecursiveLoop", "docs-public-apis:aws-cdk-lib.aws_lambda.SnapStartConf.ON_PUBLISHED_VERSIONS", "docs-public-apis:aws-cdk-lib.aws_lambda.Version.fromVersionAttributes", + "docs-public-apis:aws-cdk-lib.aws_lambda.Code.fromBucketV2", + "docs-public-apis:aws-cdk-lib.aws_lambda.Code.fromCfnParametersV2", + "docs-public-apis:aws-cdk-lib.aws_lambda.S3CodeV2", + "docs-public-apis:aws-cdk-lib.aws_lambda.BucketOptions", + "docs-public-apis:aws-cdk-lib.aws_lambda.BucketOptions.objectVersion", + "props-default-doc:aws-cdk-lib.aws_lambda.BucketOptions.objectVersion", + "docs-public-apis:aws-cdk-lib.aws_lambda.BucketOptions.sourceKMSKey", + "props-default-doc:aws-cdk-lib.aws_lambda.BucketOptions.sourceKMSKey", + "docs-public-apis:aws-cdk-lib.aws_lambda.CodeConfig.sourceKMSKeyArn", + "props-default-doc:aws-cdk-lib.aws_lambda.CodeConfig.sourceKMSKeyArn", + "docs-public-apis:aws-cdk-lib.aws_s3_assets.AssetOptions.sourceKMSKey", + "props-default-doc:aws-cdk-lib.aws_s3_assets.AssetOptions.sourceKMSKey", "docs-public-apis:aws-cdk-lib.aws_lambda_event_sources.ApiEventSource", "docs-public-apis:aws-cdk-lib.aws_lambda_event_sources.KinesisEventSource.stream", "docs-public-apis:aws-cdk-lib.aws_lambda_event_sources.S3EventSource.bucket", diff --git a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-lambda-sourcekmskey.json b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-lambda-sourcekmskey.json new file mode 100644 index 0000000000000..055790c8af286 --- /dev/null +++ b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-lambda-sourcekmskey.json @@ -0,0 +1,453 @@ +{ + "tagging" : { + "taggable" : true, + "tagOnCreate" : true, + "tagUpdatable" : true, + "tagProperty" : "/properties/Tags", + "cloudFormationSystemTags" : true + }, + "handlers" : { + "read" : { + "permissions" : [ "lambda:GetFunction", "lambda:GetFunctionCodeSigningConfig", "lambda:GetFunctionRecursionConfig" ] + }, + "create" : { + "permissions" : [ "lambda:CreateFunction", "lambda:GetFunction", "lambda:PutFunctionConcurrency", "iam:PassRole", "s3:GetObject", "s3:GetObjectVersion", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeVpcs", "elasticfilesystem:DescribeMountTargets", "kms:CreateGrant", "kms:Decrypt", "kms:Encrypt", "kms:GenerateDataKey", "lambda:GetCodeSigningConfig", "lambda:GetFunctionCodeSigningConfig", "lambda:GetLayerVersion", "lambda:GetRuntimeManagementConfig", "lambda:PutRuntimeManagementConfig", "lambda:TagResource", "lambda:PutFunctionRecursionConfig", "lambda:GetFunctionRecursionConfig" ] + }, + "update" : { + "permissions" : [ "lambda:DeleteFunctionConcurrency", "lambda:GetFunction", "lambda:PutFunctionConcurrency", "lambda:ListTags", "lambda:TagResource", "lambda:UntagResource", "lambda:UpdateFunctionConfiguration", "lambda:UpdateFunctionCode", "iam:PassRole", "s3:GetObject", "s3:GetObjectVersion", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeVpcs", "elasticfilesystem:DescribeMountTargets", "kms:CreateGrant", "kms:Decrypt", "kms:GenerateDataKey", "lambda:GetRuntimeManagementConfig", "lambda:PutRuntimeManagementConfig", "lambda:PutFunctionCodeSigningConfig", "lambda:DeleteFunctionCodeSigningConfig", "lambda:GetCodeSigningConfig", "lambda:GetFunctionCodeSigningConfig", "lambda:PutFunctionRecursionConfig", "lambda:GetFunctionRecursionConfig" ] + }, + "list" : { + "permissions" : [ "lambda:ListFunctions" ] + }, + "delete" : { + "permissions" : [ "lambda:DeleteFunction", "lambda:GetFunction", "ec2:DescribeNetworkInterfaces" ] + } + }, + "typeName" : "AWS::Lambda::Function", + "readOnlyProperties" : [ "/properties/SnapStartResponse", "/properties/SnapStartResponse/ApplyOn", "/properties/SnapStartResponse/OptimizationStatus", "/properties/Arn" ], + "description" : "The ``AWS::Lambda::Function`` resource creates a Lambda function. To create a function, you need a [deployment package](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-package.html) and an [execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html). The deployment package is a .zip file archive or container image that contains your function code. The execution role grants the function permission to use AWS services, such as Amazon CloudWatch Logs for log streaming and AWS X-Ray for request tracing.\n You set the package type to ``Image`` if the deployment package is a [container image](https://docs.aws.amazon.com/lambda/latest/dg/lambda-images.html). For a container image, the code property must include the URI of a container image in the Amazon ECR registry. You do not need to specify the handler and runtime properties. \n You set the package type to ``Zip`` if the deployment package is a [.zip file archive](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-package.html#gettingstarted-package-zip). For a .zip file archive, the code property specifies the location of the .zip file. You must also specify the handler and runtime properties. For a Python example, see [Deploy Python Lambda functions with .zip file archives](https://docs.aws.amazon.com/lambda/latest/dg/python-package.html).\n You can use [code signing](https://docs.aws.amazon.com/lambda/latest/dg/configuration-codesigning.html) if your deployment package is a .zip file archive. To enable code signing for this function, specify the ARN of a code-signing configuration. When a user attempts to deploy a code package with ``UpdateFunctionCode``, Lambda checks that the code package has a valid signature from a trusted publisher. The code-signing configuration includes a set of signing profiles, which define the trusted publishers for this function.\n Note that you configure [provisioned concurrency](https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html) on a ``AWS::Lambda::Version`` or a ``AWS::Lambda::Alias``.\n For a complete introduction to Lambda functions, see [What is Lambda?](https://docs.aws.amazon.com/lambda/latest/dg/lambda-welcome.html) in the *Lambda developer guide.*", + "writeOnlyProperties" : [ "/properties/SnapStart", "/properties/SnapStart/ApplyOn", "/properties/Code", "/properties/Code/ImageUri", "/properties/Code/S3Bucket", "/properties/Code/S3Key", "/properties/Code/S3ObjectVersion", "/properties/Code/ZipFile" ], + "createOnlyProperties" : [ "/properties/FunctionName" ], + "additionalProperties" : false, + "primaryIdentifier" : [ "/properties/FunctionName" ], + "definitions" : { + "ImageConfig" : { + "description" : "Configuration values that override the container image Dockerfile settings. For more information, see [Container image settings](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-parms).", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "WorkingDirectory" : { + "description" : "Specifies the working directory. The length of the directory string cannot exceed 1,000 characters.", + "type" : "string" + }, + "Command" : { + "maxItems" : 1500, + "uniqueItems" : true, + "description" : "Specifies parameters that you want to pass in with ENTRYPOINT. You can specify a maximum of 1,500 parameters in the list.", + "type" : "array", + "items" : { + "type" : "string" + } + }, + "EntryPoint" : { + "maxItems" : 1500, + "uniqueItems" : true, + "description" : "Specifies the entry point to their application, which is typically the location of the runtime executable. You can specify a maximum of 1,500 string entries in the list.", + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "TracingConfig" : { + "description" : "The function's [](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html) tracing configuration. To sample and record incoming requests, set ``Mode`` to ``Active``.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "Mode" : { + "description" : "The tracing mode.", + "type" : "string", + "enum" : [ "Active", "PassThrough" ] + } + } + }, + "VpcConfig" : { + "description" : "The VPC security groups and subnets that are attached to a Lambda function. When you connect a function to a VPC, Lambda creates an elastic network interface for each combination of security group and subnet in the function's VPC configuration. The function can only access resources and the internet through that VPC. For more information, see [VPC Settings](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html).\n When you delete a function, CFN monitors the state of its network interfaces and waits for Lambda to delete them before proceeding. If the VPC is defined in the same stack, the network interfaces need to be deleted by Lambda before CFN can delete the VPC's resources.\n To monitor network interfaces, CFN needs the ``ec2:DescribeNetworkInterfaces`` permission. It obtains this from the user or role that modifies the stack. If you don't provide this permission, CFN does not wait for network interfaces to be deleted.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "Ipv6AllowedForDualStack" : { + "description" : "Allows outbound IPv6 traffic on VPC functions that are connected to dual-stack subnets.", + "type" : "boolean" + }, + "SecurityGroupIds" : { + "maxItems" : 5, + "uniqueItems" : false, + "description" : "A list of VPC security group IDs.", + "type" : "array", + "items" : { + "type" : "string" + } + }, + "SubnetIds" : { + "maxItems" : 16, + "uniqueItems" : false, + "description" : "A list of VPC subnet IDs.", + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "DeadLetterConfig" : { + "description" : "The [dead-letter queue](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#dlq) for failed asynchronous invocations.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "TargetArn" : { + "pattern" : "^(arn:(aws[a-zA-Z-]*)?:[a-z0-9-.]+:.*)|()$", + "description" : "The Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic.", + "type" : "string" + } + } + }, + "RuntimeManagementConfig" : { + "description" : "Sets the runtime management configuration for a function's version. For more information, see [Runtime updates](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html).", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "UpdateRuntimeOn" : { + "description" : "Specify the runtime update mode.\n + *Auto (default)* - Automatically update to the most recent and secure runtime version using a [Two-phase runtime version rollout](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html#runtime-management-two-phase). This is the best choice for most customers to ensure they always benefit from runtime updates.\n + *FunctionUpdate* - LAM updates the runtime of you function to the most recent and secure runtime version when you update your function. This approach synchronizes runtime updates with function deployments, giving you control over when runtime updates are applied and allowing you to detect and mitigate rare runtime update incompatibilities early. When using this setting, you need to regularly update your functions to keep their runtime up-to-date.\n + *Manual* - You specify a runtime version in your function configuration. The function will use this runtime version indefinitely. In the rare case where a new runtime version is incompatible with an existing function, this allows you to roll back your function to an earlier runtime version. For more information, see [Roll back a runtime version](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html#runtime-management-rollback).\n \n *Valid Values*: ``Auto`` | ``FunctionUpdate`` | ``Manual``", + "type" : "string", + "enum" : [ "Auto", "FunctionUpdate", "Manual" ] + }, + "RuntimeVersionArn" : { + "description" : "The ARN of the runtime version you want the function to use.\n This is only required if you're using the *Manual* runtime update mode.", + "type" : "string" + } + }, + "required" : [ "UpdateRuntimeOn" ] + }, + "SnapStart" : { + "description" : "The function's [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) setting.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "ApplyOn" : { + "description" : "Set ``ApplyOn`` to ``PublishedVersions`` to create a snapshot of the initialized execution environment when you publish a function version.", + "type" : "string", + "enum" : [ "PublishedVersions", "None" ] + } + }, + "required" : [ "ApplyOn" ] + }, + "SnapStartResponse" : { + "description" : "The function's [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) setting.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "OptimizationStatus" : { + "description" : "When you provide a [qualified Amazon Resource Name (ARN)](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html#versioning-versions-using), this response element indicates whether SnapStart is activated for the specified function version.", + "type" : "string", + "enum" : [ "On", "Off" ] + }, + "ApplyOn" : { + "description" : "When set to ``PublishedVersions``, Lambda creates a snapshot of the execution environment when you publish a function version.", + "type" : "string", + "enum" : [ "PublishedVersions", "None" ] + } + } + }, + "Code" : { + "description" : "The [deployment package](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-package.html) for a Lambda function. To deploy a function defined as a container image, you specify the location of a container image in the Amazon ECR registry. For a .zip file deployment package, you can specify the location of an object in Amazon S3. For Node.js and Python functions, you can specify the function code inline in the template.\n Changes to a deployment package in Amazon S3 or a container image in ECR are not detected automatically during stack updates. To update the function code, change the object key or version in the template.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "SourceKMSKeyArn" : { + "pattern" : "^(arn:(aws[a-zA-Z-]*)?:[a-z0-9-.]+:.*)|()$", + "description" : "", + "type" : "string" + }, + "S3ObjectVersion" : { + "minLength" : 1, + "description" : "For versioned objects, the version of the deployment package object to use.", + "type" : "string", + "maxLength" : 1024 + }, + "S3Bucket" : { + "minLength" : 3, + "pattern" : "^[0-9A-Za-z\\.\\-_]*(?``. To use a different log group, enter an existing log group or enter a new log group name.", + "type" : "string", + "maxLength" : 512 + }, + "SystemLogLevel" : { + "description" : "Set this property to filter the system logs for your function that Lambda sends to CloudWatch. Lambda only sends system logs at the selected level of detail and lower, where ``DEBUG`` is the highest level and ``WARN`` is the lowest.", + "type" : "string", + "enum" : [ "DEBUG", "INFO", "WARN" ] + } + } + }, + "RecursiveLoop" : { + "description" : "The function recursion configuration.", + "type" : "string", + "enum" : [ "Allow", "Terminate" ] + }, + "Environment" : { + "description" : "A function's environment variable settings. You can use environment variables to adjust your function's behavior without updating code. An environment variable is a pair of strings that are stored in a function's version-specific configuration.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "Variables" : { + "patternProperties" : { + "[a-zA-Z][a-zA-Z0-9_]+" : { + "type" : "string" + } + }, + "description" : "Environment variable key-value pairs. For more information, see [Using Lambda environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html).", + "additionalProperties" : false, + "type" : "object" + } + } + }, + "FileSystemConfig" : { + "description" : "Details about the connection between a Lambda function and an [Amazon EFS file system](https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem.html).", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "Arn" : { + "pattern" : "^arn:aws[a-zA-Z-]*:elasticfilesystem:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\\d{1}:\\d{12}:access-point/fsap-[a-f0-9]{17}$", + "description" : "The Amazon Resource Name (ARN) of the Amazon EFS access point that provides access to the file system.", + "type" : "string", + "maxLength" : 200 + }, + "LocalMountPath" : { + "pattern" : "^/mnt/[a-zA-Z0-9-_.]+$", + "description" : "The path where the function can access the file system, starting with ``/mnt/``.", + "type" : "string", + "maxLength" : 160 + } + }, + "required" : [ "Arn", "LocalMountPath" ] + }, + "Tag" : { + "description" : "", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "Value" : { + "minLength" : 0, + "description" : "", + "type" : "string", + "maxLength" : 256 + }, + "Key" : { + "minLength" : 1, + "description" : "", + "type" : "string", + "maxLength" : 128 + } + }, + "required" : [ "Key" ] + }, + "EphemeralStorage" : { + "description" : "The size of the function's ``/tmp`` directory in MB. The default value is 512, but it can be any whole number between 512 and 10,240 MB.", + "additionalProperties" : false, + "type" : "object", + "properties" : { + "Size" : { + "description" : "The size of the function's ``/tmp`` directory.", + "maximum" : 10240, + "type" : "integer", + "minimum" : 512 + } + }, + "required" : [ "Size" ] + } + }, + "required" : [ "Code", "Role" ], + "properties" : { + "Description" : { + "description" : "A description of the function.", + "type" : "string", + "maxLength" : 256 + }, + "TracingConfig" : { + "description" : "Set ``Mode`` to ``Active`` to sample and trace a subset of incoming requests with [X-Ray](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html).", + "$ref" : "#/definitions/TracingConfig" + }, + "VpcConfig" : { + "description" : "For network connectivity to AWS resources in a VPC, specify a list of security groups and subnets in the VPC. When you connect a function to a VPC, it can access resources and the internet only through that VPC. For more information, see [Configuring a Lambda function to access resources in a VPC](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html).", + "$ref" : "#/definitions/VpcConfig" + }, + "RuntimeManagementConfig" : { + "description" : "Sets the runtime management configuration for a function's version. For more information, see [Runtime updates](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html).", + "$ref" : "#/definitions/RuntimeManagementConfig" + }, + "ReservedConcurrentExecutions" : { + "description" : "The number of simultaneous executions to reserve for the function.", + "type" : "integer", + "minimum" : 0 + }, + "SnapStart" : { + "description" : "The function's [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) setting.", + "$ref" : "#/definitions/SnapStart" + }, + "FileSystemConfigs" : { + "maxItems" : 1, + "description" : "Connection settings for an Amazon EFS file system. To connect a function to a file system, a mount target must be available in every Availability Zone that your function connects to. If your template contains an [AWS::EFS::MountTarget](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html) resource, you must also specify a ``DependsOn`` attribute to ensure that the mount target is created or updated before the function.\n For more information about using the ``DependsOn`` attribute, see [DependsOn Attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html).", + "type" : "array", + "items" : { + "$ref" : "#/definitions/FileSystemConfig" + } + }, + "FunctionName" : { + "minLength" : 1, + "description" : "The name of the Lambda function, up to 64 characters in length. If you don't specify a name, CFN generates one.\n If you specify a name, you cannot perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", + "type" : "string" + }, + "Runtime" : { + "description" : "The identifier of the function's [runtime](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). Runtime is required if the deployment package is a .zip file archive. Specifying a runtime results in an error if you're deploying a function using a container image.\n The following list includes deprecated runtimes. Lambda blocks creating new functions and updating existing functions shortly after each runtime is deprecated. For more information, see [Runtime use after deprecation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtime-deprecation-levels).\n For a list of all currently supported runtimes, see [Supported runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtimes-supported).", + "type" : "string" + }, + "KmsKeyArn" : { + "pattern" : "^(arn:(aws[a-zA-Z-]*)?:[a-z0-9-.]+:.*)|()$", + "description" : "The ARN of the KMSlong (KMS) customer managed key that's used to encrypt your function's [environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-encryption). When [Lambda SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart-security.html) is activated, Lambda also uses this key is to encrypt your function's snapshot. If you deploy your function using a container image, Lambda also uses this key to encrypt your function when it's deployed. Note that this is not the same key that's used to protect your container image in the Amazon Elastic Container Registry (Amazon ECR). If you don't provide a customer managed key, Lambda uses a default service key.", + "type" : "string" + }, + "PackageType" : { + "description" : "The type of deployment package. Set to ``Image`` for container image and set ``Zip`` for .zip file archive.", + "type" : "string", + "enum" : [ "Image", "Zip" ] + }, + "CodeSigningConfigArn" : { + "pattern" : "arn:(aws[a-zA-Z-]*)?:lambda:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\\d{1}:\\d{12}:code-signing-config:csc-[a-z0-9]{17}", + "description" : "To enable code signing for this function, specify the ARN of a code-signing configuration. A code-signing configuration includes a set of signing profiles, which define the trusted publishers for this function.", + "type" : "string" + }, + "Layers" : { + "uniqueItems" : false, + "description" : "A list of [function layers](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) to add to the function's execution environment. Specify each layer by its ARN, including the version.", + "type" : "array", + "items" : { + "type" : "string" + } + }, + "Tags" : { + "uniqueItems" : true, + "description" : "A list of [tags](https://docs.aws.amazon.com/lambda/latest/dg/tagging.html) to apply to the function.", + "insertionOrder" : false, + "type" : "array", + "items" : { + "$ref" : "#/definitions/Tag" + } + }, + "ImageConfig" : { + "description" : "Configuration values that override the container image Dockerfile settings. For more information, see [Container image settings](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-parms).", + "$ref" : "#/definitions/ImageConfig" + }, + "MemorySize" : { + "description" : "The amount of [memory available to the function](https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html#configuration-memory-console) at runtime. Increasing the function memory also increases its CPU allocation. The default value is 128 MB. The value can be any multiple of 1 MB. Note that new AWS accounts have reduced concurrency and memory quotas. AWS raises these quotas automatically based on your usage. You can also request a quota increase.", + "type" : "integer" + }, + "DeadLetterConfig" : { + "description" : "A dead-letter queue configuration that specifies the queue or topic where Lambda sends asynchronous events when they fail processing. For more information, see [Dead-letter queues](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-dlq).", + "$ref" : "#/definitions/DeadLetterConfig" + }, + "Timeout" : { + "description" : "The amount of time (in seconds) that Lambda allows a function to run before stopping it. The default is 3 seconds. The maximum allowed value is 900 seconds. For more information, see [Lambda execution environment](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html).", + "type" : "integer", + "minimum" : 1 + }, + "Handler" : { + "pattern" : "^[^\\s]+$", + "description" : "The name of the method within your code that Lambda calls to run your function. Handler is required if the deployment package is a .zip file archive. The format includes the file name. It can also include namespaces and other qualifiers, depending on the runtime. For more information, see [Lambda programming model](https://docs.aws.amazon.com/lambda/latest/dg/foundation-progmodel.html).", + "type" : "string", + "maxLength" : 128 + }, + "SnapStartResponse" : { + "description" : "", + "$ref" : "#/definitions/SnapStartResponse" + }, + "Code" : { + "description" : "The code for the function.", + "$ref" : "#/definitions/Code" + }, + "Role" : { + "pattern" : "^arn:(aws[a-zA-Z-]*)?:iam::\\d{12}:role/?[a-zA-Z_0-9+=,.@\\-_/]+$", + "description" : "The Amazon Resource Name (ARN) of the function's execution role.", + "type" : "string" + }, + "LoggingConfig" : { + "description" : "The function's Amazon CloudWatch Logs configuration settings.", + "$ref" : "#/definitions/LoggingConfig" + }, + "RecursiveLoop" : { + "description" : "", + "$ref" : "#/definitions/RecursiveLoop" + }, + "Environment" : { + "description" : "Environment variables that are accessible from function code during execution.", + "$ref" : "#/definitions/Environment" + }, + "Arn" : { + "description" : "", + "type" : "string" + }, + "EphemeralStorage" : { + "description" : "The size of the function's ``/tmp`` directory in MB. The default value is 512, but it can be any whole number between 512 and 10,240 MB.", + "$ref" : "#/definitions/EphemeralStorage" + }, + "Architectures" : { + "minItems" : 1, + "maxItems" : 1, + "uniqueItems" : true, + "description" : "The instruction set architecture that the function supports. Enter a string array with one of the valid values (arm64 or x86_64). The default value is ``x86_64``.", + "type" : "array", + "items" : { + "type" : "string", + "enum" : [ "x86_64", "arm64" ] + } + } + } + } \ No newline at end of file