diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json new file mode 100644 index 0000000000000..1e34ca625f5ac --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json @@ -0,0 +1,19 @@ +{ + "version": "32.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "IntegTestDefaultTestDeployAssertE3E7D2A4.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.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.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.params-and-secrets.js.snapshot/Stack1.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack1.assets.json new file mode 100644 index 0000000000000..d9f0589909a65 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack1.assets.json @@ -0,0 +1,32 @@ +{ + "version": "32.0.0", + "files": { + "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead": { + "source": { + "path": "asset.b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "64fb6d6ac3e1f7cda4cb6336b78f1be8f0e1f6c6323b232c8e04430a803085a2": { + "source": { + "path": "Stack1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "64fb6d6ac3e1f7cda4cb6336b78f1be8f0e1f6c6323b232c8e04430a803085a2.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.params-and-secrets.js.snapshot/Stack1.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack1.template.json new file mode 100644 index 0000000000000..b9047a17d14cd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack1.template.json @@ -0,0 +1,287 @@ +{ + "Resources": { + "Parameter9E1B4FBA": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "api.example.com", + "Name": "email_url_Stack1" + } + }, + "MySecret8FE80B51": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": {} + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "MyFuncServiceRole54065130": { + "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" + ] + ] + } + ] + } + }, + "MyFuncServiceRoleDefaultPolicyF3C36699": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": { + "Ref": "MySecret8FE80B51" + } + }, + { + "Action": [ + "ssm:DescribeParameters", + "ssm:GetParameter", + "ssm:GetParameterHistory", + "ssm:GetParameters" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":parameter/", + { + "Ref": "Parameter9E1B4FBA" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyFuncServiceRoleDefaultPolicyF3C36699", + "Roles": [ + { + "Ref": "MyFuncServiceRole54065130" + } + ] + } + }, + "MyFunc8A243A2C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFuncServiceRole54065130", + "Arn" + ] + }, + "Architectures": [ + "x86_64" + ], + "Environment": { + "Variables": { + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED": "true", + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE": "100", + "PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT": "2773", + "PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL": "info", + "PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS": "3", + "SECRETS_MANAGER_TIMEOUT_MILLIS": "0", + "SECRETS_MANAGER_TTL": "100", + "SSM_PARAMETER_STORE_TIMEOUT_MILLIS": "0", + "SSM_PARAMETER_STORE_TTL": "100" + } + }, + "Handler": "index.handler", + "Layers": [ + { + "Fn::FindInMap": [ + "ParamsandsecretslayerMap", + { + "Ref": "AWS::Region" + }, + "1x0x103xx86x64" + ] + } + ], + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "MyFuncServiceRoleDefaultPolicyF3C36699", + "MyFuncServiceRole54065130" + ] + } + }, + "Mappings": { + "ParamsandsecretslayerMap": { + "af-south-1": { + "1x0x103xx86x64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-east-1": { + "1x0x103xx86x64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-northeast-1": { + "1x0x103xx86x64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-northeast-2": { + "1x0x103xx86x64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-northeast-3": { + "1x0x103xx86x64": "arn:aws:lambda:ap-northeast-3:576959938190:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-south-1": { + "1x0x103xx86x64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-south-2": { + "1x0x103xx86x64": "arn:aws:lambda:ap-south-2:070087711984:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + }, + "ap-southeast-1": { + "1x0x103xx86x64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-southeast-2": { + "1x0x103xx86x64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-southeast-3": { + "1x0x103xx86x64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ca-central-1": { + "1x0x103xx86x64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "cn-north-1": { + "1x0x103xx86x64": "arn:aws-cn:lambda:cn-north-1:287114880934:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "cn-northwest-1": { + "1x0x103xx86x64": "arn:aws-cn:lambda:cn-northwest-1:287310001119:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-central-1": { + "1x0x103xx86x64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-central-2": { + "1x0x103xx86x64": "arn:aws:lambda:eu-central-2:772501565639:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + }, + "eu-north-1": { + "1x0x103xx86x64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-south-1": { + "1x0x103xx86x64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-south-2": { + "1x0x103xx86x64": "arn:aws:lambda:eu-south-2:524103009944:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + }, + "eu-west-1": { + "1x0x103xx86x64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-west-2": { + "1x0x103xx86x64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-west-3": { + "1x0x103xx86x64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "me-central-1": { + "1x0x103xx86x64": "arn:aws:lambda:me-central-1:858974508948:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "me-south-1": { + "1x0x103xx86x64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "sa-east-1": { + "1x0x103xx86x64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-east-1": { + "1x0x103xx86x64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-east-2": { + "1x0x103xx86x64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-gov-east-1": { + "1x0x103xx86x64": "arn:aws-us-gov:lambda:us-gov-east-1:129776340158:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-gov-west-1": { + "1x0x103xx86x64": "arn:aws-us-gov:lambda:us-gov-west-1:127562683043:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-west-1": { + "1x0x103xx86x64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-west-2": { + "1x0x103xx86x64": "arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + } + } + }, + "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.params-and-secrets.js.snapshot/Stack2.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack2.assets.json new file mode 100644 index 0000000000000..c479d0cf31250 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack2.assets.json @@ -0,0 +1,32 @@ +{ + "version": "32.0.0", + "files": { + "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead": { + "source": { + "path": "asset.b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "6e1695d4618774814bd2b919c4dfbc4e9eee44fc0caea11b6c60b543848088a8": { + "source": { + "path": "Stack2.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6e1695d4618774814bd2b919c4dfbc4e9eee44fc0caea11b6c60b543848088a8.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.params-and-secrets.js.snapshot/Stack2.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack2.template.json new file mode 100644 index 0000000000000..3394165ca5eb7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack2.template.json @@ -0,0 +1,260 @@ +{ + "Resources": { + "Parameter9E1B4FBA": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "api.example.com", + "Name": "email_url_Stack2" + } + }, + "MySecret8FE80B51": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": {} + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "MyFuncServiceRole54065130": { + "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" + ] + ] + } + ] + } + }, + "MyFuncServiceRoleDefaultPolicyF3C36699": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": { + "Ref": "MySecret8FE80B51" + } + }, + { + "Action": [ + "ssm:DescribeParameters", + "ssm:GetParameter", + "ssm:GetParameterHistory", + "ssm:GetParameters" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":parameter/", + { + "Ref": "Parameter9E1B4FBA" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "MyFuncServiceRoleDefaultPolicyF3C36699", + "Roles": [ + { + "Ref": "MyFuncServiceRole54065130" + } + ] + } + }, + "MyFunc8A243A2C": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MyFuncServiceRole54065130", + "Arn" + ] + }, + "Architectures": [ + "arm64" + ], + "Environment": { + "Variables": { + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED": "true", + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE": "100", + "PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT": "2773", + "PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL": "info", + "PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS": "3", + "SECRETS_MANAGER_TIMEOUT_MILLIS": "0", + "SECRETS_MANAGER_TTL": "100", + "SSM_PARAMETER_STORE_TIMEOUT_MILLIS": "0", + "SSM_PARAMETER_STORE_TTL": "100" + } + }, + "Handler": "index.handler", + "Layers": [ + { + "Fn::FindInMap": [ + "ParamsandsecretslayerMap", + { + "Ref": "AWS::Region" + }, + "1x0x103xarm64" + ] + } + ], + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "MyFuncServiceRoleDefaultPolicyF3C36699", + "MyFuncServiceRole54065130" + ] + } + }, + "Mappings": { + "ParamsandsecretslayerMap": { + "af-south-1": { + "1x0x103xarm64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ap-east-1": { + "1x0x103xarm64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ap-northeast-1": { + "1x0x103xarm64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-northeast-2": { + "1x0x103xarm64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ap-south-1": { + "1x0x103xarm64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-southeast-1": { + "1x0x103xarm64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-southeast-2": { + "1x0x103xarm64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-southeast-3": { + "1x0x103xarm64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ca-central-1": { + "1x0x103xarm64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "eu-central-1": { + "1x0x103xarm64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "eu-north-1": { + "1x0x103xarm64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "eu-south-1": { + "1x0x103xarm64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "eu-west-1": { + "1x0x103xarm64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "eu-west-2": { + "1x0x103xarm64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "eu-west-3": { + "1x0x103xarm64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "me-south-1": { + "1x0x103xarm64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "sa-east-1": { + "1x0x103xarm64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "us-east-1": { + "1x0x103xarm64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "us-east-2": { + "1x0x103xarm64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "us-west-1": { + "1x0x103xarm64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "us-west-2": { + "1x0x103xarm64": "arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + } + } + }, + "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.params-and-secrets.js.snapshot/asset.b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead/index.py b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/asset.b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead/index.py new file mode 100644 index 0000000000000..6f90dffcb187b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/asset.b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead/index.py @@ -0,0 +1,19 @@ +import requests +import os + +def handler(event, context): + # authentication header + session_token = os.environ.get('AWS_SESSION_TOKEN') + headers = {'X-Aws-Parameters-Secrets-Token': session_token} + + # request to parameter store + parameter_url = 'http://localhost:2773/systemsmanager/parameters/get?name=email_url' + response = requests.get(parameter_url, headers=headers) + print(f'response status code from HTTP for parameters request was {response.status_code}') + print(f'response json is {response.json()}') + + # request to secrets manager + secrets_url = 'https://localhost:2773/secretsmanager/get?secretId=MySecret' + response = requests.get(secrets_url, headers=headers) + print(f'response status code from HTTP for secrets request was {response.status_code}') + print(f'response json is {response.json()}') diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/cdk.out new file mode 100644 index 0000000000000..f0b901e7c06e5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"32.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/integ.json new file mode 100644 index 0000000000000..263e489ed7e1c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "32.0.0", + "testCases": { + "IntegTest/DefaultTest": { + "stacks": [ + "Stack1", + "Stack2" + ], + "assertionStack": "IntegTest/DefaultTest/DeployAssert", + "assertionStackName": "IntegTestDefaultTestDeployAssertE3E7D2A4" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/manifest.json new file mode 100644 index 0000000000000..6d79bb48e4802 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/manifest.json @@ -0,0 +1,224 @@ +{ + "version": "32.0.0", + "artifacts": { + "Stack1.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "Stack1.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "Stack1": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "Stack1.template.json", + "validateOnSynth": false, + "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}/64fb6d6ac3e1f7cda4cb6336b78f1be8f0e1f6c6323b232c8e04430a803085a2.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "Stack1.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": [ + "Stack1.assets" + ], + "metadata": { + "/Stack1/Parameter/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Parameter9E1B4FBA" + } + ], + "/Stack1/MySecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MySecret8FE80B51" + } + ], + "/Stack1/MyFunc/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFuncServiceRole54065130" + } + ], + "/Stack1/MyFunc/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFuncServiceRoleDefaultPolicyF3C36699" + } + ], + "/Stack1/MyFunc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunc8A243A2C" + } + ], + "/Stack1/Params-and-secrets-layerMap": [ + { + "type": "aws:cdk:logicalId", + "data": "ParamsandsecretslayerMap" + } + ], + "/Stack1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Stack1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Stack1" + }, + "Stack2.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "Stack2.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "Stack2": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "Stack2.template.json", + "validateOnSynth": false, + "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}/6e1695d4618774814bd2b919c4dfbc4e9eee44fc0caea11b6c60b543848088a8.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "Stack2.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": [ + "Stack2.assets" + ], + "metadata": { + "/Stack2/Parameter/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Parameter9E1B4FBA" + } + ], + "/Stack2/MySecret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MySecret8FE80B51" + } + ], + "/Stack2/MyFunc/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFuncServiceRole54065130" + } + ], + "/Stack2/MyFunc/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFuncServiceRoleDefaultPolicyF3C36699" + } + ], + "/Stack2/MyFunc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyFunc8A243A2C" + } + ], + "/Stack2/Params-and-secrets-layerMap": [ + { + "type": "aws:cdk:logicalId", + "data": "ParamsandsecretslayerMap" + } + ], + "/Stack2/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/Stack2/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "Stack2" + }, + "IntegTestDefaultTestDeployAssertE3E7D2A4.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "IntegTestDefaultTestDeployAssertE3E7D2A4": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "IntegTestDefaultTestDeployAssertE3E7D2A4.template.json", + "validateOnSynth": false, + "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": [ + "IntegTestDefaultTestDeployAssertE3E7D2A4.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": [ + "IntegTestDefaultTestDeployAssertE3E7D2A4.assets" + ], + "metadata": { + "/IntegTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/IntegTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "IntegTest/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.params-and-secrets.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/tree.json new file mode 100644 index 0000000000000..85aa9315b3d14 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/tree.json @@ -0,0 +1,705 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Stack1": { + "id": "Stack1", + "path": "Stack1", + "children": { + "Parameter": { + "id": "Parameter", + "path": "Stack1/Parameter", + "children": { + "Resource": { + "id": "Resource", + "path": "Stack1/Parameter/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SSM::Parameter", + "aws:cdk:cloudformation:props": { + "type": "String", + "value": "api.example.com", + "name": "email_url_Stack1" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ssm.CfnParameter", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ssm.StringParameter", + "version": "0.0.0" + } + }, + "MySecret": { + "id": "MySecret", + "path": "Stack1/MySecret", + "children": { + "Resource": { + "id": "Resource", + "path": "Stack1/MySecret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "generateSecretString": {} + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.Secret", + "version": "0.0.0" + } + }, + "MyFunc": { + "id": "MyFunc", + "path": "Stack1/MyFunc", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "Stack1/MyFunc/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "Stack1/MyFunc/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "Stack1/MyFunc/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": "Stack1/MyFunc/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "Stack1/MyFunc/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": { + "Ref": "MySecret8FE80B51" + } + }, + { + "Action": [ + "ssm:DescribeParameters", + "ssm:GetParameter", + "ssm:GetParameterHistory", + "ssm:GetParameters" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":parameter/", + { + "Ref": "Parameter9E1B4FBA" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "MyFuncServiceRoleDefaultPolicyF3C36699", + "roles": [ + { + "Ref": "MyFuncServiceRole54065130" + } + ] + } + }, + "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": "Stack1/MyFunc/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "Stack1/MyFunc/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "Stack1/MyFunc/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": "Stack1/MyFunc/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": "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead.zip" + }, + "role": { + "Fn::GetAtt": [ + "MyFuncServiceRole54065130", + "Arn" + ] + }, + "architectures": [ + "x86_64" + ], + "environment": { + "variables": { + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED": "true", + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE": "100", + "PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT": "2773", + "PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL": "info", + "PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS": "3", + "SECRETS_MANAGER_TIMEOUT_MILLIS": "0", + "SECRETS_MANAGER_TTL": "100", + "SSM_PARAMETER_STORE_TIMEOUT_MILLIS": "0", + "SSM_PARAMETER_STORE_TTL": "100" + } + }, + "handler": "index.handler", + "layers": [ + { + "Fn::FindInMap": [ + "ParamsandsecretslayerMap", + { + "Ref": "AWS::Region" + }, + "1x0x103xx86x64" + ] + } + ], + "runtime": "nodejs18.x" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + }, + "ParamsAndSecretsLayer": { + "id": "ParamsAndSecretsLayer", + "path": "Stack1/MyFunc/ParamsAndSecretsLayer", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "Params-and-secrets-layerMap": { + "id": "Params-and-secrets-layerMap", + "path": "Stack1/Params-and-secrets-layerMap", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnMapping", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Stack1/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Stack1/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "Stack2": { + "id": "Stack2", + "path": "Stack2", + "children": { + "Parameter": { + "id": "Parameter", + "path": "Stack2/Parameter", + "children": { + "Resource": { + "id": "Resource", + "path": "Stack2/Parameter/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SSM::Parameter", + "aws:cdk:cloudformation:props": { + "type": "String", + "value": "api.example.com", + "name": "email_url_Stack2" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ssm.CfnParameter", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ssm.StringParameter", + "version": "0.0.0" + } + }, + "MySecret": { + "id": "MySecret", + "path": "Stack2/MySecret", + "children": { + "Resource": { + "id": "Resource", + "path": "Stack2/MySecret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "generateSecretString": {} + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.Secret", + "version": "0.0.0" + } + }, + "MyFunc": { + "id": "MyFunc", + "path": "Stack2/MyFunc", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "Stack2/MyFunc/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "Stack2/MyFunc/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "Stack2/MyFunc/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": "Stack2/MyFunc/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "Stack2/MyFunc/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": { + "Ref": "MySecret8FE80B51" + } + }, + { + "Action": [ + "ssm:DescribeParameters", + "ssm:GetParameter", + "ssm:GetParameterHistory", + "ssm:GetParameters" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":parameter/", + { + "Ref": "Parameter9E1B4FBA" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "MyFuncServiceRoleDefaultPolicyF3C36699", + "roles": [ + { + "Ref": "MyFuncServiceRole54065130" + } + ] + } + }, + "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": "Stack2/MyFunc/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "Stack2/MyFunc/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "Stack2/MyFunc/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": "Stack2/MyFunc/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": "b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead.zip" + }, + "role": { + "Fn::GetAtt": [ + "MyFuncServiceRole54065130", + "Arn" + ] + }, + "architectures": [ + "arm64" + ], + "environment": { + "variables": { + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED": "true", + "PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE": "100", + "PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT": "2773", + "PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL": "info", + "PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS": "3", + "SECRETS_MANAGER_TIMEOUT_MILLIS": "0", + "SECRETS_MANAGER_TTL": "100", + "SSM_PARAMETER_STORE_TIMEOUT_MILLIS": "0", + "SSM_PARAMETER_STORE_TTL": "100" + } + }, + "handler": "index.handler", + "layers": [ + { + "Fn::FindInMap": [ + "ParamsandsecretslayerMap", + { + "Ref": "AWS::Region" + }, + "1x0x103xarm64" + ] + } + ], + "runtime": "nodejs18.x" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", + "version": "0.0.0" + } + }, + "ParamsAndSecretsLayer": { + "id": "ParamsAndSecretsLayer", + "path": "Stack2/MyFunc/ParamsAndSecretsLayer", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "Params-and-secrets-layerMap": { + "id": "Params-and-secrets-layerMap", + "path": "Stack2/Params-and-secrets-layerMap", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnMapping", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "Stack2/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "Stack2/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "IntegTest": { + "id": "IntegTest", + "path": "IntegTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "IntegTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "IntegTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.26" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "IntegTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "IntegTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "IntegTest/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.2.26" + } + } + }, + "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.params-and-secrets.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.ts new file mode 100644 index 0000000000000..661eb7c17dad1 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.ts @@ -0,0 +1,62 @@ +import * as cdk from 'aws-cdk-lib'; +import * as path from 'path'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { Construct } from 'constructs'; +import { StackProps, Stack } from 'aws-cdk-lib'; +import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; +import { StringParameter } from 'aws-cdk-lib/aws-ssm'; +import { + Architecture, + Function, + Runtime, + Code, + ParamsAndSecretsLayerVersion, + ParamsAndSecretsVersions, +} from 'aws-cdk-lib/aws-lambda'; + +const app = new cdk.App(); + +interface StackUnderTestProps extends StackProps { + architecture: Architecture, +} + +class StackUnderTest extends Stack { + constructor(scope: Construct, id: string, props: StackUnderTestProps) { + super(scope, id, props); + + const parameter = new StringParameter(this, 'Parameter', { + parameterName: `email_url_${id}`, + stringValue: 'api.example.com', + }); + const secret = new Secret(this, 'MySecret'); + + new Function(this, 'MyFunc', { + runtime: Runtime.NODEJS_18_X, + handler: 'index.handler', + code: Code.fromAsset(path.join(__dirname, 'params-and-secrets-handler')), + architecture: props.architecture, + paramsAndSecrets: { + layerVersion: ParamsAndSecretsLayerVersion.fromVersion(ParamsAndSecretsVersions.V1_0_103, { + cacheSize: 100, + secretsManagerTtl: cdk.Duration.seconds(100), + parameterStoreTtl: cdk.Duration.seconds(100), + }), + secrets: [secret], + parameters: [parameter], + }, + }); + } +} + +new IntegTest(app, 'IntegTest', { + testCases: [ + new StackUnderTest(app, 'Stack1', { + architecture: Architecture.X86_64, + }), + new StackUnderTest(app, 'Stack2', { + architecture: Architecture.ARM_64, + }), + ], +}); + +app.synth(); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/params-and-secrets-handler/index.py b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/params-and-secrets-handler/index.py new file mode 100644 index 0000000000000..6f90dffcb187b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/params-and-secrets-handler/index.py @@ -0,0 +1,19 @@ +import requests +import os + +def handler(event, context): + # authentication header + session_token = os.environ.get('AWS_SESSION_TOKEN') + headers = {'X-Aws-Parameters-Secrets-Token': session_token} + + # request to parameter store + parameter_url = 'http://localhost:2773/systemsmanager/parameters/get?name=email_url' + response = requests.get(parameter_url, headers=headers) + print(f'response status code from HTTP for parameters request was {response.status_code}') + print(f'response json is {response.json()}') + + # request to secrets manager + secrets_url = 'https://localhost:2773/secretsmanager/get?secretId=MySecret' + response = requests.get(secrets_url, headers=headers) + print(f'response status code from HTTP for secrets request was {response.status_code}') + print(f'response json is {response.json()}') diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 88d3a68548d01..287d1d620efac 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -583,6 +583,63 @@ new lambda.Function(this, 'MyFunction', { }); ``` +### Parameters and Secrets Extension + +Lambda functions can be configured to use the Parameters and Secrets Extension. The Parameters and Secrets Extension can be used to retrieve and cache [secrets](https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html) from Secrets Manager or [parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/ps-integration-lambda-extensions.html) from Parameter Store in Lambda functions without using an SDK. + +```ts +import * as sm from 'aws-cdk-lib/aws-secretsmanager'; +import * as ssm from 'aws-cdk-lib/aws-ssm'; + +const secret = new sm.Secret(stack, 'Secret'); +const parameter = new ssm.StringParameter(stack, 'Parameter', { + parameterName: 'mySsmParameterName', + stringValue: 'mySsmParameterValue', +}); + +new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + architecture: lambda.Architecture.ARM_64, + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + cacheSize: 500, + }), + secrets: [secret], + parameters: [parameter], + }, +}); +``` + +If the version of Parameters and Secrets Extension is not yet available in the CDK, you can also provide the ARN directly as so - + +```ts +import * as sm from 'aws-cdk-lib/aws-secretsmanager'; +import * as ssm from 'aws-cdk-lib/aws-ssm'; + +const secret = new sm.Secret(stack, 'Secret'); +const parameter = new ssm.StringParameter(stack, 'Parameter', { + parameterName: 'mySsmParameterName', + stringValue: 'mySsmParameterValue', +}); + +const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; +new lambda.Function(this, 'MyFunction', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + architecture: lambda.Architecture.ARM_64, + code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheSize: 500, + }), + secrets: [secret], + parameters: [parameter], + }, +}); +``` + ## Event Rule Target You can use an AWS Lambda function as a target for an Amazon CloudWatch event diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 1018433fcfaac..b23caea41c590 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -15,6 +15,7 @@ import { Version, VersionOptions } from './lambda-version'; import { CfnFunction } from './lambda.generated'; import { LayerVersion, ILayerVersion } from './layers'; import { LogRetentionRetryOptions } from './log-retention'; +import { ParamsAndSecretsConfig } from './params-and-secrets-layers'; import { Runtime } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; import { addAlias } from './util'; @@ -260,6 +261,15 @@ export interface FunctionOptions extends EventInvokeConfigOptions { */ readonly adotInstrumentation?: AdotInstrumentationConfig; + /** + * Specify the configuration of Parameters and Secrets Extension + * @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html + * @see https://docs.aws.amazon.com/systems-manager/latest/userguide/ps-integration-lambda-extensions.html + * + * @default - No Parameters and Secrets Extension + */ + readonly paramsAndSecrets?: ParamsAndSecretsConfig; + /** * A list of layers to add to the function's execution environment. You can configure your Lambda function to pull in * additional code during initialization in the form of layers. Layers are packages of libraries or other dependencies @@ -911,6 +921,8 @@ export class Function extends FunctionBase { this.configureLambdaInsights(props); this.configureAdotInstrumentation(props); + + this.configureParamsAndSecretsExtension(props); } /** @@ -1149,6 +1161,29 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett this.addEnvironment('AWS_LAMBDA_EXEC_WRAPPER', props.adotInstrumentation.execWrapper); } + /** + * Add a Parameters and Secrets Extension Lambda layer. + */ + private configureParamsAndSecretsExtension(props: FunctionProps): void { + if (props.paramsAndSecrets === undefined) { + return; + } + + // grant permissions to lambda execution role to allow access to provided secrets + props.paramsAndSecrets.secrets?.forEach(secret => { + secret.grantRead(this); + }); + + // grant permission to lambda execution role to allow access to provided parameters + props.paramsAndSecrets.parameters?.forEach(param => { + param.grantRead(this); + }); + + const layerVersion = props.paramsAndSecrets.layerVersion._bind(this, this); + this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', layerVersion.arn)); + Object.entries(layerVersion.environmentVars).forEach(([key, value]) => this.addEnvironment(key, value.toString())); + } + private renderLayers() { if (!this._layers || this._layers.length === 0) { return undefined; diff --git a/packages/aws-cdk-lib/aws-lambda/lib/index.ts b/packages/aws-cdk-lib/aws-lambda/lib/index.ts index 2d99e775f29b6..0c8294f3f923f 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/index.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/index.ts @@ -24,6 +24,7 @@ export * from './log-retention'; export * from './architecture'; export * from './function-url'; export * from './runtime-management'; +export * from './params-and-secrets-layers'; // AWS::Lambda CloudFormation Resources: export * from './lambda.generated'; diff --git a/packages/aws-cdk-lib/aws-lambda/lib/params-and-secrets-layers.ts b/packages/aws-cdk-lib/aws-lambda/lib/params-and-secrets-layers.ts new file mode 100644 index 0000000000000..95163eca02e3f --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda/lib/params-and-secrets-layers.ts @@ -0,0 +1,282 @@ +import { Construct, IConstruct } from 'constructs'; +import { ISecret } from '../../aws-secretsmanager'; +import { IParameter } from '../../aws-ssm'; +import { Token, Stack, Duration } from '../../core'; +import { RegionInfo, FactName } from '../../region-info'; +import * as lambda from '../lib'; + +/** + * Config returned from `ParamsAndSecretsVersion._bind` + */ +interface ParamsAndSecretsBindConfig { + /** + * ARN of the Parameters and Secrets layer version + */ + readonly arn: string; + + /** + * Environment variables for the Parameters and Secrets layer configuration + */ + readonly environmentVars: { [key: string]: string }; +} + +/** + * Parameters and Secrets Extension versions + */ +export enum ParamsAndSecretsVersions { + /** + * Version 1.0.103 + * + * Note: This is the latest version + */ + V1_0_103 = '1.0.103', +} + +/** + * Logging levels for the Parametes and Secrets Extension + */ +export enum ParamsAndSecretsLogLevel { + /** + * Debug + */ + DEBUG = 'debug', + + /** + * Info + */ + INFO = 'info', + + /** + * Warn + */ + WARN = 'warn', + + /** + * Error + */ + ERROR = 'error', + + /** + * No logging + */ + NONE = 'none', +} + +/** + * Parameters and Secrets Extension configuration options + */ +export interface ParamsAndSecretsOptions { + /** + * Whether the Parameters and Secrets Extension will cache parameters and + * secrets. + * + * @default true + */ + readonly cacheEnabled?: boolean; + + /** + * The maximum number of secrets and parameters to cache. Must be a value + * from 0 to 1000. A value of 0 means there is no caching. + * + * Note: This variable is ignored if parameterStoreTtl and secretsManagerTtl + * are 0. + * + * @default 1000 + */ + readonly cacheSize?: number; + + /** + * The port for the local HTTP server. Valid port numbers are 1 - 65535. + * + * @default 2773 + */ + readonly httpPort?: number; + + /** + * The level of logging provided by the Parameters and Secrets Extension. + * + * Note: Set to debug to see the cache configuration. + * + * @default - Logging level will be `info` + */ + readonly logLevel?: ParamsAndSecretsLogLevel; + + /** + * The maximum number of connection for HTTP clients that the Parameters and + * Secrets Extension uses to make requests to Parameter Store or Secrets + * Manager. There is no maximum limit. Minimum is 1. + * + * Note: Every running copy of this Lambda function may open the number of + * connections specified by this property. Thus, the total number of connections + * may exceed this number. + * + * @default 3 + */ + readonly maxConnections?: number; + + /** + * The timeout for requests to Secrets Manager. A value of 0 means that there is + * no timeout. + * + * @default 0 + */ + readonly secretsManagerTimeout?: Duration; + + /** + * The time-to-live of a secret in the cache. A value of 0 means there is no caching. + * The maximum time-to-live is 300 seconds. + * + * Note: This variable is ignored if cacheSize is 0. + * + * @default 300 seconds + */ + readonly secretsManagerTtl?: Duration; + + /** + * The timeout for requests to Parameter Store. A value of 0 means that there is no + * timeout. + * + * @default 0 + */ + readonly parameterStoreTimeout?: Duration; + + /** + * The time-to-live of a parameter in the cache. A value of 0 means there is no caching. + * The maximum time-to-live is 300 seconds. + * + * Note: This variable is ignored if cacheSize is 0. + * + * @default 300 seconds + */ + readonly parameterStoreTtl?: Duration; +} + +/** + * Parameters and Secrets Extension configuration + */ +export interface ParamsAndSecretsConfig { + /** + * The Parameters and Secrets Extension layer + */ + readonly layerVersion: ParamsAndSecretsLayerVersion; + + /** + * The secrets to grant lambda access to + * + * @default - No secrets + */ + readonly secrets?: ISecret[]; + + /** + * The parameters to grant lambda access to + * + * @default - No parameters + */ + readonly parameters?: IParameter[]; +} + +/** + * Parameters and Secrets Extension layer version + */ +export abstract class ParamsAndSecretsLayerVersion { + /** + * Use the Parameters and Secrets Extension associated with the provided ARN. Make sure the ARN is associated + * with the same region and architecture as your function. + * + * @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html#retrieving-secrets_lambda_ARNs + */ + public static fromVersionArn(arn: string, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { + return new (class extends ParamsAndSecretsLayerVersion { + public _bind(_scope: Construct, _fn: lambda.IFunction): ParamsAndSecretsBindConfig { + return { + arn, + environmentVars: this.environmentVariablesFromOptions, + }; + } + })(options); + } + + /** + * Use a specific version of the Parameters and Secrets Extension to generate a layer version. + */ + public static fromVersion(version: ParamsAndSecretsVersions, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { + return new (class extends ParamsAndSecretsLayerVersion { + public _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig { + return { + arn: this.getVersionArn(scope, version, fn.architecture.name), + environmentVars: this.environmentVariablesFromOptions, + }; + } + })(options); + } + + private constructor(private readonly options: ParamsAndSecretsOptions) {} + + /** + * Returns the ARN of the Parameters and Secrets Extension + * + * @internal + */ + public abstract _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig; + + /** + * Configure environment variables for Parameters and Secrets Extension based on configuration options + */ + private get environmentVariablesFromOptions(): { [key: string]: any } { + if (this.options.cacheSize !== undefined && (this.options.cacheSize < 0 || this.options.cacheSize > 1000)) { + throw new Error(`Cache size must be between 0 and 1000 inclusive - provided: ${this.options.cacheSize}`); + } + + if (this.options.httpPort !== undefined && (this.options.httpPort < 1 || this.options.httpPort > 65535)) { + throw new Error(`HTTP port must be between 1 and 65535 inclusive - provided: ${this.options.httpPort}`); + } + + // max connections has no maximum limit + if (this.options.maxConnections !== undefined && this.options.maxConnections < 1) { + throw new Error(`Maximum connections must be at least 1 - provided: ${this.options.maxConnections}`); + } + + if (this.options.secretsManagerTtl !== undefined && this.options.secretsManagerTtl.toSeconds() > 300) { + throw new Error(`Maximum TTL for a cached secret is 300 seconds - provided: ${this.options.secretsManagerTtl.toSeconds()} seconds`); + } + + if (this.options.parameterStoreTtl !== undefined && this.options.parameterStoreTtl.toSeconds() > 300) { + throw new Error(`Maximum TTL for a cached parameter is 300 seconds - provided: ${this.options.parameterStoreTtl.toSeconds()} seconds`); + } + + return { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: this.options.cacheEnabled ?? true, + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: this.options.cacheSize ?? 1000, + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: this.options.httpPort ?? 2773, + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: this.options.logLevel ?? ParamsAndSecretsLogLevel.INFO, + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: this.options.maxConnections ?? 3, + SECRETS_MANAGER_TIMEOUT_MILLIS: this.options.secretsManagerTimeout?.toMilliseconds() ?? 0, + SECRETS_MANAGER_TTL: this.options.secretsManagerTtl?.toSeconds() ?? 300, + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: this.options.parameterStoreTimeout?.toMilliseconds() ?? 0, + SSM_PARAMETER_STORE_TTL: this.options.parameterStoreTtl?.toSeconds() ?? 300, + }; + } + + /** + * Retrieve the correct Parameters and Secrets Extension Lambda ARN from RegionInfo, + * or create a mapping to look it up at stack deployment time. + * + * This function is run on CDK synthesis. + */ + private getVersionArn(scope: IConstruct, version: string, architecture: string): string { + const stack = Stack.of(scope); + const region = stack.region; + + // region is resolved - look it up directly from table + if (region !== undefined && !Token.isUnresolved(region)) { + const layerArn = RegionInfo.get(region).paramsAndSecretsLambdaLayerArn(version, architecture); + if (layerArn === undefined) { + throw new Error(`Parameters and Secrets Extension is not supported in region ${region} for ${architecture} architecture`); + } + return layerArn; + } + + // region is unresolved - create mapping and look up during deployment + return stack.regionalFact(FactName.paramsAndSecretsLambdaLayer(version, architecture)); + } +} diff --git a/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts b/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts new file mode 100644 index 0000000000000..a1980e613216c --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts @@ -0,0 +1,1095 @@ +import { Template, Match } from '../../assertions'; +import * as kms from '../../aws-kms'; +import * as sm from '../../aws-secretsmanager'; +import * as ssm from '../../aws-ssm'; +import * as cdk from '../../core'; +import * as lambda from '../lib'; + +describe('params and secrets', () => { + test('can provide arn to enable params and secrets with default config options', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can provide an arn to enable params and secrets with non-default config options', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheEnabled: false, + cacheSize: 500, + httpPort: 8080, + logLevel: lambda.ParamsAndSecretsLogLevel.DEBUG, + maxConnections: 1, + secretsManagerTimeout: cdk.Duration.seconds(10), + secretsManagerTtl: cdk.Duration.seconds(250), + parameterStoreTimeout: cdk.Duration.seconds(10), + parameterStoreTtl: cdk.Duration.seconds(250), + }), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'false', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '500', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '8080', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'debug', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '1', + SECRETS_MANAGER_TIMEOUT_MILLIS: '10000', + SECRETS_MANAGER_TTL: '250', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '10000', + SSM_PARAMETER_STORE_TTL: '250', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets from version in non-agnostic stack - x86_64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: ['arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets from version in agnostic stack - x86_64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [ + { + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + '1x0x103xx86x64', + ], + }, + ], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enbale params and secrets from version in non-agnostic stack - arm64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + architecture: lambda.Architecture.ARM_64, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: ['arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4'], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets from version in non-agnostic stack - arm64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + architecture: lambda.Architecture.ARM_64, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [ + { + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + '1x0x103xarm64', + ], + }, + ], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets from version with non-default config options', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103, { + cacheEnabled: false, + cacheSize: 500, + httpPort: 8080, + logLevel: lambda.ParamsAndSecretsLogLevel.DEBUG, + maxConnections: 1, + secretsManagerTimeout: cdk.Duration.seconds(10), + secretsManagerTtl: cdk.Duration.seconds(250), + parameterStoreTimeout: cdk.Duration.seconds(10), + parameterStoreTtl: cdk.Duration.seconds(250), + }), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: ['arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'false', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '500', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '8080', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'debug', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '1', + SECRETS_MANAGER_TIMEOUT_MILLIS: '10000', + SECRETS_MANAGER_TTL: '250', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '10000', + SSM_PARAMETER_STORE_TTL: '250', + }, + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + // x86_64 is supported in all regions - we're just checking for arm64 + test('throws for unsupported architecture in region', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { region: 'eu-central-2' } }); + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + architecture: lambda.Architecture.ARM_64, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), + }, + }); + }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); + }); + + test('can enable params and secrets with a provided secret', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const secret = new sm.Secret(stack, 'Secret'); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), + secrets: [secret], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + ManagedPolicyArns: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::aws:policy/service-role/AWSLambdaBasicExecutionRole', + ], + ], + }, + ], + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'secretsmanager:GetSecretValue', + 'secretsmanager:DescribeSecret', + ], + Effect: 'Allow', + Resource: { + Ref: 'SecretA720EF05', + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets with a provided secret with encryption key', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const encryptionKey = new kms.Key(stack, 'Key'); + const secret = new sm.Secret(stack, 'Secret', { encryptionKey }); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), + secrets: [secret], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'secretsmanager:GetSecretValue', + 'secretsmanager:DescribeSecret', + ], + Effect: 'Allow', + Resource: { + Ref: 'SecretA720EF05', + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { + KeyPolicy: { + Statement: Match.arrayWith([ + { + Action: 'kms:*', + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Resource: '*', + }, + { + Action: [ + 'kms:Decrypt', + 'kms:Encrypt', + 'kms:ReEncrypt*', + 'kms:GenerateDataKey*', + ], + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Resource: '*', + }, + { + Action: [ + 'kms:CreateGrant', + 'kms:DescribeKey', + ], + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Resource: '*', + }, + { + Action: 'kms:Decrypt', + Condition: { + StringEquals: { + 'kms:ViaService': { + 'Fn::Join': [ + '', + [ + 'secretsmanager.', + { + Ref: 'AWS::Region', + }, + '.amazonaws.com', + ], + ], + }, + }, + }, + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::GetAtt': [ + 'FunctionServiceRole675BB04A', + 'Arn', + ], + }, + }, + Resource: '*', + }, + ]), + }, + }); + }); + + test('can enable params and secrets with a provided parameter', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const parameter = new ssm.StringParameter(stack, 'Parameter', { + parameterName: 'name', + stringValue: 'value', + }); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), + parameters: [parameter], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'ssm:DescribeParameters', + 'ssm:GetParameters', + 'ssm:GetParameter', + 'ssm:GetParameterHistory', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/', + { + Ref: 'Parameter9E1B4FBA', + }, + ], + ], + }, + }, + ], + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets with a provided parameter with encryption', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const key = new kms.Key(stack, 'Key'); + // note: parameters of type SecureString cannot be created directly from a CDK application + const parameter = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'Parameter', { + parameterName: 'name', + encryptionKey: key, + }); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), + parameters: [parameter], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'true', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '1000', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '2773', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'info', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '3', + SECRETS_MANAGER_TIMEOUT_MILLIS: '0', + SECRETS_MANAGER_TTL: '300', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '0', + SSM_PARAMETER_STORE_TTL: '300', + }, + }, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }, + { + Action: [ + 'ssm:DescribeParameters', + 'ssm:GetParameters', + 'ssm:GetParameter', + 'ssm:GetParameterHistory', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/name', + ], + ], + }, + }, + ], + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { + KeyPolicy: { + Statement: [ + { + Action: 'kms:*', + Effect: 'Allow', + Principal: { + AWS: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':iam::', + { + Ref: 'AWS::AccountId', + }, + ':root', + ], + ], + }, + }, + Resource: '*', + }, + ], + }, + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets with multiple secrets and parameters', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const secret1 = new sm.Secret(stack, 'Secret1'); + const secret2 = new sm.Secret(stack, 'Secret2'); + const parameter1 = new ssm.StringParameter(stack, 'Parameter1', { + parameterName: 'name', + stringValue: 'value', + }); + const parameter2 = new ssm.StringParameter(stack, 'Parameter2', { + parameterName: 'name', + stringValue: 'value', + }); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), + secrets: [secret1, secret2], + parameters: [parameter1, parameter2], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 'secretsmanager:GetSecretValue', + 'secretsmanager:DescribeSecret', + ], + Effect: 'Allow', + Resource: { + Ref: 'Secret1C2786A59', + }, + }, + { + Action: [ + 'secretsmanager:GetSecretValue', + 'secretsmanager:DescribeSecret', + ], + Effect: 'Allow', + Resource: { + Ref: 'Secret244EA3BB5', + }, + }, + { + Action: [ + 'ssm:DescribeParameters', + 'ssm:GetParameters', + 'ssm:GetParameter', + 'ssm:GetParameterHistory', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/', + { + Ref: 'Parameter184B7AC48', + }, + ], + ], + }, + }, + { + Action: [ + 'ssm:DescribeParameters', + 'ssm:GetParameters', + 'ssm:GetParameter', + 'ssm:GetParameterHistory', + ], + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ssm:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':parameter/', + { + Ref: 'Parameter28A824271', + }, + ], + ], + }, + }, + ], + }, + }); + }); + + test('throws for cacheSize < 0', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheSize: -1, + }), + }, + }); + }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: -1'); + }); + + test('throws for cacheSize > 1000', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheSize: 1001, + }), + }, + }); + }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: 1001'); + }); + + test('throws for httpPort < 1', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + httpPort: 0, + }), + }, + }); + }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 0'); + }); + + test('throws for httpPort > 65535', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + httpPort: 65536, + }), + }, + }); + }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 65536'); + }); + + test('throws for maxConnections < 1', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + maxConnections: 0, + }), + }, + }); + }).toThrow('Maximum connections must be at least 1 - provided: 0'); + }); + + test('throws for secretsManagerTtl > 300 seconds', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + secretsManagerTtl: cdk.Duration.seconds(301), + }), + }, + }); + }).toThrow('Maximum TTL for a cached secret is 300 seconds - provided: 301 seconds'); + }); + + test('throws for parameterStoreTtl > 300 seconds', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', {}); + const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; + + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + parameterStoreTtl: cdk.Duration.seconds(301), + }), + }, + }); + }).toThrow('Maximum TTL for a cached parameter is 300 seconds - provided: 301 seconds'); + }); +}); diff --git a/packages/aws-cdk-lib/region-info/build-tools/fact-tables.ts b/packages/aws-cdk-lib/region-info/build-tools/fact-tables.ts index d24f2ce31e97f..1ccfb993636ab 100644 --- a/packages/aws-cdk-lib/region-info/build-tools/fact-tables.ts +++ b/packages/aws-cdk-lib/region-info/build-tools/fact-tables.ts @@ -547,6 +547,67 @@ export const FIREHOSE_CIDR_BLOCKS: { [region: string]: string } = { 'us-west-2': '52.89.255.224', }; +// https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html#retrieving-secrets_lambda_ARNs +export const PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS: { [version: string]: { [arch: string]: { [region: string]: string } } } = { + '1.0.103': { + x86_64: { + 'us-east-1': 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'us-east-2': 'arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'us-west-1': 'arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'us-west-2': 'arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ca-central-1': 'arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-central-1': 'arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-central-2': 'arn:aws:lambda:eu-central-2:772501565639:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1', + 'eu-west-1': 'arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-west-2': 'arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-west-3': 'arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-north-1': 'arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-south-1': 'arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'eu-south-2': 'arn:aws:lambda:eu-south-2:524103009944:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1', + 'cn-north-1': 'arn:aws-cn:lambda:cn-north-1:287114880934:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'cn-northwest-1': 'arn:aws-cn:lambda:cn-northwest-1:287310001119:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-east-1': 'arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-south-2': 'arn:aws:lambda:ap-south-2:070087711984:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1', + 'ap-northeast-1': 'arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-northeast-2': 'arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-northeast-3': 'arn:aws:lambda:ap-northeast-3:576959938190:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-southeast-1': 'arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-southeast-2': 'arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-southeast-3': 'arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'ap-south-1': 'arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'sa-east-1': 'arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'af-south-1': 'arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'me-central-1': 'arn:aws:lambda:me-central-1:858974508948:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'me-south-1': 'arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'us-gov-east-1': 'arn:aws-us-gov:lambda:us-gov-east-1:129776340158:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + 'us-gov-west-1': 'arn:aws-us-gov:lambda:us-gov-west-1:127562683043:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4', + }, + arm64: { + 'us-east-1': 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'us-east-2': 'arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'us-west-1': 'arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'us-west-2': 'arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'ca-central-1': 'arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'eu-central-1': 'arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'eu-west-1': 'arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'eu-west-2': 'arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'eu-west-3': 'arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'eu-north-1': 'arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'eu-south-1': 'arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'ap-east-1': 'arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'ap-northeast-1': 'arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'ap-northeast-2': 'arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'ap-southeast-1': 'arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'ap-southeast-2': 'arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'ap-southeast-3': 'arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'ap-south-1': 'arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4', + 'sa-east-1': 'arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'af-south-1': 'arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + 'me-south-1': 'arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1', + }, + }, +}; + const ADOT_LAMBDA_LAYER_JAVA_SDK_ARNS: { [version: string]: { [arch: string]: { [region: string]: string } } } = { '1.24.0': { x86_64: { diff --git a/packages/aws-cdk-lib/region-info/build-tools/generate-static-data.ts b/packages/aws-cdk-lib/region-info/build-tools/generate-static-data.ts index 50219a61cb392..0313246c43a15 100644 --- a/packages/aws-cdk-lib/region-info/build-tools/generate-static-data.ts +++ b/packages/aws-cdk-lib/region-info/build-tools/generate-static-data.ts @@ -12,6 +12,7 @@ import { EBS_ENV_ENDPOINT_HOSTED_ZONE_IDS, ADOT_LAMBDA_LAYER_ARNS, CR_DEFAULT_RUNTIME_MAP, + PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS, } from './fact-tables'; import { AWS_REGIONS, @@ -114,6 +115,12 @@ export async function main(): Promise { } } } + + for (const version in PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS) { + for (const arch in PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS[version]) { + registerFact(region, ['paramsAndSecretsLambdaLayer', version, arch], PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS[version][arch][region]); + } + } } lines.push(' }'); lines.push(''); diff --git a/packages/aws-cdk-lib/region-info/lib/fact.ts b/packages/aws-cdk-lib/region-info/lib/fact.ts index 320e747688de8..7ccc6df1c84b5 100644 --- a/packages/aws-cdk-lib/region-info/lib/fact.ts +++ b/packages/aws-cdk-lib/region-info/lib/fact.ts @@ -208,4 +208,15 @@ export class FactName { const suffix = type + '_' + version.split('.').join('_') + '_' + architecture; return `adot-lambda-layer:${suffix}`; } + + /** + * The ARN of Parameters and Secrets Lambda layer for a given lambda architecture. + * + * @param version the layer version + * @param architecture the Lambda Function architecture (e.g. 'x86_64' or 'arm64') + */ + public static paramsAndSecretsLambdaLayer(version: string, architecture: string): string { + const suffix = version.split('.').join('_') + `_${architecture}`; + return `params-and-secrets-layer:${suffix}`; + } } diff --git a/packages/aws-cdk-lib/region-info/lib/region-info.ts b/packages/aws-cdk-lib/region-info/lib/region-info.ts index 099218434c2c7..9d974d69a15c5 100644 --- a/packages/aws-cdk-lib/region-info/lib/region-info.ts +++ b/packages/aws-cdk-lib/region-info/lib/region-info.ts @@ -178,4 +178,14 @@ export class RegionInfo { public adotLambdaLayerArn(type: string, version: string, architecture: string): string | undefined { return Fact.find(this.name, FactName.adotLambdaLayer(type, version, architecture)); } + + /** + * The ARN of the Parameters and Secrets Lambda layer for the given lambda architecture. + * + * @param version the layer version + * @param architecture the Lambda Function architecture (e.g. 'x86_64' or 'arm64') + */ + public paramsAndSecretsLambdaLayerArn(version: string, architecture: string): string | undefined { + return Fact.find(this.name, FactName.paramsAndSecretsLambdaLayer(version, architecture)); + } }