From ab0770ac709012613c2b803bcb0b745a7dcd0a31 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 19 May 2023 15:13:01 -0700 Subject: [PATCH 01/49] added interface for params and secrets extension configuration options and added an enum for params and secrets logging level Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index d8f3ee4cc245d..d7e717b78f1ca 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -28,6 +28,7 @@ import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; import { Annotations, ArnFormat, CfnResource, Duration, FeatureFlags, Fn, IAspect, Lazy, Names, Size, Stack, Token } from '../../core'; import { LAMBDA_RECOGNIZE_LAYER_VERSION } from '../../cx-api'; +import { env } from 'node:process'; /** * X-Ray Tracing Modes (https://docs.aws.amazon.com/lambda/latest/dg/API_TracingConfig.html) @@ -49,6 +50,115 @@ export enum Tracing { DISABLED = 'Disabled' } +/** + * Logging levels for Parameters and Secrets Extension + */ +export enum ParametersAndSecretsLogLevel { + /** + * Debug logging level + */ + DEBUG = 'debug', + + /** + * Info logging level + */ + INFO = 'info', + + /** + * Warn logging level + */ + WARN = 'warn', + + /** + * Error logging level + */ + ERROR = 'error', + + /** + * No logging level + */ + NONE = 'none', +} + +export interface ParametersAndSecretsConfig { + /** + * Enables Parameters and Secrets Extension to cache parameters and secrets + * + * @default true + */ + paramsAndSecretsExtensionCacheEnabled?: 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 both parameterStoreTtl and secretsManagerTtl + * are 0. + * + * @default 1000 + */ + paramsAndSecretsExtensionCacheSize?: number; + + /** + * The port for the local HTTP server. + * + * @default 2773 + */ + paramsAndSecretsExtensionHttpPort?: number; + + /** + * The level of logging for the Parameters and Secrets Extension to provide. + * + * @default + */ + paramsAndSecretsExtensionLogLevel?: ParametersAndSecretsLogLevel, + + /** + * The maximum number of connections for HTTP clients that the Parameters and Secrets + * Extension uses to make request to Parameter Store or Secrets Manager. This is a + * per-client configuration. + * + * @default 3 + */ + paramsAndSecretsExtensionMaxConnections?: number; + + /** + * Timeout for requests to Secrets Manager in milliseconds. A value of 0 means there is no + * timeout. + * + * @default 0 + */ + secretsManagertimeout?: Duration; + + /** + * The time to live of a secret in the cache in seconds. A value of 0 means there is no + * caching. The maximum is 300 seconds. + * + * Note: This variable is ignored if parametersCacheSize is 0. + * + * @default 300 + */ + secretsManagerTtl?: Duration; + + /** + * Timeout for requests to Parameter Store in milliseconds. A value of 0 means there is no + * timeout. + * + * @default 0 + */ + parameterStoreTimeout?: Duration; + + /** + * The time to live of a parameter in the cache in seconds. A value of 0 means there is no + * caching. The maximum is 300 seconds. + * + * Note: This variable is ignored if paramsAndSecretsCacheSize is 0. + * + * @default 300 + */ + parameterStoreTtl?: Duration; +} + /** * Non runtime options */ @@ -1066,6 +1176,10 @@ export class Function extends FunctionBase { return addAlias(this, this.currentVersion, aliasName, options); } + public attachParametersAndSecretsExtension(config: ParametersAndSecretsConfig = {}): void { + + } + /** * The LogGroup where the Lambda function's logs are made available. * From dc5a38f7dc206aa1719b6a3db60ee87fcf8125e4 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 19 May 2023 15:57:08 -0700 Subject: [PATCH 02/49] created initial getter for params and secrets extension lambda arn Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index d7e717b78f1ca..30d37d4c9d23d 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -28,7 +28,6 @@ import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; import { Annotations, ArnFormat, CfnResource, Duration, FeatureFlags, Fn, IAspect, Lazy, Names, Size, Stack, Token } from '../../core'; import { LAMBDA_RECOGNIZE_LAYER_VERSION } from '../../cx-api'; -import { env } from 'node:process'; /** * X-Ray Tracing Modes (https://docs.aws.amazon.com/lambda/latest/dg/API_TracingConfig.html) @@ -1201,6 +1200,69 @@ export class Function extends FunctionBase { return this._logGroup; } + public get paramsAndSecretsExtensionLambdaArn(): string { + // TODO: Where does this need to go? + const paramsAndSecretsExtensionLambdaArns: { [key: string]: any } = { + x86_64: { + 'us-east-1': '', + 'us-east-2': '', + 'us-west-1': '', + 'us-west-2': '', + 'ca-central-1': '', + 'eu-central-1': '', + 'eu-central-2': '', + 'eu-west-1': '', + 'eu-west-2': '', + 'eu-west-3': '', + 'eu-north-1': '', + 'eu-south-1': '', + 'eu-south-2': '', + 'cn-north-1': '', + 'cn-northwest-1': '', + 'ap-east-1': '', + 'ap-south-2': '', + 'ap-northeast-1': '', + 'ap-northeast-2': '', + 'ap-northeast-3': '', + 'ap-southeast-1': '', + 'ap-southeast-2': '', + 'ap-southeast-3': '', + 'ap-south-1': '', + 'sa-east-1': '', + 'af-south-1': '', + 'me-central-1': '', + 'me-south-1': '', + 'us-gov-east-1': '', + 'us-gov-west-1': '', + }, + arm64: { + 'us-east-1': '', + 'us-east-2': '', + 'us-west-1': '', + 'us-west-2': '', + 'ca-central-1': '', + 'eu-central-1': '', + 'eu-west-1': '', + 'eu-west-2': '', + 'eu-west-3': '', + 'eu-north-1': '', + 'eu-south-1': '', + 'ap-east-1': '', + 'ap-northeast-1': '', + 'ap-northeast-2': '', + 'ap-southeast-1': '', + 'ap-southeast-2': '', + 'ap-southeast-3': '', + 'ap-south-1': '', + 'sa-east-1': '', + 'af-south-1': '', + 'me-south-1': '', + }, + }; + // TODO: Is this the right way to get the region? + return paramsAndSecretsExtensionLambdaArns[this.architecture.name][Stack.of(this).region]; + } + /** @internal */ public _checkEdgeCompatibility(): void { // Check env vars From 36d4bb826b79e33e2865d5b506aa39ba33bbc41a Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 19 May 2023 16:38:37 -0700 Subject: [PATCH 03/49] added some initial logic to create params and secrets layer and to add environment variables based on config Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 30d37d4c9d23d..47938bbd8b687 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -1176,7 +1176,27 @@ export class Function extends FunctionBase { } public attachParametersAndSecretsExtension(config: ParametersAndSecretsConfig = {}): void { - + const paramsAndSecretsLayer = LayerVersion.fromLayerVersionArn( + this.stack, + 'ParamsAndSecretsExtensionLayer', + this.paramsAndSecretsExtensionLambdaArn, + ); + this.addLayers(paramsAndSecretsLayer); + + // TODO: Do I need to handle the ignored variables or will they be ignored automatically? + // TODO: Is there a better way to structure this? + const environmentVariables: { [key: string]: any } = { + PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED: config.paramsAndSecretsExtensionCacheEnabled ?? true, + PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE: config.paramsAndSecretsExtensionCacheSize ?? 1000, + PARAMETERS_SECRETS_EXTENSION_HTTP_PORT: config.paramsAndSecretsExtensionHttpPort ?? 2773, + PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL: config.paramsAndSecretsExtensionLogLevel ?? ParametersAndSecretsLogLevel.INFO, + PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS: config.paramsAndSecretsExtensionMaxConnections ?? 3, + SECRETS_MANAGER_TIMEOUT_MILLIS: config.secretsManagertimeout ?? 0, + SECRETS_MANAGER_TTL: config.secretsManagerTtl ?? Duration.seconds(300), + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: config.parameterStoreTimeout ?? 0, + SSN_PARAMETER_STORE_TTL: config.parameterStoreTtl ?? Duration.seconds(300), + }; + Object.entries(environmentVariables).forEach(([key, value]) => this.addEnvironment(key, value)); } /** @@ -1260,7 +1280,7 @@ export class Function extends FunctionBase { }, }; // TODO: Is this the right way to get the region? - return paramsAndSecretsExtensionLambdaArns[this.architecture.name][Stack.of(this).region]; + return paramsAndSecretsExtensionLambdaArns[this.architecture.name][this.stack.region]; } /** @internal */ From 93553ff5d216c1a5fe0bd803bcb465121924cb62 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 19 May 2023 16:54:05 -0700 Subject: [PATCH 04/49] moved params and secrets extension lambda arn table to region-build directory Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 62 +------------------ 1 file changed, 2 insertions(+), 60 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 47938bbd8b687..e58fa10e178ed 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -18,6 +18,7 @@ import { LogRetentionRetryOptions } from './log-retention'; import { Runtime } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; import { addAlias } from './util'; +import { PARAMS_AND_SECRETS_EXTENSION_LAMBDA_ARNS } from '../../../@aws-cdk/region-info/build-tools/fact-tables'; import * as cloudwatch from '../../aws-cloudwatch'; import { IProfilingGroup, ProfilingGroup, ComputePlatform } from '../../aws-codeguruprofiler'; import * as ec2 from '../../aws-ec2'; @@ -1221,66 +1222,7 @@ export class Function extends FunctionBase { } public get paramsAndSecretsExtensionLambdaArn(): string { - // TODO: Where does this need to go? - const paramsAndSecretsExtensionLambdaArns: { [key: string]: any } = { - x86_64: { - 'us-east-1': '', - 'us-east-2': '', - 'us-west-1': '', - 'us-west-2': '', - 'ca-central-1': '', - 'eu-central-1': '', - 'eu-central-2': '', - 'eu-west-1': '', - 'eu-west-2': '', - 'eu-west-3': '', - 'eu-north-1': '', - 'eu-south-1': '', - 'eu-south-2': '', - 'cn-north-1': '', - 'cn-northwest-1': '', - 'ap-east-1': '', - 'ap-south-2': '', - 'ap-northeast-1': '', - 'ap-northeast-2': '', - 'ap-northeast-3': '', - 'ap-southeast-1': '', - 'ap-southeast-2': '', - 'ap-southeast-3': '', - 'ap-south-1': '', - 'sa-east-1': '', - 'af-south-1': '', - 'me-central-1': '', - 'me-south-1': '', - 'us-gov-east-1': '', - 'us-gov-west-1': '', - }, - arm64: { - 'us-east-1': '', - 'us-east-2': '', - 'us-west-1': '', - 'us-west-2': '', - 'ca-central-1': '', - 'eu-central-1': '', - 'eu-west-1': '', - 'eu-west-2': '', - 'eu-west-3': '', - 'eu-north-1': '', - 'eu-south-1': '', - 'ap-east-1': '', - 'ap-northeast-1': '', - 'ap-northeast-2': '', - 'ap-southeast-1': '', - 'ap-southeast-2': '', - 'ap-southeast-3': '', - 'ap-south-1': '', - 'sa-east-1': '', - 'af-south-1': '', - 'me-south-1': '', - }, - }; - // TODO: Is this the right way to get the region? - return paramsAndSecretsExtensionLambdaArns[this.architecture.name][this.stack.region]; + return PARAMS_AND_SECRETS_EXTENSION_LAMBDA_ARNS[this.architecture.name][this.stack.region]; } /** @internal */ From bba4e63a2c863c484ec4305f3db901bb6bbfc2a9 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 19 May 2023 23:48:23 -0700 Subject: [PATCH 05/49] added readonly keyword to ParametersAndSecretsExtensionConfig interface and added permissions to attachParametersAndSecretsExtension method Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index e58fa10e178ed..1ef27e140548b 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -25,6 +25,7 @@ import * as ec2 from '../../aws-ec2'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; +import * as sm from '../../aws-secretsmanager'; import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; import { Annotations, ArnFormat, CfnResource, Duration, FeatureFlags, Fn, IAspect, Lazy, Names, Size, Stack, Token } from '../../core'; @@ -86,7 +87,7 @@ export interface ParametersAndSecretsConfig { * * @default true */ - paramsAndSecretsExtensionCacheEnabled?: boolean; + readonly paramsAndSecretsExtensionCacheEnabled?: boolean; /** * The maximum number of secrets and parameters to cache. Must be a value from 0 @@ -97,21 +98,21 @@ export interface ParametersAndSecretsConfig { * * @default 1000 */ - paramsAndSecretsExtensionCacheSize?: number; + readonly paramsAndSecretsExtensionCacheSize?: number; /** * The port for the local HTTP server. * * @default 2773 */ - paramsAndSecretsExtensionHttpPort?: number; + readonly paramsAndSecretsExtensionHttpPort?: number; /** * The level of logging for the Parameters and Secrets Extension to provide. * * @default */ - paramsAndSecretsExtensionLogLevel?: ParametersAndSecretsLogLevel, + readonly paramsAndSecretsExtensionLogLevel?: ParametersAndSecretsLogLevel, /** * The maximum number of connections for HTTP clients that the Parameters and Secrets @@ -120,7 +121,7 @@ export interface ParametersAndSecretsConfig { * * @default 3 */ - paramsAndSecretsExtensionMaxConnections?: number; + readonly paramsAndSecretsExtensionMaxConnections?: number; /** * Timeout for requests to Secrets Manager in milliseconds. A value of 0 means there is no @@ -128,7 +129,7 @@ export interface ParametersAndSecretsConfig { * * @default 0 */ - secretsManagertimeout?: Duration; + readonly secretsManagertimeout?: Duration; /** * The time to live of a secret in the cache in seconds. A value of 0 means there is no @@ -138,7 +139,7 @@ export interface ParametersAndSecretsConfig { * * @default 300 */ - secretsManagerTtl?: Duration; + readonly secretsManagerTtl?: Duration; /** * Timeout for requests to Parameter Store in milliseconds. A value of 0 means there is no @@ -146,7 +147,7 @@ export interface ParametersAndSecretsConfig { * * @default 0 */ - parameterStoreTimeout?: Duration; + readonly parameterStoreTimeout?: Duration; /** * The time to live of a parameter in the cache in seconds. A value of 0 means there is no @@ -156,7 +157,7 @@ export interface ParametersAndSecretsConfig { * * @default 300 */ - parameterStoreTtl?: Duration; + readonly parameterStoreTtl?: Duration; } /** @@ -1176,7 +1177,7 @@ export class Function extends FunctionBase { return addAlias(this, this.currentVersion, aliasName, options); } - public attachParametersAndSecretsExtension(config: ParametersAndSecretsConfig = {}): void { + public attachParametersAndSecretsExtension(secret: sm.ISecret, config: ParametersAndSecretsConfig = {}): void { const paramsAndSecretsLayer = LayerVersion.fromLayerVersionArn( this.stack, 'ParamsAndSecretsExtensionLayer', @@ -1184,20 +1185,27 @@ export class Function extends FunctionBase { ); this.addLayers(paramsAndSecretsLayer); - // TODO: Do I need to handle the ignored variables or will they be ignored automatically? - // TODO: Is there a better way to structure this? + this.addToRolePolicy(new iam.PolicyStatement({ + actions: ['secretsmanager:GetSecret'], + resources: [secret.secretArn], + })); + + if (secret.encryptionKey) { + secret.encryptionKey.grantDecrypt(this); + } + const environmentVariables: { [key: string]: any } = { PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED: config.paramsAndSecretsExtensionCacheEnabled ?? true, PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE: config.paramsAndSecretsExtensionCacheSize ?? 1000, PARAMETERS_SECRETS_EXTENSION_HTTP_PORT: config.paramsAndSecretsExtensionHttpPort ?? 2773, PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL: config.paramsAndSecretsExtensionLogLevel ?? ParametersAndSecretsLogLevel.INFO, PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS: config.paramsAndSecretsExtensionMaxConnections ?? 3, - SECRETS_MANAGER_TIMEOUT_MILLIS: config.secretsManagertimeout ?? 0, - SECRETS_MANAGER_TTL: config.secretsManagerTtl ?? Duration.seconds(300), - SSM_PARAMETER_STORE_TIMEOUT_MILLIS: config.parameterStoreTimeout ?? 0, - SSN_PARAMETER_STORE_TTL: config.parameterStoreTtl ?? Duration.seconds(300), + SECRETS_MANAGER_TIMEOUT_MILLIS: config.secretsManagertimeout?.toMilliseconds() ?? 0, + SECRETS_MANAGER_TTL: config.secretsManagerTtl?.toSeconds() ?? 300, + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: config.parameterStoreTimeout?.toMilliseconds() ?? 0, + SSN_PARAMETER_STORE_TTL: config.parameterStoreTtl?.toSeconds() ?? 300, }; - Object.entries(environmentVariables).forEach(([key, value]) => this.addEnvironment(key, value)); + Object.entries(environmentVariables).forEach(([key, value]) => this.addEnvironment(key, value.toString())); } /** @@ -1222,6 +1230,9 @@ export class Function extends FunctionBase { } public get paramsAndSecretsExtensionLambdaArn(): string { + if (Token.isUnresolved(this.stack.region)) { + throw new Error('Unable to retrieve lambda arn for parameters and secrets extension'); + } return PARAMS_AND_SECRETS_EXTENSION_LAMBDA_ARNS[this.architecture.name][this.stack.region]; } From a721460c7872bf663c0c2979bce834af90c8ec24 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 13:54:47 -0700 Subject: [PATCH 06/49] refactored code and added a params-and-secrets-layers file - separation of concerns Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 139 +++--------------- .../lib/params-and-secrets-layers.ts | 122 +++++++++++++++ .../aws-lambda/test/function.test.ts | 16 ++ 3 files changed, 161 insertions(+), 116 deletions(-) create mode 100644 packages/aws-cdk-lib/aws-lambda/lib/params-and-secrets-layers.ts diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 1ef27e140548b..0333f6ffbe04d 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, ParamsAndSecretsLayer, ParamsAndSecretsLogLevels } from './params-and-secrets-layers'; import { Runtime } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; import { addAlias } from './util'; @@ -51,115 +52,6 @@ export enum Tracing { DISABLED = 'Disabled' } -/** - * Logging levels for Parameters and Secrets Extension - */ -export enum ParametersAndSecretsLogLevel { - /** - * Debug logging level - */ - DEBUG = 'debug', - - /** - * Info logging level - */ - INFO = 'info', - - /** - * Warn logging level - */ - WARN = 'warn', - - /** - * Error logging level - */ - ERROR = 'error', - - /** - * No logging level - */ - NONE = 'none', -} - -export interface ParametersAndSecretsConfig { - /** - * Enables Parameters and Secrets Extension to cache parameters and secrets - * - * @default true - */ - readonly paramsAndSecretsExtensionCacheEnabled?: 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 both parameterStoreTtl and secretsManagerTtl - * are 0. - * - * @default 1000 - */ - readonly paramsAndSecretsExtensionCacheSize?: number; - - /** - * The port for the local HTTP server. - * - * @default 2773 - */ - readonly paramsAndSecretsExtensionHttpPort?: number; - - /** - * The level of logging for the Parameters and Secrets Extension to provide. - * - * @default - */ - readonly paramsAndSecretsExtensionLogLevel?: ParametersAndSecretsLogLevel, - - /** - * The maximum number of connections for HTTP clients that the Parameters and Secrets - * Extension uses to make request to Parameter Store or Secrets Manager. This is a - * per-client configuration. - * - * @default 3 - */ - readonly paramsAndSecretsExtensionMaxConnections?: number; - - /** - * Timeout for requests to Secrets Manager in milliseconds. A value of 0 means there is no - * timeout. - * - * @default 0 - */ - readonly secretsManagertimeout?: Duration; - - /** - * The time to live of a secret in the cache in seconds. A value of 0 means there is no - * caching. The maximum is 300 seconds. - * - * Note: This variable is ignored if parametersCacheSize is 0. - * - * @default 300 - */ - readonly secretsManagerTtl?: Duration; - - /** - * Timeout for requests to Parameter Store in milliseconds. A value of 0 means there is no - * timeout. - * - * @default 0 - */ - readonly parameterStoreTimeout?: Duration; - - /** - * The time to live of a parameter in the cache in seconds. A value of 0 means there is no - * caching. The maximum is 300 seconds. - * - * Note: This variable is ignored if paramsAndSecretsCacheSize is 0. - * - * @default 300 - */ - readonly parameterStoreTtl?: Duration; -} - /** * Non runtime options */ @@ -371,6 +263,14 @@ export interface FunctionOptions extends EventInvokeConfigOptions { */ readonly adotInstrumentation?: AdotInstrumentationConfig; + /** + * Specify a Parameters and Secrets Extension layer + * @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html + * + * @default - No Parameters and Secrets Extension layer + */ + readonly paramsAndSecretsLayer?: ParamsAndSecretsLayer; + /** * 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 @@ -1177,7 +1077,7 @@ export class Function extends FunctionBase { return addAlias(this, this.currentVersion, aliasName, options); } - public attachParametersAndSecretsExtension(secret: sm.ISecret, config: ParametersAndSecretsConfig = {}): void { + public attachParametersAndSecretsExtension(secret: sm.ISecret, config: ParamsAndSecretsConfig = {}): void { const paramsAndSecretsLayer = LayerVersion.fromLayerVersionArn( this.stack, 'ParamsAndSecretsExtensionLayer', @@ -1195,12 +1095,12 @@ export class Function extends FunctionBase { } const environmentVariables: { [key: string]: any } = { - PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED: config.paramsAndSecretsExtensionCacheEnabled ?? true, - PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE: config.paramsAndSecretsExtensionCacheSize ?? 1000, - PARAMETERS_SECRETS_EXTENSION_HTTP_PORT: config.paramsAndSecretsExtensionHttpPort ?? 2773, - PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL: config.paramsAndSecretsExtensionLogLevel ?? ParametersAndSecretsLogLevel.INFO, - PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS: config.paramsAndSecretsExtensionMaxConnections ?? 3, - SECRETS_MANAGER_TIMEOUT_MILLIS: config.secretsManagertimeout?.toMilliseconds() ?? 0, + PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED: config.paramsAndSecretsCacheEnabled ?? true, + PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE: config.paramsAndSecretsCacheEnabled ?? 1000, + PARAMETERS_SECRETS_EXTENSION_HTTP_PORT: config.paramsAndSecretsHttpPort ?? 2773, + PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL: config.paramsAndSecretsLogLevel ?? ParamsAndSecretsLogLevels.INFO, + PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS: config.paramsAndSecretsMaxConnections ?? 3, + SECRETS_MANAGER_TIMEOUT_MILLIS: config.secretsManagerTimeout?.toMilliseconds() ?? 0, SECRETS_MANAGER_TTL: config.secretsManagerTtl?.toSeconds() ?? 300, SSM_PARAMETER_STORE_TIMEOUT_MILLIS: config.parameterStoreTimeout?.toMilliseconds() ?? 0, SSN_PARAMETER_STORE_TTL: config.parameterStoreTtl?.toSeconds() ?? 300, @@ -1298,6 +1198,13 @@ 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 { + + } + private renderLayers() { if (!this._layers || this._layers.length === 0) { return undefined; 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..e7a91d30cdc32 --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda/lib/params-and-secrets-layers.ts @@ -0,0 +1,122 @@ +import { Duration } from '../../core'; + +/** + * Logging levels for Parameters and Secrets Extension + */ +export enum ParamsAndSecretsLogLevels { + /** + * Debug + */ + DEBUG = 'debug', + + /** + * Info + */ + INFO = 'info', + + /** + * Warn + */ + WARN = 'warn', + + /** + * Error + */ + ERROR = 'error', + + /** + * No logging + */ + NONE = 'none', +} + +/** + * Configuration options for Parameters and Secrets Extension + */ +export interface ParamsAndSecretsConfig { + /** + * Enables Parameters and Secrets Extension to cache parameters and secrets + * + * @default true + */ + readonly paramsAndSecretsCacheEnabled?: 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 is ignored if both parameterStoreTtl and secretsManagerTtl are 0. + * + * @default 1000 + */ + readonly paramsAndSecretsCacheSize?: number; + + /** + * The port for the local HTTP server. + * + * @default 2773 + */ + readonly paramsAndSecretsHttpPort?: number; + + /** + * The level of logging for the Parameters and Secrets Extension to provide. + * + * @default - no logging + */ + readonly paramsAndSecretsLogLevel?: ParamsAndSecretsLogLevels; + + /** + * The maximum number of connections for HTTP clients that the Parameters and Secrets + * Extension uses to make requests to Parameter Store or Secrets Manager. This is a + * per-client configuration + * + * @default 3 + */ + readonly paramsAndSecretsMaxConnections?: number; + + /** + * Timeout for request to Secrets Manager in milliseconds. A value of 0 means there is + * no timeout. + * + * @default 0 + */ + readonly secretsManagerTimeout?: Duration; + + /** + * The time to live of a secret in the cache in seconds. A value of 0 means there is no + * caching. The maximum is 300 seconds. + * + * @default 300 + */ + readonly secretsManagerTtl?: Duration; + + /** + * Timeout for requests to Parameter Store in milliseconds. A value of 0 means there is + * no timeout. + * + * @default 0 + */ + readonly parameterStoreTimeout?: Duration; + + /** + * The time to live of a parameter in the cache in seconds. A value of 0 means there is + * no caching. The maximum is 300 seconds. + * + * Note: This is ignored if paramsAndSecretsCacheSize is 0. + * + * @default 300 + */ + readonly parameterStoreTtl?: Duration; +} + +export class ParamsAndSecretsLayer { + public static fromParamsAndSecretsConfig(config: ParamsAndSecretsConfig = {}): ParamsAndSecretsLayer { + return new ParamsAndSecretsLayer(config); + } + + public static _bind(): void { + + } + + private constructor(private readonly config: ParamsAndSecretsConfig) {} +} diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index bf637ac9c00ac..1e69d4c45a0d9 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -10,6 +10,7 @@ import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; import * as s3 from '../../aws-s3'; +import * as sm from '../../aws-secretsmanager'; import * as signer from '../../aws-signer'; import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; @@ -19,6 +20,7 @@ import * as cxapi from '../../cx-api'; import * as lambda from '../lib'; import { AdotLambdaLayerJavaSdkVersion } from '../lib/adot-layers'; import { calculateFunctionHash } from '../lib/function-hash'; +import { ParamsAndSecretsLayerVersion } from '../lib/params-and-secrets-layers'; describe('function', () => { const dockerLambdaHandlerPath = path.join(__dirname, 'docker-lambda-handler'); @@ -3203,6 +3205,20 @@ test('set SnapStart to desired value', () => { }); }); +test('parameters and secrets extension', () => { + const stack = new cdk.Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + const lambdaFunction = new lambda.Function(stack, 'MyLambda', { + code: new lambda.InlineCode('foo'), + handler: 'bar', + runtime: lambda.Runtime.NODEJS_14_X, + ephemeralStorageSize: Size.mebibytes(1024), + }); + + /* eslint-disable no-console */ + console.log('Duration millis = ', cdk.Duration.millis(3000)); + console.log(JSON.stringify(Template.fromStack(stack), null, 4)); +}); + function newTestLambda(scope: constructs.Construct) { return new lambda.Function(scope, 'MyLambda', { code: new lambda.InlineCode('foo'), From d4ac1c551bdbb5cf747a2e07bac4b720fdb2f494 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 14:07:23 -0700 Subject: [PATCH 07/49] initial implementation for _bind and some initial logic for configureParamsAndSecretsExtension Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 2 ++ .../lib/params-and-secrets-layers.ts | 20 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 0333f6ffbe04d..f35a260598747 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -922,6 +922,8 @@ export class Function extends FunctionBase { this.configureLambdaInsights(props); this.configureAdotInstrumentation(props); + + this.configureParamsAndSecretsExtension(props); } /** 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 index e7a91d30cdc32..4b22fcda95713 100644 --- 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 @@ -1,5 +1,17 @@ +import { Construct } from 'constructs'; +import { IFunction } from './function-base'; import { Duration } from '../../core'; +/** + * Config returned from `ParamsAndSecretsVersion._bind` + */ +interface ParamsAndSecretsBindConfig { + /** + * ARN of the Parameters and Secrets Layer Version + */ + readonly arn: string; +} + /** * Logging levels for Parameters and Secrets Extension */ @@ -114,9 +126,11 @@ export class ParamsAndSecretsLayer { return new ParamsAndSecretsLayer(config); } - public static _bind(): void { + private constructor(private readonly config: ParamsAndSecretsConfig) {} + public _bind(scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { + return { + arn: '', + }; } - - private constructor(private readonly config: ParamsAndSecretsConfig) {} } From 762b2d34148287105131ffc6eb1742824bfbf1f2 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 20:09:14 -0700 Subject: [PATCH 08/49] refactor Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 49 +----- packages/aws-cdk-lib/aws-lambda/lib/index.ts | 1 + .../lib/params-and-secrets-layers.ts | 139 ++++-------------- .../aws-lambda/test/function.test.ts | 4 +- packages/aws-cdk-lib/region-info/lib/fact.ts | 2 + 5 files changed, 43 insertions(+), 152 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index f35a260598747..db90619b77704 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -15,7 +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, ParamsAndSecretsLayer, ParamsAndSecretsLogLevels } from './params-and-secrets-layers'; +import { ParamsAndSecretsConfig, ParamsAndSecretsLayerVersion } from './params-and-secrets-layers'; import { Runtime } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; import { addAlias } from './util'; @@ -26,7 +26,6 @@ import * as ec2 from '../../aws-ec2'; import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; -import * as sm from '../../aws-secretsmanager'; import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; import { Annotations, ArnFormat, CfnResource, Duration, FeatureFlags, Fn, IAspect, Lazy, Names, Size, Stack, Token } from '../../core'; @@ -264,12 +263,12 @@ export interface FunctionOptions extends EventInvokeConfigOptions { readonly adotInstrumentation?: AdotInstrumentationConfig; /** - * Specify a Parameters and Secrets Extension layer + * Specify the configuration of Parameters and Secrets Extension * @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html * * @default - No Parameters and Secrets Extension layer */ - readonly paramsAndSecretsLayer?: ParamsAndSecretsLayer; + readonly paramsAndSecrets?: ParamsAndSecretsConfig; /** * A list of layers to add to the function's execution environment. You can configure your Lambda function to pull in @@ -1079,37 +1078,6 @@ export class Function extends FunctionBase { return addAlias(this, this.currentVersion, aliasName, options); } - public attachParametersAndSecretsExtension(secret: sm.ISecret, config: ParamsAndSecretsConfig = {}): void { - const paramsAndSecretsLayer = LayerVersion.fromLayerVersionArn( - this.stack, - 'ParamsAndSecretsExtensionLayer', - this.paramsAndSecretsExtensionLambdaArn, - ); - this.addLayers(paramsAndSecretsLayer); - - this.addToRolePolicy(new iam.PolicyStatement({ - actions: ['secretsmanager:GetSecret'], - resources: [secret.secretArn], - })); - - if (secret.encryptionKey) { - secret.encryptionKey.grantDecrypt(this); - } - - const environmentVariables: { [key: string]: any } = { - PARAMETERS_SECRETS_EXTENSION_CACHE_ENABLED: config.paramsAndSecretsCacheEnabled ?? true, - PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE: config.paramsAndSecretsCacheEnabled ?? 1000, - PARAMETERS_SECRETS_EXTENSION_HTTP_PORT: config.paramsAndSecretsHttpPort ?? 2773, - PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL: config.paramsAndSecretsLogLevel ?? ParamsAndSecretsLogLevels.INFO, - PARAMETERS_SECRETS_EXTENSION_MAX_CONNECTIONS: config.paramsAndSecretsMaxConnections ?? 3, - SECRETS_MANAGER_TIMEOUT_MILLIS: config.secretsManagerTimeout?.toMilliseconds() ?? 0, - SECRETS_MANAGER_TTL: config.secretsManagerTtl?.toSeconds() ?? 300, - SSM_PARAMETER_STORE_TIMEOUT_MILLIS: config.parameterStoreTimeout?.toMilliseconds() ?? 0, - SSN_PARAMETER_STORE_TTL: config.parameterStoreTtl?.toSeconds() ?? 300, - }; - Object.entries(environmentVariables).forEach(([key, value]) => this.addEnvironment(key, value.toString())); - } - /** * The LogGroup where the Lambda function's logs are made available. * @@ -1131,13 +1099,6 @@ export class Function extends FunctionBase { return this._logGroup; } - public get paramsAndSecretsExtensionLambdaArn(): string { - if (Token.isUnresolved(this.stack.region)) { - throw new Error('Unable to retrieve lambda arn for parameters and secrets extension'); - } - return PARAMS_AND_SECRETS_EXTENSION_LAMBDA_ARNS[this.architecture.name][this.stack.region]; - } - /** @internal */ public _checkEdgeCompatibility(): void { // Check env vars @@ -1204,7 +1165,11 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett * Add a Parameters and Secrets Extension Lambda layer. */ private configureParamsAndSecretsExtension(props: FunctionProps): void { + if (props.paramsAndSecrets === undefined) { + return; + } + this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', props.paramsAndSecrets.paramsAndSecretsVersion._bind(this, this).arn)); } private renderLayers() { 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 index 4b22fcda95713..e56853a2a1d1e 100644 --- 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 @@ -1,136 +1,61 @@ import { Construct } from 'constructs'; import { IFunction } from './function-base'; -import { Duration } from '../../core'; +import { ISecret } from '../../aws-secretsmanager'; /** * Config returned from `ParamsAndSecretsVersion._bind` */ interface ParamsAndSecretsBindConfig { /** - * ARN of the Parameters and Secrets Layer Version + * ARN of the Parameters and Secrets layer version */ readonly arn: string; } -/** - * Logging levels for Parameters and Secrets Extension - */ -export enum ParamsAndSecretsLogLevels { - /** - * Debug - */ - DEBUG = 'debug', - - /** - * Info - */ - INFO = 'info', - - /** - * Warn - */ - WARN = 'warn', - - /** - * Error - */ - ERROR = 'error', - - /** - * No logging - */ - NONE = 'none', -} - -/** - * Configuration options for Parameters and Secrets Extension - */ export interface ParamsAndSecretsConfig { /** - * Enables Parameters and Secrets Extension to cache parameters and secrets * - * @default true */ - readonly paramsAndSecretsCacheEnabled?: boolean; + readonly secret: ISecret; /** - * 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 is ignored if both parameterStoreTtl and secretsManagerTtl are 0. - * - * @default 1000 - */ - readonly paramsAndSecretsCacheSize?: number; - - /** - * The port for the local HTTP server. - * - * @default 2773 + * The Parameters and Secrets Extension layer. */ - readonly paramsAndSecretsHttpPort?: number; + readonly paramsAndSecretsVersion: ParamsAndSecretsLayerVersion; +} - /** - * The level of logging for the Parameters and Secrets Extension to provide. - * - * @default - no logging - */ - readonly paramsAndSecretsLogLevel?: ParamsAndSecretsLogLevels; +export abstract class ParamsAndSecretsLayerVersion { + public static readonly LATEST = ParamsAndSecretsLayerVersion.fromLookUp(); - /** - * The maximum number of connections for HTTP clients that the Parameters and Secrets - * Extension uses to make requests to Parameter Store or Secrets Manager. This is a - * per-client configuration - * - * @default 3 - */ - readonly paramsAndSecretsMaxConnections?: number; + public static fromParamsAndSecretsVersionArn(arn: string): ParamsAndSecretsLayerVersion { + class ParamsAndSecretsArn extends ParamsAndSecretsLayerVersion { + public readonly layerVersionArn = arn; + public _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { + return { + arn, + }; + } + } - /** - * Timeout for request to Secrets Manager in milliseconds. A value of 0 means there is - * no timeout. - * - * @default 0 - */ - readonly secretsManagerTimeout?: Duration; + return new ParamsAndSecretsArn(); + } - /** - * The time to live of a secret in the cache in seconds. A value of 0 means there is no - * caching. The maximum is 300 seconds. - * - * @default 300 - */ - readonly secretsManagerTtl?: Duration; + private static fromLookUp(): ParamsAndSecretsLayerVersion { + class ParamsAndSecretsVersion extends ParamsAndSecretsLayerVersion { + public _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { + return { + arn: '', + }; + } + } - /** - * Timeout for requests to Parameter Store in milliseconds. A value of 0 means there is - * no timeout. - * - * @default 0 - */ - readonly parameterStoreTimeout?: Duration; + return new ParamsAndSecretsVersion(); + } /** - * The time to live of a parameter in the cache in seconds. A value of 0 means there is - * no caching. The maximum is 300 seconds. - * - * Note: This is ignored if paramsAndSecretsCacheSize is 0. + * Returns the arn of the Parameters and Secrets extension * - * @default 300 + * @internal */ - readonly parameterStoreTtl?: Duration; -} - -export class ParamsAndSecretsLayer { - public static fromParamsAndSecretsConfig(config: ParamsAndSecretsConfig = {}): ParamsAndSecretsLayer { - return new ParamsAndSecretsLayer(config); - } - - private constructor(private readonly config: ParamsAndSecretsConfig) {} - - public _bind(scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { - return { - arn: '', - }; - } + public abstract _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig; } diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index 1e69d4c45a0d9..e3bfd591611e2 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -10,7 +10,6 @@ import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; import * as s3 from '../../aws-s3'; -import * as sm from '../../aws-secretsmanager'; import * as signer from '../../aws-signer'; import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; @@ -20,7 +19,6 @@ import * as cxapi from '../../cx-api'; import * as lambda from '../lib'; import { AdotLambdaLayerJavaSdkVersion } from '../lib/adot-layers'; import { calculateFunctionHash } from '../lib/function-hash'; -import { ParamsAndSecretsLayerVersion } from '../lib/params-and-secrets-layers'; describe('function', () => { const dockerLambdaHandlerPath = path.join(__dirname, 'docker-lambda-handler'); @@ -3207,7 +3205,7 @@ test('set SnapStart to desired value', () => { test('parameters and secrets extension', () => { const stack = new cdk.Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); - const lambdaFunction = new lambda.Function(stack, 'MyLambda', { + new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('foo'), handler: 'bar', runtime: lambda.Runtime.NODEJS_14_X, diff --git a/packages/aws-cdk-lib/region-info/lib/fact.ts b/packages/aws-cdk-lib/region-info/lib/fact.ts index 320e747688de8..787c6ee951267 100644 --- a/packages/aws-cdk-lib/region-info/lib/fact.ts +++ b/packages/aws-cdk-lib/region-info/lib/fact.ts @@ -22,6 +22,8 @@ export class Fact { * @returns the fact value if it is known, and `undefined` otherwise. */ public static find(region: string, name: string): string | undefined { + /* eslint-disable no-console */ + console.log(this.database); const regionFacts = this.database[region]; return regionFacts && regionFacts[name]; } From d70555951beb932653c443fe953343fef126c7c0 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 20:32:45 -0700 Subject: [PATCH 09/49] created initial params and secrets fact table and added code for registering fact Signed-off-by: Francis --- .../aws-cdk-lib/region-info/build-tools/fact-tables.ts | 9 +++++++++ .../region-info/build-tools/generate-static-data.ts | 5 +++++ 2 files changed, 14 insertions(+) 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 62c8159dc0d3d..56f0b42fb8b16 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 @@ -543,6 +543,15 @@ export const FIREHOSE_CIDR_BLOCKS: { [region: string]: string } = { 'us-west-2': '52.89.255.224', }; +export const PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS: { [arch: string]: { [region: string]: string } } = { + x86_64: { + 'us-east-1': 'arn:aws:lambda:us-east-1:177933569100: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', + }, +}; + 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..0f980e1f28346 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,10 @@ export async function main(): Promise { } } } + + for (const arch in PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS) { + registerFact(region, ['paramsAndSecretsLambdaLayer', arch], PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS[arch][region]); + } } lines.push(' }'); lines.push(''); From a08b55bdb55064bda48425814e110e2a871c1e99 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 20:45:17 -0700 Subject: [PATCH 10/49] registered params and secrets fact Signed-off-by: Francis --- packages/aws-cdk-lib/region-info/lib/fact.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/aws-cdk-lib/region-info/lib/fact.ts b/packages/aws-cdk-lib/region-info/lib/fact.ts index 787c6ee951267..e85a0f3e91b74 100644 --- a/packages/aws-cdk-lib/region-info/lib/fact.ts +++ b/packages/aws-cdk-lib/region-info/lib/fact.ts @@ -210,4 +210,13 @@ 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 architecture the Lambda Function architecture (e.g. 'x86_64' or 'arm64') + */ + public static paramsAndSecretsLambdaLayer(architecture: string): string { + return `params-and-secrets-layer:${architecture}`; + } } From f8a22f11ea327caa4bdcc551a7be803b528d6d09 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 20:54:46 -0700 Subject: [PATCH 11/49] completed registering fact and created getVersionArn logic Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 22 +++++++++++++++++-- .../region-info/lib/region-info.ts | 9 ++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) 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 index e56853a2a1d1e..4d362dae5e977 100644 --- 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 @@ -1,6 +1,9 @@ -import { Construct } from 'constructs'; +import { Construct, IConstruct } from 'constructs'; +import { Architecture } from './architecture'; import { IFunction } from './function-base'; import { ISecret } from '../../aws-secretsmanager'; +import { Token, Stack } from '../../core'; +import { RegionInfo, FactName } from '../../region-info'; /** * Config returned from `ParamsAndSecretsVersion._bind` @@ -44,7 +47,7 @@ export abstract class ParamsAndSecretsLayerVersion { class ParamsAndSecretsVersion extends ParamsAndSecretsLayerVersion { public _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { return { - arn: '', + arn: getVersionArn(_scope, _function.architecture?.name ?? Architecture.X86_64.name), }; } } @@ -59,3 +62,18 @@ export abstract class ParamsAndSecretsLayerVersion { */ public abstract _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig; } + +function getVersionArn(scope: IConstruct, architecture: string): string { + const stack = Stack.of(scope); + const region = stack.region; + + if (region !== undefined && !Token.isUnresolved(region)) { + const layerArn = RegionInfo.get(region).paramsAndSecretsLambdaLayerArn(architecture); + if (layerArn === undefined) { + throw new Error(`Parameters and Secrets Extension is not supported in region ${region}`); + } + return layerArn; + } + + return stack.regionalFact(FactName.paramsAndSecretsLambdaLayer(architecture)); +} 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..7288b7fee1b30 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,13 @@ 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 architecture the Lambda Function architecture (e.g. 'x86_64' or 'arm64') + */ + public paramsAndSecretsLambdaLayerArn(architecture: string): string | undefined { + return Fact.find(this.name, FactName.paramsAndSecretsLambdaLayer(architecture)); + } } From 70143518bbfdfd9a63594dd25305b8c00b303622 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 21:29:20 -0700 Subject: [PATCH 12/49] made fromArchitecture static method and made lambda layern arn selectable by architecture Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) 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 index 4d362dae5e977..a896a798426c1 100644 --- 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 @@ -1,8 +1,7 @@ import { Construct, IConstruct } from 'constructs'; import { Architecture } from './architecture'; -import { IFunction } from './function-base'; import { ISecret } from '../../aws-secretsmanager'; -import { Token, Stack } from '../../core'; +import { Token, Stack, Lazy } from '../../core'; import { RegionInfo, FactName } from '../../region-info'; /** @@ -28,12 +27,15 @@ export interface ParamsAndSecretsConfig { } export abstract class ParamsAndSecretsLayerVersion { - public static readonly LATEST = ParamsAndSecretsLayerVersion.fromLookUp(); + public static readonly X86_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.X86_64); + + public static readonly ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); public static fromParamsAndSecretsVersionArn(arn: string): ParamsAndSecretsLayerVersion { class ParamsAndSecretsArn extends ParamsAndSecretsLayerVersion { public readonly layerVersionArn = arn; - public _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { + + public _bind(_scope: Construct): ParamsAndSecretsBindConfig { return { arn, }; @@ -43,11 +45,15 @@ export abstract class ParamsAndSecretsLayerVersion { return new ParamsAndSecretsArn(); } - private static fromLookUp(): ParamsAndSecretsLayerVersion { + private static fromArchitecture(architecture: Architecture): ParamsAndSecretsLayerVersion { class ParamsAndSecretsVersion extends ParamsAndSecretsLayerVersion { - public _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig { + public readonly layerVersionArn = Lazy.uncachedString({ + produce: (context) => getVersionArn(context.scope, architecture.name), + }); + + public _bind(_scope: Construct): ParamsAndSecretsBindConfig { return { - arn: getVersionArn(_scope, _function.architecture?.name ?? Architecture.X86_64.name), + arn: getVersionArn(_scope, architecture.name), }; } } @@ -60,7 +66,7 @@ export abstract class ParamsAndSecretsLayerVersion { * * @internal */ - public abstract _bind(_scope: Construct, _function: IFunction): ParamsAndSecretsBindConfig; + public abstract _bind(_scope: Construct): ParamsAndSecretsBindConfig; } function getVersionArn(scope: IConstruct, architecture: string): string { From a688ef43b6097620f2230772db0427ff088a3dbb Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 21:35:49 -0700 Subject: [PATCH 13/49] added permissions to configure params and secrets method Signed-off-by: Francis --- packages/aws-cdk-lib/aws-lambda/lib/function.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index db90619b77704..5632841a5bff1 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -15,11 +15,10 @@ import { Version, VersionOptions } from './lambda-version'; import { CfnFunction } from './lambda.generated'; import { LayerVersion, ILayerVersion } from './layers'; import { LogRetentionRetryOptions } from './log-retention'; -import { ParamsAndSecretsConfig, ParamsAndSecretsLayerVersion } from './params-and-secrets-layers'; +import { ParamsAndSecretsConfig } from './params-and-secrets-layers'; import { Runtime } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; import { addAlias } from './util'; -import { PARAMS_AND_SECRETS_EXTENSION_LAMBDA_ARNS } from '../../../@aws-cdk/region-info/build-tools/fact-tables'; import * as cloudwatch from '../../aws-cloudwatch'; import { IProfilingGroup, ProfilingGroup, ComputePlatform } from '../../aws-codeguruprofiler'; import * as ec2 from '../../aws-ec2'; @@ -1169,7 +1168,16 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett return; } - this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', props.paramsAndSecrets.paramsAndSecretsVersion._bind(this, this).arn)); + this.addToRolePolicy(new iam.PolicyStatement({ + actions: ['secretsmanager:GetSecretValue'], + resources: [props.paramsAndSecrets.secret.secretArn], + })); + + if (props.paramsAndSecrets.secret.encryptionKey) { + props.paramsAndSecrets.secret.encryptionKey.grantDecrypt(this); + } + + this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', props.paramsAndSecrets.paramsAndSecretsVersion._bind(this).arn)); } private renderLayers() { From 961460406467e2ea84842cc3ae2397e588df7c14 Mon Sep 17 00:00:00 2001 From: Francis Date: Sat, 20 May 2023 22:36:29 -0700 Subject: [PATCH 14/49] small refactoring and added all arns to fact table Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 4 +- .../aws-lambda/test/function.test.ts | 8 ++- .../region-info/build-tools/fact-tables.ts | 49 +++++++++++++++++++ packages/aws-cdk-lib/region-info/lib/fact.ts | 2 - 4 files changed, 57 insertions(+), 6 deletions(-) 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 index a896a798426c1..29054157c6c38 100644 --- 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 @@ -27,9 +27,9 @@ export interface ParamsAndSecretsConfig { } export abstract class ParamsAndSecretsLayerVersion { - public static readonly X86_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.X86_64); + public static readonly FOR_X86_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.X86_64); - public static readonly ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); + public static readonly FOR_ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); public static fromParamsAndSecretsVersionArn(arn: string): ParamsAndSecretsLayerVersion { class ParamsAndSecretsArn extends ParamsAndSecretsLayerVersion { diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index e3bfd591611e2..b3dfc4ca222fc 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -10,6 +10,7 @@ import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; import * as s3 from '../../aws-s3'; +import * as sm from '../../aws-secretsmanager'; import * as signer from '../../aws-signer'; import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; @@ -3204,16 +3205,19 @@ test('set SnapStart to desired value', () => { }); test('parameters and secrets extension', () => { - const stack = new cdk.Stack(undefined, 'Stack', { env: { region: 'us-east-1' } }); + const stack = new cdk.Stack(undefined, 'Stack'); new lambda.Function(stack, 'MyLambda', { code: new lambda.InlineCode('foo'), handler: 'bar', runtime: lambda.Runtime.NODEJS_14_X, ephemeralStorageSize: Size.mebibytes(1024), + paramsAndSecrets: { + secret: new sm.Secret(stack, 'Secret'), + paramsAndSecretsVersion: lambda.ParamsAndSecretsLayerVersion.FOR_X86_64, + }, }); /* eslint-disable no-console */ - console.log('Duration millis = ', cdk.Duration.millis(3000)); console.log(JSON.stringify(Template.fromStack(stack), null, 4)); }); 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 56f0b42fb8b16..009a6e8a008a9 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 @@ -546,9 +546,58 @@ export const FIREHOSE_CIDR_BLOCKS: { [region: string]: string } = { export const PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS: { [arch: string]: { [region: string]: string } } = { 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', }, }; diff --git a/packages/aws-cdk-lib/region-info/lib/fact.ts b/packages/aws-cdk-lib/region-info/lib/fact.ts index e85a0f3e91b74..f19ba130a3f92 100644 --- a/packages/aws-cdk-lib/region-info/lib/fact.ts +++ b/packages/aws-cdk-lib/region-info/lib/fact.ts @@ -22,8 +22,6 @@ export class Fact { * @returns the fact value if it is known, and `undefined` otherwise. */ public static find(region: string, name: string): string | undefined { - /* eslint-disable no-console */ - console.log(this.database); const regionFacts = this.database[region]; return regionFacts && regionFacts[name]; } From 2def06d16352f277111965d5924ffd41f6aa4ee2 Mon Sep 17 00:00:00 2001 From: Francis Date: Mon, 22 May 2023 08:38:52 -0700 Subject: [PATCH 15/49] removed test and added attribute to abstract class Signed-off-by: Francis --- .../aws-lambda/lib/params-and-secrets-layers.ts | 2 ++ .../aws-lambda/test/function.test.ts | 17 ----------------- 2 files changed, 2 insertions(+), 17 deletions(-) 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 index 29054157c6c38..48fbd1e612c9a 100644 --- 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 @@ -61,6 +61,8 @@ export abstract class ParamsAndSecretsLayerVersion { return new ParamsAndSecretsVersion(); } + public readonly layerVersionArn: string = ''; + /** * Returns the arn of the Parameters and Secrets extension * diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index b3dfc4ca222fc..d6c048c49783f 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -3204,23 +3204,6 @@ test('set SnapStart to desired value', () => { }); }); -test('parameters and secrets extension', () => { - const stack = new cdk.Stack(undefined, 'Stack'); - new lambda.Function(stack, 'MyLambda', { - code: new lambda.InlineCode('foo'), - handler: 'bar', - runtime: lambda.Runtime.NODEJS_14_X, - ephemeralStorageSize: Size.mebibytes(1024), - paramsAndSecrets: { - secret: new sm.Secret(stack, 'Secret'), - paramsAndSecretsVersion: lambda.ParamsAndSecretsLayerVersion.FOR_X86_64, - }, - }); - - /* eslint-disable no-console */ - console.log(JSON.stringify(Template.fromStack(stack), null, 4)); -}); - function newTestLambda(scope: constructs.Construct) { return new lambda.Function(scope, 'MyLambda', { code: new lambda.InlineCode('foo'), From f8e6f3457efa6a6de747ddb36ca85dc5c908a66f Mon Sep 17 00:00:00 2001 From: Francis Date: Mon, 22 May 2023 10:21:01 -0700 Subject: [PATCH 16/49] wip - unit tests Signed-off-by: Francis --- .../aws-lambda/test/function.test.ts | 1 - .../test/params-and-secrets.test.ts | 74 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index d6c048c49783f..bf637ac9c00ac 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -10,7 +10,6 @@ import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; import * as s3 from '../../aws-s3'; -import * as sm from '../../aws-secretsmanager'; import * as signer from '../../aws-signer'; import * as sns from '../../aws-sns'; import * as sqs from '../../aws-sqs'; 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..dc45717934c2f --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts @@ -0,0 +1,74 @@ +import { Template } from '../../assertions'; +import * as sm from '../../aws-secretsmanager'; +import * as cdk from '../../core'; +import * as lambda from '../lib'; + +function functionWithParamsAndSecrets(stack: cdk.Stack) { + return new lambda.Function(stack, 'Function', { + functionName: 'lambda', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + }); +} + +describe('params and secrets', () => { + test('can provide arn to enable params and secrets', () => { + // 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: { + paramsAndSecretsVersion: lambda.ParamsAndSecretsLayerVersion.fromParamsAndSecretsVersionArn(layerArn), + secret, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [layerArn], + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can specify x86_64 architecture', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(app, 'Secret'); + + // WHEN + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + paramsAndSecretsVersion: lambda.ParamsAndSecretsLayerVersion.FOR_X86_64, + secret, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: ['arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], + }); + expect(() => app.synth()).not.toThrow(); + }); + + test('can specify arm64 architecture', () => { + + }); + + test('role has kms:Decrypt for secret with encryption key', () => { + + }); +}); From a13cf7514cbfcbb21633a458cc2d887d27c607d3 Mon Sep 17 00:00:00 2001 From: Francis Date: Mon, 22 May 2023 13:23:43 -0700 Subject: [PATCH 17/49] wip Signed-off-by: Francis --- .../aws-lambda/test/params-and-secrets.test.ts | 9 --------- 1 file changed, 9 deletions(-) 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 index dc45717934c2f..4782c4ec9c278 100644 --- 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 @@ -3,15 +3,6 @@ import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; -function functionWithParamsAndSecrets(stack: cdk.Stack) { - return new lambda.Function(stack, 'Function', { - functionName: 'lambda', - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_18_X, - }); -} - describe('params and secrets', () => { test('can provide arn to enable params and secrets', () => { // GIVEN From 2361ff093c9ddab57fd43d89f4704bd5e908d1d1 Mon Sep 17 00:00:00 2001 From: Francis Date: Mon, 22 May 2023 14:59:27 -0700 Subject: [PATCH 18/49] updated naming and added unit tests Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 2 +- .../lib/params-and-secrets-layers.ts | 4 +- .../test/params-and-secrets.test.ts | 209 +++++++++++++++++- 3 files changed, 207 insertions(+), 8 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 5632841a5bff1..2b345a8c9bb13 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -1177,7 +1177,7 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett props.paramsAndSecrets.secret.encryptionKey.grantDecrypt(this); } - this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', props.paramsAndSecrets.paramsAndSecretsVersion._bind(this).arn)); + this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', props.paramsAndSecrets.layerVersion._bind(this).arn)); } private renderLayers() { 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 index 48fbd1e612c9a..a6c359c87ecad 100644 --- 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 @@ -23,7 +23,7 @@ export interface ParamsAndSecretsConfig { /** * The Parameters and Secrets Extension layer. */ - readonly paramsAndSecretsVersion: ParamsAndSecretsLayerVersion; + readonly layerVersion: ParamsAndSecretsLayerVersion; } export abstract class ParamsAndSecretsLayerVersion { @@ -31,7 +31,7 @@ export abstract class ParamsAndSecretsLayerVersion { public static readonly FOR_ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); - public static fromParamsAndSecretsVersionArn(arn: string): ParamsAndSecretsLayerVersion { + public static fromVersionArn(arn: string): ParamsAndSecretsLayerVersion { class ParamsAndSecretsArn extends ParamsAndSecretsLayerVersion { public readonly layerVersionArn = arn; 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 index 4782c4ec9c278..e3314d69f1dd2 100644 --- 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 @@ -1,8 +1,48 @@ import { Template } from '../../assertions'; +import * as kms from '../../aws-kms'; import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; +function verifyRoleHasCorrectPolicies(stack: cdk.Stack) { + 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', + Effect: 'Allow', + Resource: { + Ref: 'SecretA720EF05', + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); +} + describe('params and secrets', () => { test('can provide arn to enable params and secrets', () => { // GIVEN @@ -18,7 +58,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - paramsAndSecretsVersion: lambda.ParamsAndSecretsLayerVersion.fromParamsAndSecretsVersionArn(layerArn), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), secret, }, }); @@ -27,14 +67,15 @@ describe('params and secrets', () => { Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: [layerArn], }); + verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); - test('can specify x86_64 architecture', () => { + test('can specify x86_64 architecture in non-agnostic stack', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(app, 'Secret'); + const secret = new sm.Secret(stack, 'Secret'); // WHEN new lambda.Function (stack, 'Function', { @@ -43,7 +84,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - paramsAndSecretsVersion: lambda.ParamsAndSecretsLayerVersion.FOR_X86_64, + layerVersion: lambda.ParamsAndSecretsLayerVersion.FOR_X86_64, secret, }, }); @@ -52,14 +93,172 @@ describe('params and secrets', () => { Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: ['arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); + }); + + test('can specify x86_64 architecture in agnostic stack', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.FOR_X86_64, + secret, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [ + { + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + 'x86x64', + ], + }, + ], + }); + verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); - test('can specify arm64 architecture', () => { + test('can specify arm64 architecture in non-agnostic stack', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.FOR_ARM_64, + secret, + }, + }); + // 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'], + }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); + }); + + test('can specify arm64 architecture in agnostic stack', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.FOR_ARM_64, + secret, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [ + { + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + 'arm64', + ], + }, + ], + }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); }); test('role has kms:Decrypt for 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 }); + + // 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.FOR_ARM_64, + secret, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'secretsmanager:GetSecretValue', + Effect: 'Allow', + Resource: { + Ref: 'SecretA720EF05', + }, + }, + { + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: { + Ref: 'SecretA720EF05', + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); + }); + + test('can create two functions in a region agnostic stack with the same version', () => { + + }); + + test('can create two functions with different architectures in agnostic stack', () => { + + }); + + test('throws if x86_64 is not available in region', () => { + + }); + + test('throws if arm64 is not available in region', () => { }); }); From ab603dec8e08e9d86def6fa79d1d267d47b71588 Mon Sep 17 00:00:00 2001 From: Francis Date: Mon, 22 May 2023 15:14:50 -0700 Subject: [PATCH 19/49] corrected unit test and added more description to getVersionArn error message Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/params-and-secrets-layers.ts | 2 +- .../aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) 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 index a6c359c87ecad..485b24a866745 100644 --- 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 @@ -78,7 +78,7 @@ function getVersionArn(scope: IConstruct, architecture: string): string { if (region !== undefined && !Token.isUnresolved(region)) { const layerArn = RegionInfo.get(region).paramsAndSecretsLambdaLayerArn(architecture); if (layerArn === undefined) { - throw new Error(`Parameters and Secrets Extension is not supported in region ${region}`); + throw new Error(`Parameters and Secrets Extension is not supported in region ${region} for ${architecture} architecture`); } return layerArn; } 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 index e3314d69f1dd2..92129d681a6af 100644 --- 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 @@ -231,7 +231,10 @@ describe('params and secrets', () => { Action: 'kms:Decrypt', Effect: 'Allow', Resource: { - Ref: 'SecretA720EF05', + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], }, }, ], From 07c4d7df6fb787666e1478e3aafc74499c51e739 Mon Sep 17 00:00:00 2001 From: Francis Date: Mon, 22 May 2023 15:49:30 -0700 Subject: [PATCH 20/49] docstrings and unit test logic Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 34 +++++++++++++++++-- .../test/params-and-secrets.test.ts | 23 +++++++++---- 2 files changed, 49 insertions(+), 8 deletions(-) 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 index 485b24a866745..097ecaa28ce01 100644 --- 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 @@ -14,23 +14,41 @@ interface ParamsAndSecretsBindConfig { readonly arn: string; } +/** + * Parameters and Secrets Extension configuration + */ export interface ParamsAndSecretsConfig { /** - * + * The secret to grant the function access to */ readonly secret: ISecret; /** - * The Parameters and Secrets Extension layer. + * The Parameters and Secrets Extension layer */ readonly layerVersion: ParamsAndSecretsLayerVersion; } +/** + * Version of Parameters and Secrets Extension + */ export abstract class ParamsAndSecretsLayerVersion { + /** + * Version for x86_64 + */ public static readonly FOR_X86_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.X86_64); + /** + * Version for ARM_64 + */ public static readonly FOR_ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); + /** + * Use the Parameters and Secrets extension associate with the provided ARN. Make sure the ARN is associated + * with the same region 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): ParamsAndSecretsLayerVersion { class ParamsAndSecretsArn extends ParamsAndSecretsLayerVersion { public readonly layerVersionArn = arn; @@ -45,6 +63,9 @@ export abstract class ParamsAndSecretsLayerVersion { return new ParamsAndSecretsArn(); } + /** + * Use the architecture to build the object + */ private static fromArchitecture(architecture: Architecture): ParamsAndSecretsLayerVersion { class ParamsAndSecretsVersion extends ParamsAndSecretsLayerVersion { public readonly layerVersionArn = Lazy.uncachedString({ @@ -61,6 +82,9 @@ export abstract class ParamsAndSecretsLayerVersion { return new ParamsAndSecretsVersion(); } + /** + * The arn of the Parameters and Secrets extension lambda + */ public readonly layerVersionArn: string = ''; /** @@ -71,6 +95,12 @@ export abstract class ParamsAndSecretsLayerVersion { public abstract _bind(_scope: Construct): ParamsAndSecretsBindConfig; } +/** + * Function to 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. + */ function getVersionArn(scope: IConstruct, architecture: string): string { const stack = Stack.of(scope); const region = stack.region; 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 index 92129d681a6af..e8b5a8b0435df 100644 --- 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 @@ -145,7 +145,6 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { layerVersion: lambda.ParamsAndSecretsLayerVersion.FOR_ARM_64, secret, @@ -172,7 +171,6 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { layerVersion: lambda.ParamsAndSecretsLayerVersion.FOR_ARM_64, secret, @@ -257,11 +255,24 @@ describe('params and secrets', () => { }); - test('throws if x86_64 is not available in region', () => { - - }); - test('throws if arm64 is not available in region', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'eu-central-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + // 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.FOR_ARM_64, + secret, + }, + }); + }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); }); }); From 9fb3e491cb7f29b15620fb4c197d80dd506ccad4 Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 23 May 2023 11:34:52 -0700 Subject: [PATCH 21/49] added an options property to allow users to configure environment variables as part of the extension Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 138 +++++++++++++++++- 1 file changed, 131 insertions(+), 7 deletions(-) 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 index 097ecaa28ce01..e8ec1a228f986 100644 --- 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 @@ -1,7 +1,7 @@ import { Construct, IConstruct } from 'constructs'; import { Architecture } from './architecture'; import { ISecret } from '../../aws-secretsmanager'; -import { Token, Stack, Lazy } from '../../core'; +import { Token, Stack, Lazy, Duration } from '../../core'; import { RegionInfo, FactName } from '../../region-info'; /** @@ -14,12 +14,131 @@ interface ParamsAndSecretsBindConfig { readonly arn: string; } +/** + * Logging levels for the Parametes and Secrets Extension layer + */ +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 is parameterStoreTtl and secretsManagerTtl + * are 0. + * + * @default 1000 + */ + readonly cacheSize?: number; + + /** + * The port for the local HTTP server. + * + * @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. + * + * Note: This is a per-client configuration. + * + * @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 secret to grant the function access to + * + * TODO: Multiple secrets */ readonly secret: ISecret; @@ -27,6 +146,11 @@ export interface ParamsAndSecretsConfig { * The Parameters and Secrets Extension layer */ readonly layerVersion: ParamsAndSecretsLayerVersion; + + /** + * Configuration options for the Parameters and Secrets Extension layer + */ + readonly options: ParamsAndSecretsOptions; } /** @@ -34,18 +158,18 @@ export interface ParamsAndSecretsConfig { */ export abstract class ParamsAndSecretsLayerVersion { /** - * Version for x86_64 + * Version for x86_64 architecture */ public static readonly FOR_X86_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.X86_64); /** - * Version for ARM_64 + * Version for ARM_64 architecture */ public static readonly FOR_ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); /** - * Use the Parameters and Secrets extension associate with the provided ARN. Make sure the ARN is associated - * with the same region as your function + * Use the Parameters and Secrets Extension associated with the provided ARN. Make sure the ARN is associated + * with the same region as your function. * * @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html#retrieving-secrets_lambda_ARNs */ @@ -83,12 +207,12 @@ export abstract class ParamsAndSecretsLayerVersion { } /** - * The arn of the Parameters and Secrets extension lambda + * The ARN of the Parameters and Secrets Extension lambda */ public readonly layerVersionArn: string = ''; /** - * Returns the arn of the Parameters and Secrets extension + * Returns the ARN of the Parameters and Secrets Extension * * @internal */ From 9759a4159124a78bc6b62345dde4541bca05581b Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 23 May 2023 20:32:08 -0700 Subject: [PATCH 22/49] refactor Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 20 +- .../lib/params-and-secrets-layers.ts | 99 ++++---- .../test/params-and-secrets.test.ts | 217 +----------------- 3 files changed, 65 insertions(+), 271 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 2b345a8c9bb13..f1db3e916b3a3 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -265,7 +265,7 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * Specify the configuration of Parameters and Secrets Extension * @see https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html * - * @default - No Parameters and Secrets Extension layer + * @default - No Parameters and Secrets Extension */ readonly paramsAndSecrets?: ParamsAndSecretsConfig; @@ -1168,16 +1168,22 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett return; } + // grant permissions to lambda execution role to allow access to provided secrets + const resources: string[] = []; + props.paramsAndSecrets.secrets.forEach(secret => { + resources.push(secret.secretArn); + if (secret.encryptionKey) { + secret.encryptionKey.grantDecrypt(this); + } + }); this.addToRolePolicy(new iam.PolicyStatement({ actions: ['secretsmanager:GetSecretValue'], - resources: [props.paramsAndSecrets.secret.secretArn], + resources, })); - if (props.paramsAndSecrets.secret.encryptionKey) { - props.paramsAndSecrets.secret.encryptionKey.grantDecrypt(this); - } - - this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', props.paramsAndSecrets.layerVersion._bind(this).arn)); + 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() { 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 index e8ec1a228f986..6255dd76a31a4 100644 --- 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 @@ -1,8 +1,8 @@ import { Construct, IConstruct } from 'constructs'; -import { Architecture } from './architecture'; import { ISecret } from '../../aws-secretsmanager'; -import { Token, Stack, Lazy, Duration } from '../../core'; +import { Token, Stack, Duration } from '../../core'; import { RegionInfo, FactName } from '../../region-info'; +import * as lambda from '../lib'; /** * Config returned from `ParamsAndSecretsVersion._bind` @@ -12,10 +12,15 @@ 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 }; } /** - * Logging levels for the Parametes and Secrets Extension layer + * Logging levels for the Parametes and Secrets Extension */ export enum ParamsAndSecretsLogLevel { /** @@ -60,7 +65,7 @@ export interface ParamsAndSecretsOptions { * 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 is parameterStoreTtl and secretsManagerTtl + * Note: This variable is ignored if parameterStoreTtl and secretsManagerTtl * are 0. * * @default 1000 @@ -136,87 +141,63 @@ export interface ParamsAndSecretsOptions { */ export interface ParamsAndSecretsConfig { /** - * The secret to grant the function access to - * - * TODO: Multiple secrets + * The secrets to grant the function access to */ - readonly secret: ISecret; + readonly secrets: ISecret[]; /** * The Parameters and Secrets Extension layer + * + * @default - Parameters and Secrets Extension will be configured using */ readonly layerVersion: ParamsAndSecretsLayerVersion; - - /** - * Configuration options for the Parameters and Secrets Extension layer - */ - readonly options: ParamsAndSecretsOptions; } -/** - * Version of Parameters and Secrets Extension - */ export abstract class ParamsAndSecretsLayerVersion { - /** - * Version for x86_64 architecture - */ - public static readonly FOR_X86_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.X86_64); - - /** - * Version for ARM_64 architecture - */ - public static readonly FOR_ARM_64 = ParamsAndSecretsLayerVersion.fromArchitecture(Architecture.ARM_64); - - /** - * Use the Parameters and Secrets Extension associated with the provided ARN. Make sure the ARN is associated - * with the same region 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): ParamsAndSecretsLayerVersion { - class ParamsAndSecretsArn extends ParamsAndSecretsLayerVersion { - public readonly layerVersionArn = arn; - - public _bind(_scope: Construct): ParamsAndSecretsBindConfig { + public static fromVersionArn(arn: string, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { + return new (class extends ParamsAndSecretsLayerVersion { + public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { return { arn, + environmentVars: this.environmentVariablesFromOptions, }; } - } - - return new ParamsAndSecretsArn(); + })(options); } - /** - * Use the architecture to build the object - */ - private static fromArchitecture(architecture: Architecture): ParamsAndSecretsLayerVersion { - class ParamsAndSecretsVersion extends ParamsAndSecretsLayerVersion { - public readonly layerVersionArn = Lazy.uncachedString({ - produce: (context) => getVersionArn(context.scope, architecture.name), - }); - - public _bind(_scope: Construct): ParamsAndSecretsBindConfig { + public static fromParamsAndSecretsExtension(options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { + return new (class extends ParamsAndSecretsLayerVersion { + public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { return { - arn: getVersionArn(_scope, architecture.name), + arn: getVersionArn(_scope, _function.architecture.name), + environmentVars: this.environmentVariablesFromOptions, }; } - } - - return new ParamsAndSecretsVersion(); + })(options); } - /** - * The ARN of the Parameters and Secrets Extension lambda - */ - public readonly layerVersionArn: string = ''; + protected constructor(protected readonly options: ParamsAndSecretsOptions) {} /** * Returns the ARN of the Parameters and Secrets Extension * * @internal */ - public abstract _bind(_scope: Construct): ParamsAndSecretsBindConfig; + public abstract _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig; + + private get environmentVariablesFromOptions(): { [key: string]: any } { + 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, + }; + } } /** 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 index e8b5a8b0435df..2aa5a9a63efb6 100644 --- 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 @@ -1,5 +1,4 @@ import { Template } from '../../assertions'; -import * as kms from '../../aws-kms'; import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; @@ -59,220 +58,28 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), - secret, + secrets: [secret], }, }); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { Layers: [layerArn], - }); - verifyRoleHasCorrectPolicies(stack); - expect(() => app.synth()).not.toThrow(); - }); - - test('can specify x86_64 architecture in non-agnostic stack', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - - // 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.FOR_X86_64, - secret, - }, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { - Layers: ['arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], - }); - verifyRoleHasCorrectPolicies(stack); - expect(() => app.synth()).not.toThrow(); - }); - - test('can specify x86_64 architecture in agnostic stack', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const secret = new sm.Secret(stack, 'Secret'); - - // 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.FOR_X86_64, - secret, - }, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { - Layers: [ - { - 'Fn::FindInMap': [ - 'ParamsandsecretslayerMap', - { - Ref: 'AWS::Region', - }, - 'x86x64', - ], + 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', }, - ], - }); - verifyRoleHasCorrectPolicies(stack); - expect(() => app.synth()).not.toThrow(); - }); - - test('can specify arm64 architecture in non-agnostic stack', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - - // 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.FOR_ARM_64, - secret, }, }); - - // 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'], - }); verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); - - test('can specify arm64 architecture in agnostic stack', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack'); - const secret = new sm.Secret(stack, 'Secret'); - - // 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.FOR_ARM_64, - secret, - }, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { - Layers: [ - { - 'Fn::FindInMap': [ - 'ParamsandsecretslayerMap', - { - Ref: 'AWS::Region', - }, - 'arm64', - ], - }, - ], - }); - verifyRoleHasCorrectPolicies(stack); - expect(() => app.synth()).not.toThrow(); - }); - - test('role has kms:Decrypt for 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 }); - - // 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.FOR_ARM_64, - secret, - }, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: 'secretsmanager:GetSecretValue', - Effect: 'Allow', - Resource: { - Ref: 'SecretA720EF05', - }, - }, - { - Action: 'kms:Decrypt', - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'Key961B73FD', - 'Arn', - ], - }, - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', - Roles: [ - { - Ref: 'FunctionServiceRole675BB04A', - }, - ], - }); - }); - - test('can create two functions in a region agnostic stack with the same version', () => { - - }); - - test('can create two functions with different architectures in agnostic stack', () => { - - }); - - test('throws if arm64 is not available in region', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'eu-central-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - - // 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.FOR_ARM_64, - secret, - }, - }); - }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); - }); }); From 3e56c45e9df64f09be5120c0665cd8ba4986d69b Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 23 May 2023 21:20:02 -0700 Subject: [PATCH 23/49] wip Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 2 +- .../test/params-and-secrets.test.ts | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) 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 index 6255dd76a31a4..7123230d723a1 100644 --- 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 @@ -165,7 +165,7 @@ export abstract class ParamsAndSecretsLayerVersion { })(options); } - public static fromParamsAndSecretsExtension(options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { + public static fromExtension(options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { return { 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 index 2aa5a9a63efb6..a7f6959405015 100644 --- 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 @@ -82,4 +82,91 @@ describe('params and secrets', () => { verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); + + test('can enable params and secrets from extension in non-agnostic stack - x86-64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.fromExtension(), + secrets: [secret], + }, + }); + + // 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', + }, + }, + }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets from extension in agnostic stack - x86-64', () => { + + }); + + test('can enable params and secrets from extension in non-agnostic stack - arm64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.fromExtension(), + secrets: [secret], + }, + }); + + // 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', + }, + }, + }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); + }); + + test('can enable params and secrets from extension in agnostic stack - arm64', () => { + + }); }); From c86d4068a506d63f9ecfaf90314bbf8deedc2cce Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 23 May 2023 23:32:50 -0700 Subject: [PATCH 24/49] unit tests Signed-off-by: Francis --- .../lib/params-and-secrets-layers.ts | 2 +- .../test/params-and-secrets.test.ts | 182 ++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) 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 index 7123230d723a1..60ebaddb96ae2 100644 --- 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 @@ -176,7 +176,7 @@ export abstract class ParamsAndSecretsLayerVersion { })(options); } - protected constructor(protected readonly options: ParamsAndSecretsOptions) {} + private constructor(private readonly options: ParamsAndSecretsOptions) {} /** * Returns the ARN of the Parameters and Secrets Extension 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 index a7f6959405015..8f24a201f99ec 100644 --- 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 @@ -123,7 +123,50 @@ describe('params and secrets', () => { }); test('can enable params and secrets from extension in agnostic stack - x86-64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.fromExtension(), + secrets: [secret], + }, + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [{ + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + 'x86x64', + ], + }], + 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', + }, + }, + }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); }); test('can enable params and secrets from extension in non-agnostic stack - arm64', () => { @@ -167,6 +210,145 @@ describe('params and secrets', () => { }); test('can enable params and secrets from extension in agnostic stack - arm64', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'Stack'); + const secret = new sm.Secret(stack, 'Secret'); + + // 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.fromExtension(), + secrets: [secret], + }, + }); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [{ + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + 'arm64', + ], + }], + 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', + }, + }, + }); + verifyRoleHasCorrectPolicies(stack); + expect(() => app.synth()).not.toThrow(); + }); + + test('can configure params and secrets configuration options with arn', () => { + // GIVEN + const stack = new cdk.Stack(undefined, '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'; + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheEnabled: false, + cacheSize: 200, + httpPort: 8080, + logLevel: lambda.ParamsAndSecretsLogLevel.DEBUG, + maxConnections: 5, + secretsManagerTimeout: cdk.Duration.seconds(1), + secretsManagerTtl: cdk.Duration.seconds(150), + parameterStoreTimeout: cdk.Duration.seconds(2), + parameterStoreTtl: cdk.Duration.seconds(250), + }); + + // 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, + secrets: [secret], + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: ['arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], + Environment: { + Variables: { + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'false', + PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '200', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '8080', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'debug', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '5', + SECRETS_MANAGER_TIMEOUT_MILLIS: '1000', + SECRETS_MANAGER_TTL: '150', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '2000', + SSM_PARAMETER_STORE_TTL: '250', + }, + }, + }); + }); + + test('can configure params and secrets configuration options with layer version from extension', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromExtension({ + cacheEnabled: false, + cacheSize: 200, + httpPort: 8080, + logLevel: lambda.ParamsAndSecretsLogLevel.DEBUG, + maxConnections: 5, + secretsManagerTimeout: cdk.Duration.seconds(1), + secretsManagerTtl: cdk.Duration.seconds(150), + parameterStoreTimeout: cdk.Duration.seconds(2), + parameterStoreTtl: cdk.Duration.seconds(250), + }); + + // 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, + secrets: [secret], + }, + }); + + // 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: '200', + PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '8080', + PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'debug', + PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '5', + SECRETS_MANAGER_TIMEOUT_MILLIS: '1000', + SECRETS_MANAGER_TTL: '150', + SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '2000', + SSM_PARAMETER_STORE_TTL: '250', + }, + }, + }); }); }); From 581a7379ef724129007c77afa343524e7b0147a2 Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 09:49:12 -0700 Subject: [PATCH 25/49] added validation for configuration options, added unit tests, updated region-info to include version Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 38 +++-- .../lib/params-and-secrets-layers.ts | 62 ++++++-- .../test/params-and-secrets.test.ts | 138 +++++++++++++++++- .../region-info/build-tools/fact-tables.ts | 112 +++++++------- .../build-tools/generate-static-data.ts | 6 +- packages/aws-cdk-lib/region-info/lib/fact.ts | 6 +- .../region-info/lib/region-info.ts | 5 +- 7 files changed, 276 insertions(+), 91 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index f1db3e916b3a3..5c66145d98510 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -1168,18 +1168,34 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett return; } + let resources: string[]; // grant permissions to lambda execution role to allow access to provided secrets - const resources: string[] = []; - props.paramsAndSecrets.secrets.forEach(secret => { - resources.push(secret.secretArn); - if (secret.encryptionKey) { - secret.encryptionKey.grantDecrypt(this); - } - }); - this.addToRolePolicy(new iam.PolicyStatement({ - actions: ['secretsmanager:GetSecretValue'], - resources, - })); + if (props.paramsAndSecrets.secrets) { + resources = []; + props.paramsAndSecrets.secrets?.forEach(secret => { + resources.push(secret.secretArn); + if (secret.encryptionKey) { + secret.encryptionKey.grantDecrypt(this); + } + }); + this.addToRolePolicy(new iam.PolicyStatement({ + actions: ['secretsmanager:GetSecretValue'], + resources, + })); + } + + // grant permission to lambda execution role to allow access to provided parameters + if (props.paramsAndSecrets.parameters) { + resources = []; + props.paramsAndSecrets.parameters?.forEach(param => { + resources.push(param.parameterArn); + // TODO: Figure out how to determine if param is secure string for kms:Decrypt + }); + this.addToRolePolicy(new iam.PolicyStatement({ + actions: ['ssm:GetParameter'], + resources, + })); + } const layerVersion = props.paramsAndSecrets.layerVersion._bind(this, this); this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', layerVersion.arn)); 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 index 60ebaddb96ae2..f77b24281155e 100644 --- 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 @@ -1,5 +1,6 @@ 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'; @@ -19,6 +20,15 @@ interface ParamsAndSecretsBindConfig { readonly environmentVars: { [key: string]: string }; } +export enum ParamsAndSecretsVersions { + /** + * V4 + * + * Note: This is the latest version + */ + V4 = '4', +} + /** * Logging levels for the Parametes and Secrets Extension */ @@ -73,7 +83,7 @@ export interface ParamsAndSecretsOptions { readonly cacheSize?: number; /** - * The port for the local HTTP server. + * The port for the local HTTP server. Valid port numbers are 1 - 65535. * * @default 2773 */ @@ -91,7 +101,7 @@ export interface ParamsAndSecretsOptions { /** * The maximum number of connection for HTTP clients that the Parameters and * Secrets Extension uses to make requests to Parameter Store or Secrets - * Manager. + * Manager. There is no maximum limit. Minimum is 1. * * Note: This is a per-client configuration. * @@ -141,16 +151,23 @@ export interface ParamsAndSecretsOptions { */ export interface ParamsAndSecretsConfig { /** - * The secrets to grant the function access to + * The Parameters and Secrets Extension layer */ - readonly secrets: ISecret[]; + readonly layerVersion: ParamsAndSecretsLayerVersion; /** - * The Parameters and Secrets Extension layer + * The secrets to grant lambda access to * - * @default - Parameters and Secrets Extension will be configured using + * @default - No secrets */ - readonly layerVersion: ParamsAndSecretsLayerVersion; + readonly secrets?: ISecret[]; + + /** + * The parameters to grant lambda access to + * + * @default - No parameters + */ + readonly parameters?: IParameter[]; } export abstract class ParamsAndSecretsLayerVersion { @@ -165,11 +182,11 @@ export abstract class ParamsAndSecretsLayerVersion { })(options); } - public static fromExtension(options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { + public static fromVersion(version: ParamsAndSecretsVersions, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { return { - arn: getVersionArn(_scope, _function.architecture.name), + arn: getVersionArn(_scope, version, _function.architecture.name), environmentVars: this.environmentVariablesFromOptions, }; } @@ -186,6 +203,27 @@ export abstract class ParamsAndSecretsLayerVersion { public abstract _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig; 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, @@ -206,17 +244,17 @@ export abstract class ParamsAndSecretsLayerVersion { * * This function is run on CDK synthesis. */ -function getVersionArn(scope: IConstruct, architecture: string): string { +function getVersionArn(scope: IConstruct, version: string, architecture: string): string { const stack = Stack.of(scope); const region = stack.region; if (region !== undefined && !Token.isUnresolved(region)) { - const layerArn = RegionInfo.get(region).paramsAndSecretsLambdaLayerArn(architecture); + 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; } - return stack.regionalFact(FactName.paramsAndSecretsLambdaLayer(architecture)); + 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 index 8f24a201f99ec..095e1246ded2f 100644 --- 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 @@ -1,4 +1,5 @@ import { Template } from '../../assertions'; +import * as kms from '../../aws-kms'; import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; @@ -96,7 +97,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromExtension(), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), secrets: [secret], }, }); @@ -135,7 +136,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromExtension(), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), secrets: [secret], }, }); @@ -148,7 +149,7 @@ describe('params and secrets', () => { { Ref: 'AWS::Region', }, - 'x86x64', + '4xx86x64', ], }], Environment: { @@ -183,7 +184,7 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromExtension(), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), secrets: [secret], }, }); @@ -223,7 +224,7 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromExtension(), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), secrets: [secret], }, }); @@ -236,7 +237,7 @@ describe('params and secrets', () => { { Ref: 'AWS::Region', }, - 'arm64', + '4xarm64', ], }], Environment: { @@ -309,7 +310,7 @@ describe('params and secrets', () => { // GIVEN const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromExtension({ + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { cacheEnabled: false, cacheSize: 200, httpPort: 8080, @@ -351,4 +352,127 @@ describe('params and secrets', () => { }, }); }); + + test('execution role has kms:Decrypt', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const key = new kms.Key(stack, 'Key'); + const secret = new sm.Secret(stack, 'Secret', { encryptionKey: key }); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); + + // 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, + secrets: [secret], + }, + }); + + /* eslint-disable no-console */ + console.log(JSON.stringify(Template.fromStack(stack), null, 4)); + }); + + test('can provide multiple secrets', () => { + + }); + + test('throws for architecture in unsupported region', () => { + + }); + + test('throws for cache size < 0', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + cacheSize: -1, + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: -1'); + }); + + test('throws for cache size > 1000', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + cacheSize: 1001, + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: 1001'); + }); + + test('throws for port number < 1', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + httpPort: 0, + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 0'); + }); + + test('throws for port number > 65535', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + httpPort: 65536, + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 65536'); + }); }); 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 009a6e8a008a9..5838bdd22b764 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 @@ -543,61 +543,63 @@ export const FIREHOSE_CIDR_BLOCKS: { [region: string]: string } = { 'us-west-2': '52.89.255.224', }; -export const PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS: { [arch: string]: { [region: string]: string } } = { - 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', +export const PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS: { [version: string]: { [arch: string]: { [region: string]: string } } } = { + 4: { + 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', + }, }, }; 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 0f980e1f28346..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 @@ -116,8 +116,10 @@ export async function main(): Promise { } } - for (const arch in PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS) { - registerFact(region, ['paramsAndSecretsLambdaLayer', arch], PARAMS_AND_SECRETS_LAMBDA_LAYER_ARNS[arch][region]); + 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(' }'); diff --git a/packages/aws-cdk-lib/region-info/lib/fact.ts b/packages/aws-cdk-lib/region-info/lib/fact.ts index f19ba130a3f92..7ccc6df1c84b5 100644 --- a/packages/aws-cdk-lib/region-info/lib/fact.ts +++ b/packages/aws-cdk-lib/region-info/lib/fact.ts @@ -212,9 +212,11 @@ export class FactName { /** * 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(architecture: string): string { - return `params-and-secrets-layer:${architecture}`; + 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 7288b7fee1b30..9d974d69a15c5 100644 --- a/packages/aws-cdk-lib/region-info/lib/region-info.ts +++ b/packages/aws-cdk-lib/region-info/lib/region-info.ts @@ -182,9 +182,10 @@ export class RegionInfo { /** * 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(architecture: string): string | undefined { - return Fact.find(this.name, FactName.paramsAndSecretsLambdaLayer(architecture)); + public paramsAndSecretsLambdaLayerArn(version: string, architecture: string): string | undefined { + return Fact.find(this.name, FactName.paramsAndSecretsLambdaLayer(version, architecture)); } } From f15ba2d4071f09210f5bca956ca6f8ec8087df14 Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 10:24:27 -0700 Subject: [PATCH 26/49] unit tests for bad configuration options Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) 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 index 095e1246ded2f..ff8350fa20193 100644 --- 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 @@ -475,4 +475,90 @@ describe('params and secrets', () => { }); }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 65536'); }); + + test('throws for max connections < 1', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + maxConnections: 0, + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('Maximum connections must be at least 1 - provided: 0'); + }); + + test('throws for secrets TTL > 300 seconds', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + secretsManagerTtl: cdk.Duration.seconds(301), + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('Maximum TTL for a cached secret is 300 seconds - provided: 301 seconds'); + }); + + test('throws for parameters TTL > 300 seconds', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + parameterStoreTtl: cdk.Duration.seconds(301), + }); + + // 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, + secrets: [secret], + }, + }); + }).toThrow('Maximum TTL for a cached parameter is 300 seconds - provided: 301 seconds'); + }); + + test('', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); + + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion, + secrets: [], + }, + }); + }); }); From 06ab452de10393aefbeea97ab4b5607747b4919a Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 10:32:23 -0700 Subject: [PATCH 27/49] unit test for arm64 in unsupported region Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) 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 index ff8350fa20193..72f43c7e015c6 100644 --- 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 @@ -381,7 +381,25 @@ describe('params and secrets', () => { }); test('throws for architecture in unsupported region', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'eu-central-2' } }); + const secret = new sm.Secret(stack, 'Secret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); + // WHEN/THEN + expect(() => { + new lambda.Function (stack, 'Function', { + functionName: 'lambda-function', + code: new lambda.InlineCode('foo'), + handler: 'index.handler', + architecture: lambda.Architecture.ARM_64, + runtime: lambda.Runtime.NODEJS_18_X, + paramsAndSecrets: { + layerVersion, + secrets: [secret], + }, + }); + }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); }); test('throws for cache size < 0', () => { @@ -544,21 +562,4 @@ describe('params and secrets', () => { }); }).toThrow('Maximum TTL for a cached parameter is 300 seconds - provided: 301 seconds'); }); - - test('', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); - - new lambda.Function (stack, 'Function', { - functionName: 'lambda-function', - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion, - secrets: [], - }, - }); - }); }); From c09bbd41c62292b60ede31491a711b6abbb6ecc0 Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 10:39:03 -0700 Subject: [PATCH 28/49] unit test for kms:Decrypt in execution pole Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) 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 index 72f43c7e015c6..6bac00b061d40 100644 --- 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 @@ -372,8 +372,37 @@ describe('params and secrets', () => { }, }); - /* eslint-disable no-console */ - console.log(JSON.stringify(Template.fromStack(stack), null, 4)); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'kms:Decrypt', + Effect: 'Allow', + Resource: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }, + { + Action: 'secretsmanager:GetSecretValue', + Effect: 'Allow', + Resource: { + Ref: 'SecretA720EF05', + }, + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); }); test('can provide multiple secrets', () => { From a8c4b3c4c6a3700003363e007a0bc871f134df8c Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 11:14:45 -0700 Subject: [PATCH 29/49] unit test for multiple secrets Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) 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 index 6bac00b061d40..179274f3a739a 100644 --- 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 @@ -406,7 +406,66 @@ describe('params and secrets', () => { }); test('can provide multiple secrets', () => { + // GIVEN + const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); + const secret1 = new sm.Secret(stack, 'FirstSecret'); + const secret2 = new sm.Secret(stack, 'SecondSecret'); + const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); + // 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, + secrets: [secret1, secret2], + }, + }); + + // THEN + 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', + Effect: 'Allow', + Resource: [ + { + Ref: 'FirstSecret68ED90E5', + }, + { + Ref: 'SecondSecret188EE3B6', + }, + ], + }, + ], + Version: '2012-10-17', + }, + PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', + Roles: [ + { + Ref: 'FunctionServiceRole675BB04A', + }, + ], + }); }); test('throws for architecture in unsupported region', () => { From 8ae5edfa35f7bdd13ea1064fe476f68d53219983 Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 12:16:19 -0700 Subject: [PATCH 30/49] added some comments Signed-off-by: Francis --- .../aws-lambda/lib/params-and-secrets-layers.ts | 9 +++++++++ .../aws-lambda/test/params-and-secrets.test.ts | 1 + 2 files changed, 10 insertions(+) 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 index f77b24281155e..2fbf425b408e8 100644 --- 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 @@ -171,6 +171,9 @@ export interface ParamsAndSecretsConfig { } export abstract class ParamsAndSecretsLayerVersion { + /** + * Create layer version with provided ARN + */ public static fromVersionArn(arn: string, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { @@ -182,6 +185,9 @@ export abstract class ParamsAndSecretsLayerVersion { })(options); } + /** + * Create layer version from specific version + */ public static fromVersion(version: ParamsAndSecretsVersions, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { @@ -202,6 +208,9 @@ export abstract class ParamsAndSecretsLayerVersion { */ public abstract _bind(_scope: Construct, _function: 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}`); 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 index 179274f3a739a..6eb51878370dd 100644 --- 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 @@ -623,6 +623,7 @@ describe('params and secrets', () => { paramsAndSecrets: { layerVersion, secrets: [secret], + parameters: [] }, }); }).toThrow('Maximum TTL for a cached secret is 300 seconds - provided: 301 seconds'); From d128ab4156f3654231bf8b976a188f4aed9d491e Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 12:38:55 -0700 Subject: [PATCH 31/49] wip Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 35 ++--- .../test/params-and-secrets.test.ts | 121 +----------------- .../region-info/build-tools/fact-tables.ts | 1 + 3 files changed, 15 insertions(+), 142 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 5c66145d98510..6f8160f737716 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -1168,34 +1168,19 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett return; } - let resources: string[]; // grant permissions to lambda execution role to allow access to provided secrets - if (props.paramsAndSecrets.secrets) { - resources = []; - props.paramsAndSecrets.secrets?.forEach(secret => { - resources.push(secret.secretArn); - if (secret.encryptionKey) { - secret.encryptionKey.grantDecrypt(this); - } - }); - this.addToRolePolicy(new iam.PolicyStatement({ - actions: ['secretsmanager:GetSecretValue'], - resources, - })); - } + props.paramsAndSecrets.secrets?.forEach(secret => { + secret.grantRead(this); + if (secret.encryptionKey) { + secret.encryptionKey.grantDecrypt(this); + } + }); // grant permission to lambda execution role to allow access to provided parameters - if (props.paramsAndSecrets.parameters) { - resources = []; - props.paramsAndSecrets.parameters?.forEach(param => { - resources.push(param.parameterArn); - // TODO: Figure out how to determine if param is secure string for kms:Decrypt - }); - this.addToRolePolicy(new iam.PolicyStatement({ - actions: ['ssm:GetParameter'], - resources, - })); - } + props.paramsAndSecrets.parameters?.forEach(param => { + param.grantRead(this); + // TODO: Figure out how to determine if param is secure string for kms:Decrypt + }); const layerVersion = props.paramsAndSecrets.layerVersion._bind(this, this); this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', layerVersion.arn)); 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 index 6eb51878370dd..0ca3e585b7222 100644 --- 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 @@ -25,7 +25,10 @@ function verifyRoleHasCorrectPolicies(stack: cdk.Stack) { PolicyDocument: { Statement: [ { - Action: 'secretsmanager:GetSecretValue', + Action: [ + 'secretsmanager:GetSecretValue', + 'secretsmanager:DescribeSecret', + ], Effect: 'Allow', Resource: { Ref: 'SecretA720EF05', @@ -353,121 +356,6 @@ describe('params and secrets', () => { }); }); - test('execution role has kms:Decrypt', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const key = new kms.Key(stack, 'Key'); - const secret = new sm.Secret(stack, 'Secret', { encryptionKey: key }); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); - - // 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, - secrets: [secret], - }, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ - { - Action: 'kms:Decrypt', - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'Key961B73FD', - 'Arn', - ], - }, - }, - { - Action: 'secretsmanager:GetSecretValue', - Effect: 'Allow', - Resource: { - Ref: 'SecretA720EF05', - }, - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', - Roles: [ - { - Ref: 'FunctionServiceRole675BB04A', - }, - ], - }); - }); - - test('can provide multiple secrets', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret1 = new sm.Secret(stack, 'FirstSecret'); - const secret2 = new sm.Secret(stack, 'SecondSecret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); - - // 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, - secrets: [secret1, secret2], - }, - }); - - // THEN - 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', - Effect: 'Allow', - Resource: [ - { - Ref: 'FirstSecret68ED90E5', - }, - { - Ref: 'SecondSecret188EE3B6', - }, - ], - }, - ], - Version: '2012-10-17', - }, - PolicyName: 'FunctionServiceRoleDefaultPolicy2F49994A', - Roles: [ - { - Ref: 'FunctionServiceRole675BB04A', - }, - ], - }); - }); - test('throws for architecture in unsupported region', () => { // GIVEN const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'eu-central-2' } }); @@ -623,7 +511,6 @@ describe('params and secrets', () => { paramsAndSecrets: { layerVersion, secrets: [secret], - parameters: [] }, }); }).toThrow('Maximum TTL for a cached secret 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 5838bdd22b764..64aabac20d1f3 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 @@ -543,6 +543,7 @@ 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 } } } = { 4: { x86_64: { From 2b273a841e288c8b1fc143fb364fecce3ad8f071 Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 12:39:43 -0700 Subject: [PATCH 32/49] removed unneeded dependency Signed-off-by: Francis --- packages/aws-cdk-lib/aws-lambda/test/params-and-secrets.test.ts | 1 - 1 file changed, 1 deletion(-) 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 index 0ca3e585b7222..4b82fa33efa43 100644 --- 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 @@ -1,5 +1,4 @@ import { Template } from '../../assertions'; -import * as kms from '../../aws-kms'; import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; From 6e869ad96b341a8ae797a4136950ae96e9c21c21 Mon Sep 17 00:00:00 2001 From: Francis Date: Wed, 24 May 2023 21:02:04 -0700 Subject: [PATCH 33/49] naming convention Signed-off-by: Francis --- .../aws-lambda/lib/params-and-secrets-layers.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 2fbf425b408e8..ed214e119cd19 100644 --- 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 @@ -176,7 +176,7 @@ export abstract class ParamsAndSecretsLayerVersion { */ public static fromVersionArn(arn: string, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { - public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { + public _bind(_scope: Construct, _fn: lambda.IFunction): ParamsAndSecretsBindConfig { return { arn, environmentVars: this.environmentVariablesFromOptions, @@ -190,9 +190,9 @@ export abstract class ParamsAndSecretsLayerVersion { */ public static fromVersion(version: ParamsAndSecretsVersions, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { - public _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig { + public _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig { return { - arn: getVersionArn(_scope, version, _function.architecture.name), + arn: getVersionArn(scope, version, fn.architecture.name), environmentVars: this.environmentVariablesFromOptions, }; } @@ -206,7 +206,7 @@ export abstract class ParamsAndSecretsLayerVersion { * * @internal */ - public abstract _bind(_scope: Construct, _function: lambda.IFunction): ParamsAndSecretsBindConfig; + public abstract _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig; /** * Configure environment variables for Parameters and Secrets Extension based on configuration options From f8fa77cb32cc9980f389265f19b52fec01dde38d Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 26 May 2023 12:15:44 -0700 Subject: [PATCH 34/49] updated granting of permissions in function to just use grantRead, made getVersionArn a class method, unit tests Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 4 - .../lib/params-and-secrets-layers.ts | 44 +- .../test/params-and-secrets.test.ts | 455 ++---------------- 3 files changed, 55 insertions(+), 448 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 98080b9c048fc..9bfd41721f328 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -1171,15 +1171,11 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett // grant permissions to lambda execution role to allow access to provided secrets props.paramsAndSecrets.secrets?.forEach(secret => { secret.grantRead(this); - if (secret.encryptionKey) { - secret.encryptionKey.grantDecrypt(this); - } }); // grant permission to lambda execution role to allow access to provided parameters props.paramsAndSecrets.parameters?.forEach(param => { param.grantRead(this); - // TODO: Figure out how to determine if param is secure string for kms:Decrypt }); const layerVersion = props.paramsAndSecrets.layerVersion._bind(this, this); 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 index ed214e119cd19..f2e8351eda34e 100644 --- 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 @@ -103,7 +103,9 @@ export interface ParamsAndSecretsOptions { * Secrets Extension uses to make requests to Parameter Store or Secrets * Manager. There is no maximum limit. Minimum is 1. * - * Note: This is a per-client configuration. + * 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 */ @@ -192,7 +194,7 @@ export abstract class ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { public _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig { return { - arn: getVersionArn(scope, version, fn.architecture.name), + arn: this.getVersionArn(scope, version, fn.architecture.name), environmentVars: this.environmentVariablesFromOptions, }; } @@ -245,25 +247,27 @@ export abstract class ParamsAndSecretsLayerVersion { SSM_PARAMETER_STORE_TTL: this.options.parameterStoreTtl?.toSeconds() ?? 300, }; } -} -/** - * Function to 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. - */ -function getVersionArn(scope: IConstruct, version: string, architecture: string): string { - const stack = Stack.of(scope); - const region = stack.region; - - 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`); + /** + * 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; } - return layerArn; - } - return stack.regionalFact(FactName.paramsAndSecretsLambdaLayer(version, architecture)); + // 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 index 4b82fa33efa43..cede666c68fe2 100644 --- 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 @@ -1,56 +1,12 @@ import { Template } from '../../assertions'; -import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; -function verifyRoleHasCorrectPolicies(stack: cdk.Stack) { - 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', - }, - ], - }); -} - describe('params and secrets', () => { - test('can provide arn to enable 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 secret = new sm.Secret(stack, 'Secret'); const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; // WHEN @@ -61,7 +17,6 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), - secrets: [secret], }, }); @@ -82,54 +37,14 @@ describe('params and secrets', () => { }, }, }); - verifyRoleHasCorrectPolicies(stack); - expect(() => app.synth()).not.toThrow(); - }); - - test('can enable params and secrets from extension in non-agnostic stack - x86-64', () => { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - - // 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.V4), - secrets: [secret], - }, - }); - - // 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', - }, - }, - }); - verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); - test('can enable params and secrets from extension in agnostic stack - x86-64', () => { + 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 secret = new sm.Secret(stack, 'Secret'); + 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', { @@ -138,45 +53,44 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), - secrets: [secret], + 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: [{ - 'Fn::FindInMap': [ - 'ParamsandsecretslayerMap', - { - Ref: 'AWS::Region', - }, - '4xx86x64', - ], - }], + 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', + 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', }, }, }); - verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); - test('can enable params and secrets from extension in non-agnostic stack - arm64', () => { + 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: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); + const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); // WHEN new lambda.Function (stack, 'Function', { @@ -184,16 +98,14 @@ describe('params and secrets', () => { 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.V4), - secrets: [secret], }, }); // 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'], + 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', @@ -208,15 +120,13 @@ describe('params and secrets', () => { }, }, }); - verifyRoleHasCorrectPolicies(stack); expect(() => app.synth()).not.toThrow(); }); - test('can enable params and secrets from extension in agnostic stack - arm64', () => { + 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'); - const secret = new sm.Secret(stack, 'Secret'); // WHEN new lambda.Function (stack, 'Function', { @@ -224,317 +134,14 @@ describe('params and secrets', () => { 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.V4), - secrets: [secret], }, }); // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { - Layers: [{ - 'Fn::FindInMap': [ - 'ParamsandsecretslayerMap', - { - Ref: 'AWS::Region', - }, - '4xarm64', - ], - }], - 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', - }, - }, - }); - verifyRoleHasCorrectPolicies(stack); + /* eslint-disable no-console */ + console.log(JSON.stringify(Template.fromStack(stack), null, 4)); expect(() => app.synth()).not.toThrow(); }); - - test('can configure params and secrets configuration options with arn', () => { - // GIVEN - const stack = new cdk.Stack(undefined, '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'; - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { - cacheEnabled: false, - cacheSize: 200, - httpPort: 8080, - logLevel: lambda.ParamsAndSecretsLogLevel.DEBUG, - maxConnections: 5, - secretsManagerTimeout: cdk.Duration.seconds(1), - secretsManagerTtl: cdk.Duration.seconds(150), - parameterStoreTimeout: cdk.Duration.seconds(2), - parameterStoreTtl: cdk.Duration.seconds(250), - }); - - // 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, - secrets: [secret], - }, - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { - Layers: ['arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'], - Environment: { - Variables: { - PARAMETERS_AND_SECRETS_EXTENSION_CACHE_ENABLED: 'false', - PARAMETERS_AND_SECRETS_EXTENSION_CACHE_SIZE: '200', - PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '8080', - PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'debug', - PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '5', - SECRETS_MANAGER_TIMEOUT_MILLIS: '1000', - SECRETS_MANAGER_TTL: '150', - SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '2000', - SSM_PARAMETER_STORE_TTL: '250', - }, - }, - }); - }); - - test('can configure params and secrets configuration options with layer version from extension', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - cacheEnabled: false, - cacheSize: 200, - httpPort: 8080, - logLevel: lambda.ParamsAndSecretsLogLevel.DEBUG, - maxConnections: 5, - secretsManagerTimeout: cdk.Duration.seconds(1), - secretsManagerTtl: cdk.Duration.seconds(150), - parameterStoreTimeout: cdk.Duration.seconds(2), - parameterStoreTtl: cdk.Duration.seconds(250), - }); - - // 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, - secrets: [secret], - }, - }); - - // 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: '200', - PARAMETERS_AND_SECRETS_EXTENSION_HTTP_PORT: '8080', - PARAMETERS_AND_SECRETS_EXTENSION_LOG_LEVEL: 'debug', - PARAMETERS_AND_SECRETS_EXTENSION_MAX_CONNECTIONS: '5', - SECRETS_MANAGER_TIMEOUT_MILLIS: '1000', - SECRETS_MANAGER_TTL: '150', - SSM_PARAMETER_STORE_TIMEOUT_MILLIS: '2000', - SSM_PARAMETER_STORE_TTL: '250', - }, - }, - }); - }); - - test('throws for architecture in unsupported region', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'eu-central-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4); - - // WHEN/THEN - expect(() => { - new lambda.Function (stack, 'Function', { - functionName: 'lambda-function', - code: new lambda.InlineCode('foo'), - handler: 'index.handler', - architecture: lambda.Architecture.ARM_64, - runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion, - secrets: [secret], - }, - }); - }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); - }); - - test('throws for cache size < 0', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - cacheSize: -1, - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: -1'); - }); - - test('throws for cache size > 1000', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - cacheSize: 1001, - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: 1001'); - }); - - test('throws for port number < 1', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - httpPort: 0, - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 0'); - }); - - test('throws for port number > 65535', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - httpPort: 65536, - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 65536'); - }); - - test('throws for max connections < 1', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - maxConnections: 0, - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('Maximum connections must be at least 1 - provided: 0'); - }); - - test('throws for secrets TTL > 300 seconds', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - secretsManagerTtl: cdk.Duration.seconds(301), - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('Maximum TTL for a cached secret is 300 seconds - provided: 301 seconds'); - }); - - test('throws for parameters TTL > 300 seconds', () => { - // GIVEN - const stack = new cdk.Stack(undefined, 'Stack', { env: { account: '123456789012', region: 'us-west-2' } }); - const secret = new sm.Secret(stack, 'Secret'); - const layerVersion = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { - parameterStoreTtl: cdk.Duration.seconds(301), - }); - - // 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, - secrets: [secret], - }, - }); - }).toThrow('Maximum TTL for a cached parameter is 300 seconds - provided: 301 seconds'); - }); }); From 2745e6963ef3c0f48507d863a2a734e71421df73 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 26 May 2023 12:37:18 -0700 Subject: [PATCH 35/49] unit tests for fromVersion testing Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 179 +++++++++++++++++- 1 file changed, 177 insertions(+), 2 deletions(-) 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 index cede666c68fe2..aad8aef7016f3 100644 --- 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 @@ -140,8 +140,183 @@ describe('params and secrets', () => { }); // THEN - /* eslint-disable no-console */ - console.log(JSON.stringify(Template.fromStack(stack), null, 4)); + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [ + { + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + '4xx86x64', + ], + }, + ], + 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.V4), + }, + }); + + // 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.V4), + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Layers: [ + { + 'Fn::FindInMap': [ + 'ParamsandsecretslayerMap', + { + Ref: 'AWS::Region', + }, + '4xarm64', + ], + }, + ], + 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.V4, { + 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.V4), + }, + }); + }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); + }); }); From 2e4a2afa76451c3fad9b99af58708556f4fadb58 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 26 May 2023 14:25:05 -0700 Subject: [PATCH 36/49] unit tests for secrets with and without encryption key Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 300 +++++++++++++++++- 1 file changed, 299 insertions(+), 1 deletion(-) 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 index aad8aef7016f3..7917fe3c6f0f4 100644 --- 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 @@ -1,4 +1,6 @@ -import { Template } from '../../assertions'; +import { Template, Match } from '../../assertions'; +import * as kms from '../../aws-kms'; +import * as sm from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as lambda from '../lib'; @@ -319,4 +321,300 @@ describe('params and secrets', () => { }); }).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', () => { + + }); + + test('can enable params and secrets with a provided parameter with encryption', () => { + + }); + + test('can enable params and secrets with multiple secrets and parameters', () => { + + }); }); From 005d6fdf06a6c6a525f1b4880afa7233e965f049 Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 30 May 2023 06:06:11 -0700 Subject: [PATCH 37/49] added unit tests for parameters Signed-off-by: Francis --- .../test/params-and-secrets.test.ts | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) 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 index 7917fe3c6f0f4..8960ba694520e 100644 --- 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 @@ -1,6 +1,7 @@ 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'; @@ -607,11 +608,213 @@ describe('params and secrets', () => { }); 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', () => { From dd12ce500df7aa0d6ea467a2fc0de1fc54ce6ae6 Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 30 May 2023 07:11:42 -0700 Subject: [PATCH 38/49] unit tests for configuration options Signed-off-by: Francis --- .../aws-cdk-lib/aws-lambda/lib/function.ts | 1 + .../lib/params-and-secrets-layers.ts | 13 +- .../test/params-and-secrets.test.ts | 272 ++++++++++++++++++ 3 files changed, 284 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 9bfd41721f328..b23caea41c590 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -264,6 +264,7 @@ export interface FunctionOptions extends EventInvokeConfigOptions { /** * 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 */ 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 index f2e8351eda34e..2aac7085282a5 100644 --- 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 @@ -20,6 +20,9 @@ interface ParamsAndSecretsBindConfig { readonly environmentVars: { [key: string]: string }; } +/** + * Parameters and Secrets Extension versions + */ export enum ParamsAndSecretsVersions { /** * V4 @@ -172,9 +175,15 @@ export interface ParamsAndSecretsConfig { readonly parameters?: IParameter[]; } +/** + * Parameters and Secrets Extension layer version + */ export abstract class ParamsAndSecretsLayerVersion { /** - * Create layer version with provided ARN + * 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 { @@ -188,7 +197,7 @@ export abstract class ParamsAndSecretsLayerVersion { } /** - * Create layer version from specific version + * 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 { 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 index 8960ba694520e..7b0869479ad85 100644 --- 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 @@ -818,6 +818,278 @@ describe('params and secrets', () => { }); 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'); }); }); From 4dfb29ec06fae97b03a98bd2d0cac1bb5fd7c294 Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 30 May 2023 07:29:46 -0700 Subject: [PATCH 39/49] added README section for parameters and secrets extension Signed-off-by: Francis --- packages/aws-cdk-lib/aws-lambda/README.md | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 9d9962c807469..3764a792cf1e1 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -568,6 +568,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.ParamsAndSecretsVersion.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 From c16d2d8706522a28a75cc8c59fea84642902ce5a Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 30 May 2023 07:35:40 -0700 Subject: [PATCH 40/49] updated readme Signed-off-by: Francis --- packages/aws-cdk-lib/aws-lambda/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 3764a792cf1e1..38ed6b3e43556 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -588,7 +588,7 @@ new lambda.Function(this, 'MyFunction', { architecture: lambda.Architecture.ARM_64, code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersion.V4, { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { cacheSize: 500, }), secrets: [secret], From f93ed5ba819b89125627d0876a893e46e430b8b3 Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 30 May 2023 08:30:14 -0700 Subject: [PATCH 41/49] created integ test for params and secrets Signed-off-by: Francis --- .../test/integ.params-and-secrets.ts | 58 +++++++++++++++++++ .../test/params-and-secrets-handler/index.py | 15 +++++ 2 files changed, 73 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.ts create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/params-and-secrets-handler/index.py 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..8dada3668fb34 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.ts @@ -0,0 +1,58 @@ +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', + 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', 'index.py')), + architecture: props.architecture, + paramsAndSecrets: { + layerVersion: ParamsAndSecretsLayerVersion.fromVersion(ParamsAndSecretsVersions.V4, { + + }), + 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, + }), + ], +}); 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..b26bc8a9caed8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/params-and-secrets-handler/index.py @@ -0,0 +1,15 @@ +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) + + # request to secrets manager + secrets_url = 'https://localhost:2773/secretsmanager/get?secretId=MySecret' + response = requests.get(secrets_url, headers=headers) From 9cd452e8330f7984ab4719200f749765bdfeec4f Mon Sep 17 00:00:00 2001 From: Francis Date: Tue, 30 May 2023 09:48:14 -0700 Subject: [PATCH 42/49] integ tests and snapshots Signed-off-by: Francis --- ...efaultTestDeployAssertE3E7D2A4.assets.json | 19 + ...aultTestDeployAssertE3E7D2A4.template.json | 36 + .../Stack1.assets.json | 32 + .../Stack1.template.json | 287 +++++++ .../Stack2.assets.json | 32 + .../Stack2.template.json | 260 +++++++ .../index.py | 19 + .../cdk.out | 1 + .../integ.json | 13 + .../manifest.json | 224 ++++++ .../tree.json | 705 ++++++++++++++++++ .../test/integ.params-and-secrets.ts | 10 +- .../test/params-and-secrets-handler/index.py | 4 + 13 files changed, 1639 insertions(+), 3 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack1.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack1.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack2.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/Stack2.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/asset.b375dfd7699947c404936c2d1c4a0b91bd2bb49158ce52f6064bda6d3a7e0ead/index.py create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.params-and-secrets.js.snapshot/tree.json 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..7b15434288272 --- /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}" + } + } + }, + "88abcb919a25e64c9c183e348b25ccf2e9c70f9a73dba583f333fb87f79328fd": { + "source": { + "path": "Stack1.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "88abcb919a25e64c9c183e348b25ccf2e9c70f9a73dba583f333fb87f79328fd.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..e9ea9d270a177 --- /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" + }, + "4xx86x64" + ] + } + ], + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "MyFuncServiceRoleDefaultPolicyF3C36699", + "MyFuncServiceRole54065130" + ] + } + }, + "Mappings": { + "ParamsandsecretslayerMap": { + "af-south-1": { + "4xx86x64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-east-1": { + "4xx86x64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-northeast-1": { + "4xx86x64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-northeast-2": { + "4xx86x64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-northeast-3": { + "4xx86x64": "arn:aws:lambda:ap-northeast-3:576959938190:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-south-1": { + "4xx86x64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-south-2": { + "4xx86x64": "arn:aws:lambda:ap-south-2:070087711984:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + }, + "ap-southeast-1": { + "4xx86x64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-southeast-2": { + "4xx86x64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ap-southeast-3": { + "4xx86x64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "ca-central-1": { + "4xx86x64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "cn-north-1": { + "4xx86x64": "arn:aws-cn:lambda:cn-north-1:287114880934:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "cn-northwest-1": { + "4xx86x64": "arn:aws-cn:lambda:cn-northwest-1:287310001119:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-central-1": { + "4xx86x64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-central-2": { + "4xx86x64": "arn:aws:lambda:eu-central-2:772501565639:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + }, + "eu-north-1": { + "4xx86x64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-south-1": { + "4xx86x64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-south-2": { + "4xx86x64": "arn:aws:lambda:eu-south-2:524103009944:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + }, + "eu-west-1": { + "4xx86x64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-west-2": { + "4xx86x64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "eu-west-3": { + "4xx86x64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "me-central-1": { + "4xx86x64": "arn:aws:lambda:me-central-1:858974508948:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "me-south-1": { + "4xx86x64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "sa-east-1": { + "4xx86x64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-east-1": { + "4xx86x64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-east-2": { + "4xx86x64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-gov-east-1": { + "4xx86x64": "arn:aws-us-gov:lambda:us-gov-east-1:129776340158:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-gov-west-1": { + "4xx86x64": "arn:aws-us-gov:lambda:us-gov-west-1:127562683043:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-west-1": { + "4xx86x64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + }, + "us-west-2": { + "4xx86x64": "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..a4eec47de3eb2 --- /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}" + } + } + }, + "6ac252791a555f4333e667beb0e9013036286601363be7a294f235586b140aed": { + "source": { + "path": "Stack2.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6ac252791a555f4333e667beb0e9013036286601363be7a294f235586b140aed.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..83001ddad1c2f --- /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" + }, + "4xarm64" + ] + } + ], + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "MyFuncServiceRoleDefaultPolicyF3C36699", + "MyFuncServiceRole54065130" + ] + } + }, + "Mappings": { + "ParamsandsecretslayerMap": { + "af-south-1": { + "4xarm64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ap-east-1": { + "4xarm64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ap-northeast-1": { + "4xarm64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-northeast-2": { + "4xarm64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ap-south-1": { + "4xarm64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-southeast-1": { + "4xarm64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-southeast-2": { + "4xarm64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "ap-southeast-3": { + "4xarm64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "ca-central-1": { + "4xarm64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "eu-central-1": { + "4xarm64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "eu-north-1": { + "4xarm64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "eu-south-1": { + "4xarm64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "eu-west-1": { + "4xarm64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "eu-west-2": { + "4xarm64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "eu-west-3": { + "4xarm64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "me-south-1": { + "4xarm64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "sa-east-1": { + "4xarm64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "us-east-1": { + "4xarm64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "us-east-2": { + "4xarm64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + }, + "us-west-1": { + "4xarm64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + }, + "us-west-2": { + "4xarm64": "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..8d74fb3f493c8 --- /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}/88abcb919a25e64c9c183e348b25ccf2e9c70f9a73dba583f333fb87f79328fd.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}/6ac252791a555f4333e667beb0e9013036286601363be7a294f235586b140aed.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..52bd3de7f5fa5 --- /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" + }, + "4xx86x64" + ] + } + ], + "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" + }, + "4xarm64" + ] + } + ], + "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 index 8dada3668fb34..a1285b94a2640 100644 --- 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 @@ -25,7 +25,7 @@ class StackUnderTest extends Stack { super(scope, id, props); const parameter = new StringParameter(this, 'Parameter', { - parameterName: 'email_url', + parameterName: `email_url_${id}`, stringValue: 'api.example.com', }); const secret = new Secret(this, 'MySecret'); @@ -33,11 +33,13 @@ class StackUnderTest extends Stack { new Function(this, 'MyFunc', { runtime: Runtime.NODEJS_18_X, handler: 'index.handler', - code: Code.fromAsset(path.join(__dirname, 'params-and-secrets-handler', 'index.py')), + code: Code.fromAsset(path.join(__dirname, 'params-and-secrets-handler')), architecture: props.architecture, paramsAndSecrets: { layerVersion: ParamsAndSecretsLayerVersion.fromVersion(ParamsAndSecretsVersions.V4, { - + cacheSize: 100, + secretsManagerTtl: cdk.Duration.seconds(100), + parameterStoreTtl: cdk.Duration.seconds(100), }), secrets: [secret], parameters: [parameter], @@ -56,3 +58,5 @@ new IntegTest(app, 'IntegTest', { }), ], }); + +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 index b26bc8a9caed8..6f90dffcb187b 100644 --- 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 @@ -9,7 +9,11 @@ def handler(event, context): # 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()}') From 22cab5dd2bf1a05929e0d8033b2be5cc45675d7f Mon Sep 17 00:00:00 2001 From: Francis Date: Thu, 1 Jun 2023 06:39:42 -0700 Subject: [PATCH 43/49] updated version to correctly use 1.0.103 Signed-off-by: Francis --- .../aws-lambda/lib/params-and-secrets-layers.ts | 4 ++-- .../aws-lambda/test/params-and-secrets.test.ts | 16 ++++++++-------- .../region-info/build-tools/fact-tables.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) 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 index 2aac7085282a5..c7c8f7d55106b 100644 --- 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 @@ -25,11 +25,11 @@ interface ParamsAndSecretsBindConfig { */ export enum ParamsAndSecretsVersions { /** - * V4 + * 1.0.103 * * Note: This is the latest version */ - V4 = '4', + V1_0_103 = '1.0.103', } /** 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 index 7b0869479ad85..a1980e613216c 100644 --- 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 @@ -102,7 +102,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }, }); @@ -138,7 +138,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }, }); @@ -151,7 +151,7 @@ describe('params and secrets', () => { { Ref: 'AWS::Region', }, - '4xx86x64', + '1x0x103xx86x64', ], }, ], @@ -185,7 +185,7 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }, }); @@ -222,7 +222,7 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }, }); @@ -235,7 +235,7 @@ describe('params and secrets', () => { { Ref: 'AWS::Region', }, - '4xarm64', + '1x0x103xarm64', ], }, ], @@ -268,7 +268,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4, { + layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103, { cacheEnabled: false, cacheSize: 500, httpPort: 8080, @@ -317,7 +317,7 @@ describe('params and secrets', () => { runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V4), + 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'); 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 47556ec263f1e..748e3582be7b1 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 @@ -548,7 +548,7 @@ export const FIREHOSE_CIDR_BLOCKS: { [region: string]: string } = { // 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 } } } = { - 4: { + '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', From c9275e1e944052ce206a728767562ef3609e2a0f Mon Sep 17 00:00:00 2001 From: Francis Date: Thu, 1 Jun 2023 07:01:26 -0700 Subject: [PATCH 44/49] updated integ test and snapshots for extension version 1.0.103 Signed-off-by: Francis --- .../Stack1.assets.json | 4 +- .../Stack1.template.json | 62 +++++++++---------- .../Stack2.assets.json | 4 +- .../Stack2.template.json | 44 ++++++------- .../manifest.json | 4 +- .../tree.json | 4 +- .../test/integ.params-and-secrets.ts | 2 +- .../lib/params-and-secrets-layers.ts | 2 +- 8 files changed, 63 insertions(+), 63 deletions(-) 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 index 7b15434288272..d9f0589909a65 100644 --- 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 @@ -14,7 +14,7 @@ } } }, - "88abcb919a25e64c9c183e348b25ccf2e9c70f9a73dba583f333fb87f79328fd": { + "64fb6d6ac3e1f7cda4cb6336b78f1be8f0e1f6c6323b232c8e04430a803085a2": { "source": { "path": "Stack1.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "88abcb919a25e64c9c183e348b25ccf2e9c70f9a73dba583f333fb87f79328fd.json", + "objectKey": "64fb6d6ac3e1f7cda4cb6336b78f1be8f0e1f6c6323b232c8e04430a803085a2.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } 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 index e9ea9d270a177..b9047a17d14cd 100644 --- 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 @@ -144,7 +144,7 @@ { "Ref": "AWS::Region" }, - "4xx86x64" + "1x0x103xx86x64" ] } ], @@ -159,94 +159,94 @@ "Mappings": { "ParamsandsecretslayerMap": { "af-south-1": { - "4xx86x64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-east-1": { - "4xx86x64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-northeast-1": { - "4xx86x64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-northeast-2": { - "4xx86x64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-northeast-3": { - "4xx86x64": "arn:aws:lambda:ap-northeast-3:576959938190:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-northeast-3:576959938190:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-south-1": { - "4xx86x64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-south-2": { - "4xx86x64": "arn:aws:lambda:ap-south-2:070087711984:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + "1x0x103xx86x64": "arn:aws:lambda:ap-south-2:070087711984:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" }, "ap-southeast-1": { - "4xx86x64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-southeast-2": { - "4xx86x64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ap-southeast-3": { - "4xx86x64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "ca-central-1": { - "4xx86x64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "cn-north-1": { - "4xx86x64": "arn:aws-cn:lambda:cn-north-1:287114880934:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws-cn:lambda:cn-north-1:287114880934:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "cn-northwest-1": { - "4xx86x64": "arn:aws-cn:lambda:cn-northwest-1:287310001119:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws-cn:lambda:cn-northwest-1:287310001119:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "eu-central-1": { - "4xx86x64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "eu-central-2": { - "4xx86x64": "arn:aws:lambda:eu-central-2:772501565639:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + "1x0x103xx86x64": "arn:aws:lambda:eu-central-2:772501565639:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" }, "eu-north-1": { - "4xx86x64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "eu-south-1": { - "4xx86x64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "eu-south-2": { - "4xx86x64": "arn:aws:lambda:eu-south-2:524103009944:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" + "1x0x103xx86x64": "arn:aws:lambda:eu-south-2:524103009944:layer:AWS-Parameters-and-Secrets-Lambda-Extension:1" }, "eu-west-1": { - "4xx86x64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "eu-west-2": { - "4xx86x64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "eu-west-3": { - "4xx86x64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "me-central-1": { - "4xx86x64": "arn:aws:lambda:me-central-1:858974508948:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:me-central-1:858974508948:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "me-south-1": { - "4xx86x64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "sa-east-1": { - "4xx86x64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "us-east-1": { - "4xx86x64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "us-east-2": { - "4xx86x64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "us-gov-east-1": { - "4xx86x64": "arn:aws-us-gov:lambda:us-gov-east-1:129776340158:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws-us-gov:lambda:us-gov-east-1:129776340158:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "us-gov-west-1": { - "4xx86x64": "arn:aws-us-gov:lambda:us-gov-west-1:127562683043:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws-us-gov:lambda:us-gov-west-1:127562683043:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "us-west-1": { - "4xx86x64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" }, "us-west-2": { - "4xx86x64": "arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" + "1x0x103xx86x64": "arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4" } } }, 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 index a4eec47de3eb2..c479d0cf31250 100644 --- 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 @@ -14,7 +14,7 @@ } } }, - "6ac252791a555f4333e667beb0e9013036286601363be7a294f235586b140aed": { + "6e1695d4618774814bd2b919c4dfbc4e9eee44fc0caea11b6c60b543848088a8": { "source": { "path": "Stack2.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "6ac252791a555f4333e667beb0e9013036286601363be7a294f235586b140aed.json", + "objectKey": "6e1695d4618774814bd2b919c4dfbc4e9eee44fc0caea11b6c60b543848088a8.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } 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 index 83001ddad1c2f..3394165ca5eb7 100644 --- 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 @@ -144,7 +144,7 @@ { "Ref": "AWS::Region" }, - "4xarm64" + "1x0x103xarm64" ] } ], @@ -159,67 +159,67 @@ "Mappings": { "ParamsandsecretslayerMap": { "af-south-1": { - "4xarm64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:af-south-1:317013901791:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "ap-east-1": { - "4xarm64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:ap-east-1:768336418462:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "ap-northeast-1": { - "4xarm64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:ap-northeast-1:133490724326:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "ap-northeast-2": { - "4xarm64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:ap-northeast-2:738900069198:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "ap-south-1": { - "4xarm64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:ap-south-1:176022468876:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "ap-southeast-1": { - "4xarm64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:ap-southeast-1:044395824272:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "ap-southeast-2": { - "4xarm64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:ap-southeast-2:665172237481:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "ap-southeast-3": { - "4xarm64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:ap-southeast-3:490737872127:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "ca-central-1": { - "4xarm64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:ca-central-1:200266452380:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "eu-central-1": { - "4xarm64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "eu-north-1": { - "4xarm64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:eu-north-1:427196147048:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "eu-south-1": { - "4xarm64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:eu-south-1:325218067255:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "eu-west-1": { - "4xarm64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "eu-west-2": { - "4xarm64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:eu-west-2:133256977650:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "eu-west-3": { - "4xarm64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:eu-west-3:780235371811:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "me-south-1": { - "4xarm64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:me-south-1:832021897121:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "sa-east-1": { - "4xarm64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:sa-east-1:933737806257:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "us-east-1": { - "4xarm64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "us-east-2": { - "4xarm64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:us-east-2:590474943231:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" }, "us-west-1": { - "4xarm64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" + "1x0x103xarm64": "arn:aws:lambda:us-west-1:997803712105:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:1" }, "us-west-2": { - "4xarm64": "arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" + "1x0x103xarm64": "arn:aws:lambda:us-west-2:345057560386:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:4" } } }, 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 index 8d74fb3f493c8..6d79bb48e4802 100644 --- 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 @@ -17,7 +17,7 @@ "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}/88abcb919a25e64c9c183e348b25ccf2e9c70f9a73dba583f333fb87f79328fd.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/64fb6d6ac3e1f7cda4cb6336b78f1be8f0e1f6c6323b232c8e04430a803085a2.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -100,7 +100,7 @@ "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}/6ac252791a555f4333e667beb0e9013036286601363be7a294f235586b140aed.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/6e1695d4618774814bd2b919c4dfbc4e9eee44fc0caea11b6c60b543848088a8.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ 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 index 52bd3de7f5fa5..85aa9315b3d14 100644 --- 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 @@ -263,7 +263,7 @@ { "Ref": "AWS::Region" }, - "4xx86x64" + "1x0x103xx86x64" ] } ], @@ -578,7 +578,7 @@ { "Ref": "AWS::Region" }, - "4xarm64" + "1x0x103xarm64" ] } ], 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 index a1285b94a2640..661eb7c17dad1 100644 --- 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 @@ -36,7 +36,7 @@ class StackUnderTest extends Stack { code: Code.fromAsset(path.join(__dirname, 'params-and-secrets-handler')), architecture: props.architecture, paramsAndSecrets: { - layerVersion: ParamsAndSecretsLayerVersion.fromVersion(ParamsAndSecretsVersions.V4, { + layerVersion: ParamsAndSecretsLayerVersion.fromVersion(ParamsAndSecretsVersions.V1_0_103, { cacheSize: 100, secretsManagerTtl: cdk.Duration.seconds(100), parameterStoreTtl: cdk.Duration.seconds(100), 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 index c7c8f7d55106b..95163eca02e3f 100644 --- 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 @@ -25,7 +25,7 @@ interface ParamsAndSecretsBindConfig { */ export enum ParamsAndSecretsVersions { /** - * 1.0.103 + * Version 1.0.103 * * Note: This is the latest version */ From 19f9cbba74487b1b28d3da1c33f5987311c87a9d Mon Sep 17 00:00:00 2001 From: Francis Date: Thu, 8 Jun 2023 11:35:52 -0700 Subject: [PATCH 45/49] empty commit to re-run integ tests Signed-off-by: Francis From 5cb363c3a7ffc5d3f1fd6cd35415eed0fd1f5308 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 9 Jun 2023 10:08:02 -0700 Subject: [PATCH 46/49] removed cyclic dependency Signed-off-by: Francis --- .../aws-lambda/lib/params-and-secrets-layers.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 95163eca02e3f..46cda5de1696e 100644 --- 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 @@ -1,9 +1,9 @@ import { Construct, IConstruct } from 'constructs'; +import { IFunction } from './function-base'; 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` @@ -187,7 +187,7 @@ export abstract class ParamsAndSecretsLayerVersion { */ public static fromVersionArn(arn: string, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { - public _bind(_scope: Construct, _fn: lambda.IFunction): ParamsAndSecretsBindConfig { + public _bind(_scope: Construct, _fn: IFunction): ParamsAndSecretsBindConfig { return { arn, environmentVars: this.environmentVariablesFromOptions, @@ -201,7 +201,7 @@ export abstract class ParamsAndSecretsLayerVersion { */ public static fromVersion(version: ParamsAndSecretsVersions, options: ParamsAndSecretsOptions = {}): ParamsAndSecretsLayerVersion { return new (class extends ParamsAndSecretsLayerVersion { - public _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig { + public _bind(scope: Construct, fn: IFunction): ParamsAndSecretsBindConfig { return { arn: this.getVersionArn(scope, version, fn.architecture.name), environmentVars: this.environmentVariablesFromOptions, @@ -217,7 +217,7 @@ export abstract class ParamsAndSecretsLayerVersion { * * @internal */ - public abstract _bind(scope: Construct, fn: lambda.IFunction): ParamsAndSecretsBindConfig; + public abstract _bind(scope: Construct, fn: IFunction): ParamsAndSecretsBindConfig; /** * Configure environment variables for Parameters and Secrets Extension based on configuration options From 4a3692b2a64edcf045df59e6cff19263afe73582 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 9 Jun 2023 15:35:43 -0700 Subject: [PATCH 47/49] removed dependency on secretsmanager and ssm - updated code and unit tests Signed-off-by: Francis --- packages/aws-cdk-lib/aws-lambda/README.md | 18 +- .../aws-cdk-lib/aws-lambda/lib/function.ts | 16 +- .../lib/params-and-secrets-layers.ts | 26 --- .../test/params-and-secrets.test.ts | 203 ++++++++---------- 4 files changed, 101 insertions(+), 162 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 287d1d620efac..3361c111fde16 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -597,19 +597,21 @@ const parameter = new ssm.StringParameter(stack, 'Parameter', { stringValue: 'mySsmParameterValue', }); -new lambda.Function(this, 'MyFunction', { +const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103, { + cacheSize: 500, + logLevel: lamabda.ParamsAndSecretsLogLevel.DEBUG, +}); + +const lambdaFunction = 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], - }, + paramsAndSecrets, }); + +secret.grantRead(lambdaFunction); +parameter.grantRead(lambdaFunction); ``` If the version of Parameters and Secrets Extension is not yet available in the CDK, you can also provide the ARN directly as so - diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index b23caea41c590..4e4826eeefd09 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -15,7 +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 { ParamsAndSecretsLayerVersion } from './params-and-secrets-layers'; import { Runtime } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; import { addAlias } from './util'; @@ -268,7 +268,7 @@ export interface FunctionOptions extends EventInvokeConfigOptions { * * @default - No Parameters and Secrets Extension */ - readonly paramsAndSecrets?: ParamsAndSecretsConfig; + readonly paramsAndSecrets?: ParamsAndSecretsLayerVersion; /** * A list of layers to add to the function's execution environment. You can configure your Lambda function to pull in @@ -1169,17 +1169,7 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett 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); + const layerVersion = props.paramsAndSecrets._bind(this, this); this.addLayers(LayerVersion.fromLayerVersionArn(this, 'ParamsAndSecretsLayer', layerVersion.arn)); Object.entries(layerVersion.environmentVars).forEach(([key, value]) => this.addEnvironment(key, value.toString())); } 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 index 46cda5de1696e..062bc20d43401 100644 --- 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 @@ -1,7 +1,5 @@ import { Construct, IConstruct } from 'constructs'; import { IFunction } from './function-base'; -import { ISecret } from '../../aws-secretsmanager'; -import { IParameter } from '../../aws-ssm'; import { Token, Stack, Duration } from '../../core'; import { RegionInfo, FactName } from '../../region-info'; @@ -151,30 +149,6 @@ export interface ParamsAndSecretsOptions { 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 */ 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 index a1980e613216c..2c4fdb8034df2 100644 --- 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 @@ -18,9 +18,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), }); // THEN @@ -48,6 +46,17 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = 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), + }); // WHEN new lambda.Function (stack, 'Function', { @@ -55,19 +64,7 @@ describe('params and secrets', () => { 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), - }), - }, + paramsAndSecrets, }); // THEN @@ -101,9 +98,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }); // THEN @@ -137,9 +132,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }); // THEN @@ -184,9 +177,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }); // THEN @@ -221,9 +212,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }); // THEN @@ -260,6 +249,17 @@ describe('params and secrets', () => { // GIVEN const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack', { env: { region: 'us-west-2' } }); + const paramsAndSecrets = 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), + }); // WHEN new lambda.Function (stack, 'Function', { @@ -267,19 +267,7 @@ describe('params and secrets', () => { 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), - }), - }, + paramsAndSecrets, }); // THEN @@ -316,9 +304,7 @@ describe('params and secrets', () => { handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, architecture: lambda.Architecture.ARM_64, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103), }); }).toThrow('Parameters and Secrets Extension is not supported in region eu-central-2 for arm64 architecture'); }); @@ -331,16 +317,14 @@ describe('params and secrets', () => { const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; // WHEN - new lambda.Function (stack, 'Function', { + const lambdaFunction = 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], - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), }); + secret.grantRead(lambdaFunction); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { @@ -410,16 +394,14 @@ describe('params and secrets', () => { const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; // WHEN - new lambda.Function (stack, 'Function', { + const lambdaFunction = 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], - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), }); + secret.grantRead(lambdaFunction); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { @@ -618,16 +600,14 @@ describe('params and secrets', () => { const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; // WHEN - new lambda.Function (stack, 'Function', { + const lambdaFunction = 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], - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), }); + parameter.grantRead(lambdaFunction); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { @@ -706,16 +686,14 @@ describe('params and secrets', () => { const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; // WHEN - new lambda.Function (stack, 'Function', { + const lambdaFunction = 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], - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), }); + parameter.grantRead(lambdaFunction); // THEN Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { @@ -821,30 +799,32 @@ describe('params and secrets', () => { // 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 secrets = [ + new sm.Secret(stack, 'Secret1'), + new sm.Secret(stack, 'Secret2'), + ]; + const parameters = [ + new ssm.StringParameter(stack, 'Parameter1', { + parameterName: 'name', + stringValue: 'value', + }), + 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', { + const lambdaFunction = 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], - }, + paramsAndSecrets: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn), }); + secrets.forEach(secret => secret.grantRead(lambdaFunction)); + parameters.forEach(parameter => parameter.grantRead(lambdaFunction)); // THEN Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { @@ -944,6 +924,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheSize: -1, + }); // WHEN/THEN expect(() => { @@ -952,11 +935,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { - cacheSize: -1, - }), - }, + paramsAndSecrets, }); }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: -1'); }); @@ -966,6 +945,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheSize: 1001, + }); // WHEN/THEN expect(() => { @@ -974,11 +956,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { - cacheSize: 1001, - }), - }, + paramsAndSecrets, }); }).toThrow('Cache size must be between 0 and 1000 inclusive - provided: 1001'); }); @@ -988,6 +966,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + httpPort: 0, + }); // WHEN/THEN expect(() => { @@ -996,11 +977,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { - httpPort: 0, - }), - }, + paramsAndSecrets, }); }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 0'); }); @@ -1010,6 +987,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + httpPort: 65536, + }); // WHEN/THEN expect(() => { @@ -1018,11 +998,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { - httpPort: 65536, - }), - }, + paramsAndSecrets, }); }).toThrow('HTTP port must be between 1 and 65535 inclusive - provided: 65536'); }); @@ -1032,6 +1008,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + maxConnections: 0, + }); // WHEN/THEN expect(() => { @@ -1040,11 +1019,7 @@ describe('params and secrets', () => { code: new lambda.InlineCode('foo'), handler: 'index.handler', runtime: lambda.Runtime.NODEJS_18_X, - paramsAndSecrets: { - layerVersion: lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { - maxConnections: 0, - }), - }, + paramsAndSecrets, }); }).toThrow('Maximum connections must be at least 1 - provided: 0'); }); @@ -1054,6 +1029,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + secretsManagerTtl: cdk.Duration.seconds(301), + }); // WHEN/THEN expect(() => { @@ -1062,11 +1040,7 @@ describe('params and secrets', () => { 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), - }), - }, + paramsAndSecrets, }); }).toThrow('Maximum TTL for a cached secret is 300 seconds - provided: 301 seconds'); }); @@ -1076,6 +1050,9 @@ describe('params and secrets', () => { 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'; + const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + parameterStoreTtl: cdk.Duration.seconds(301), + }); // WHEN/THEN expect(() => { @@ -1084,11 +1061,7 @@ describe('params and secrets', () => { 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), - }), - }, + paramsAndSecrets, }); }).toThrow('Maximum TTL for a cached parameter is 300 seconds - provided: 301 seconds'); }); From 765dc65c6351b492c9649f65d325986151710f13 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 9 Jun 2023 16:12:09 -0700 Subject: [PATCH 48/49] updated integ test code Signed-off-by: Francis --- .../test/integ.params-and-secrets.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) 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 index 661eb7c17dad1..8ecb2797c6b47 100644 --- 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 @@ -30,21 +30,22 @@ class StackUnderTest extends Stack { }); const secret = new Secret(this, 'MySecret'); - new Function(this, 'MyFunc', { + const paramsAndSecrets = ParamsAndSecretsLayerVersion.fromVersion(ParamsAndSecretsVersions.V1_0_103, { + cacheSize: 100, + secretsManagerTtl: cdk.Duration.seconds(100), + parameterStoreTtl: cdk.Duration.seconds(100), + }); + + const lambdaFunction = 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], - }, + paramsAndSecrets, }); + + secret.grantRead(lambdaFunction); + parameter.grantRead(lambdaFunction); } } From 7849d374dd3d1f239ddc359ac00a82a0ced30dc2 Mon Sep 17 00:00:00 2001 From: Francis Date: Fri, 9 Jun 2023 17:11:09 -0700 Subject: [PATCH 49/49] updated README to correctly display example of providing params and secrets ARN Signed-off-by: Francis --- packages/aws-cdk-lib/aws-lambda/README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 3361c111fde16..bf284c1e495c1 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -614,7 +614,7 @@ secret.grantRead(lambdaFunction); parameter.grantRead(lambdaFunction); ``` -If the version of Parameters and Secrets Extension is not yet available in the CDK, you can also provide the ARN directly as so - +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'; @@ -627,19 +627,20 @@ const parameter = new ssm.StringParameter(stack, 'Parameter', { }); const layerArn = 'arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:4'; -new lambda.Function(this, 'MyFunction', { +const paramsAndSecrets = lambda.ParamsAndSecretsLayerVersion.fromVersionArn(layerArn, { + cacheSize: 500, +}); + +const lambdaFunction = 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], - }, + paramsAndSecrets, }); + +secret.grantRead(lambdaFunction); +parameters.grantRead(lambdaFunction); ``` ## Event Rule Target