diff --git a/packages/aws-cdk-lib/custom-resources/README.md b/packages/aws-cdk-lib/custom-resources/README.md index 940e6303e0e83..b36075ac9199c 100644 --- a/packages/aws-cdk-lib/custom-resources/README.md +++ b/packages/aws-cdk-lib/custom-resources/README.md @@ -387,6 +387,27 @@ const myProvider = new cr.Provider(this, 'MyProvider', { ``` +### Customizing Provider Function environment encryption key + +Sometimes it may be useful to manually set a AWS KMS key for the Provider Function Lambda and therefore +be able to view, manage and audit the key usage. + +```ts +declare const onEvent: lambda.Function; +declare const isComplete: lambda.Function; +declare const myRole: iam.Role; + +const key = new kms.Key(this, 'MyKey'); +const myProvider = new cr.Provider(this, 'MyProvider', { + onEventHandler: onEvent, + isCompleteHandler: isComplete, + logRetention: logs.RetentionDays.ONE_DAY, + role: myRole, + providerFunctionEnvEncryption: key, // Optional +}); + +``` + ## Custom Resources for AWS APIs Sometimes a single API call can fill the gap in the CloudFormation coverage. In diff --git a/packages/aws-cdk-lib/custom-resources/lib/provider-framework/provider.ts b/packages/aws-cdk-lib/custom-resources/lib/provider-framework/provider.ts index d9e28da32dcaa..a0690b3d5055e 100644 --- a/packages/aws-cdk-lib/custom-resources/lib/provider-framework/provider.ts +++ b/packages/aws-cdk-lib/custom-resources/lib/provider-framework/provider.ts @@ -6,6 +6,7 @@ import { WaiterStateMachine } from './waiter-state-machine'; import { CustomResourceProviderConfig, ICustomResourceProvider } from '../../../aws-cloudformation'; import * as ec2 from '../../../aws-ec2'; import * as iam from '../../../aws-iam'; +import * as kms from '../../../aws-kms'; import * as lambda from '../../../aws-lambda'; import * as logs from '../../../aws-logs'; import { Duration } from '../../../core'; @@ -118,6 +119,13 @@ export interface ProviderProps { * @default - CloudFormation default name from unique physical ID */ readonly providerFunctionName?: string; + + /** + * AWS KMS key used to encrypt provider lambda's environment variables. + * + * @default - AWS Lambda creates and uses an AWS managed customer master key (CMK) + */ + readonly providerFunctionEnvEncryption?: kms.IKey; } /** @@ -149,6 +157,7 @@ export class Provider extends Construct implements ICustomResourceProvider { private readonly vpcSubnets?: ec2.SubnetSelection; private readonly securityGroups?: ec2.ISecurityGroup[]; private readonly role?: iam.IRole; + private readonly providerFunctionEnvEncryption?: kms.IKey; constructor(scope: Construct, id: string, props: ProviderProps) { super(scope, id); @@ -167,6 +176,7 @@ export class Provider extends Construct implements ICustomResourceProvider { this.securityGroups = props.securityGroups; this.role = props.role; + this.providerFunctionEnvEncryption = props.providerFunctionEnvEncryption; const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME, props.providerFunctionName); @@ -216,6 +226,7 @@ export class Provider extends Construct implements ICustomResourceProvider { securityGroups: this.securityGroups, role: this.role, functionName: name, + environmentEncryption: this.providerFunctionEnvEncryption, }); fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn); diff --git a/packages/aws-cdk-lib/custom-resources/test/provider-framework/provider.test.ts b/packages/aws-cdk-lib/custom-resources/test/provider-framework/provider.test.ts index 0a69d13b1f0ce..aa164cb5fa1d0 100644 --- a/packages/aws-cdk-lib/custom-resources/test/provider-framework/provider.test.ts +++ b/packages/aws-cdk-lib/custom-resources/test/provider-framework/provider.test.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import { Template } from '../../../assertions'; import * as ec2 from '../../../aws-ec2'; import * as iam from '../../../aws-iam'; +import * as kms from '../../../aws-kms'; import * as lambda from '../../../aws-lambda'; import * as logs from '../../../aws-logs'; import { Duration, Stack } from '../../../core'; @@ -419,3 +420,33 @@ describe('name', () => { }); }); }); + +describe('environment encryption', () => { + it('uses custom KMS key for environment encryption when present', () => { + // GIVEN + const stack = new Stack(); + const key: kms.IKey = new kms.Key(stack, 'EnvVarEncryptKey', { + description: 'sample key', + }); + + // WHEN + new cr.Provider(stack, 'MyProvider', { + onEventHandler: new lambda.Function(stack, 'MyHandler', { + code: lambda.Code.fromAsset(path.join(__dirname, './integration-test-fixtures/s3-file-handler')), + handler: 'index.onEvent', + runtime: lambda.Runtime.NODEJS_14_X, + }), + providerFunctionEnvEncryption: key, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + KmsKeyArn: { + 'Fn::GetAtt': [ + 'EnvVarEncryptKey1A7CABDB', + 'Arn', + ], + }, + }); + }); +});