Skip to content

Commit ac9251c

Browse files
allen-moheimani-awsdanielmatukihnishar
authored
aws-lambda-secretsmanager (#162)
* docs: added README.md and architecture.png * feat(aws-lambda-secretsmanager): Updated documentation with code review changes requested * feat(aws-lambda-secretsmanager): Updated documentation with code review changes requested * feat(aws-lambda-secretsmanager): Created core helpers to provision secrets manager secret. * feat(aws-lambda-secretsmanager): Fixed double quotes in import * feat(aws-lambda-secretsmanager): Fixed double quotes in import * implemented lib/index.ts; added ignore files; added package.json * fixed naming * feat(aws-lambda-secretsmanager): Implementation changes, integration tests, and unit tests * feat(aws-lambda-secretsmanager): Added missing snapshot * feat(aws-lambda-secretsmanager): Updated documentation and test snapshots. * feat(aws-lambda-secretsmanager): Updated documentation and test snapshots. * suppressed warning on build * docs: added README.md and architecture.png * implemented lib/index.ts; added ignore files; added package.json * feat(aws-lambda-secretsmanager): Updated documentation with code review changes requested * feat(aws-lambda-secretsmanager): Created core helpers to provision secrets manager secret. * feat(aws-lambda-secretsmanager): Fixed double quotes in import * feat(aws-lambda-secretsmanager): Fixed double quotes in import * fixed naming * feat(aws-lambda-secretsmanager): Implementation changes, integration tests, and unit tests * feat(aws-lambda-secretsmanager): Added missing snapshot * feat(aws-lambda-secretsmanager): Updated documentation and test snapshots. * feat(aws-lambda-secretsmanager): Updated documentation and test snapshots. * suppressed warning on build * feedback from PR * fixed failing test * feat(aws-lambda-secretsmanager): code review fixes. * feat(aws-lambda-secretsmanager): unit test code review fixes. * updated removal policy for tests to destroy the secret upon stack deletion * feat(aws-lambda-secretsmanager): Updated unit tests snapshot * feat(aws-lambda-secretsmanager): Updates to utilize secret ARN instead of name. * feat(aws-lambda-secretsmanager): Included unit test to override the secretProps and validate the KMS key permissions. * feat(aws-lambda-secretsmanager): Included viper light ignore for unit test. Co-authored-by: Daniel Matuki da Cunha <[email protected]> Co-authored-by: Daniel Matuki da Cunha <[email protected]> Co-authored-by: Hitendra Nishar <[email protected]>
1 parent c36b752 commit ac9251c

26 files changed

+3665
-1
lines changed

Diff for: .viperlightignore

+1
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ source/patterns/@aws-solutions-constructs/core/test/cloudfront-distribution-s3-h
3636
source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/test.s3-sqs.test.ts:251
3737
source/use_cases/aws-custom-glue-etl/stream-producer/generate_data.py:86
3838
source/use_cases/aws-custom-glue-etl/stream-producer/generate_data.py:87
39+
source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager/test/lambda-secretsmanager.test.ts:481
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
lib/*.js
2+
test/*.js
3+
*.d.ts
4+
coverage
5+
test/lambda/index.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
lib/*.js
2+
test/*.js
3+
*.js.map
4+
*.d.ts
5+
node_modules
6+
*.generated.ts
7+
dist
8+
.jsii
9+
10+
.LAST_BUILD
11+
.nyc_output
12+
coverage
13+
.nycrc
14+
.LAST_PACKAGE
15+
*.snk
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Exclude typescript source and config
2+
*.ts
3+
tsconfig.json
4+
coverage
5+
.nyc_output
6+
*.tgz
7+
*.snk
8+
*.tsbuildinfo
9+
10+
# Include javascript files and typescript declarations
11+
!*.js
12+
!*.d.ts
13+
14+
# Exclude jsii outdir
15+
dist
16+
17+
# Include .jsii
18+
!.jsii
19+
20+
# Include .jsii
21+
!.jsii
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# aws-lambda-secretsmanager module
2+
<!--BEGIN STABILITY BANNER-->
3+
4+
---
5+
6+
![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge)
7+
8+
> All classes are under active development and subject to non-backward compatible changes or removal in any
9+
> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model.
10+
> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package.
11+
12+
---
13+
<!--END STABILITY BANNER-->
14+
15+
| **Reference Documentation**:| <span style="font-weight: normal">https://docs.aws.amazon.com/solutions/latest/constructs/</span>|
16+
|:-------------|:-------------|
17+
<div style="height:8px"></div>
18+
19+
| **Language** | **Package** |
20+
|:-------------|-----------------|
21+
|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_lambda_secretsmanager`|
22+
|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-lambda-secretsmanager`|
23+
|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.lambdasecretsmanager`|
24+
25+
This AWS Solutions Construct implements the AWS Lambda function and AWS Secrets Manager secret with the least privileged permissions.
26+
27+
Here is a minimal deployable pattern definition in Typescript:
28+
29+
``` javascript
30+
const { LambdaToSecretsmanagerProps, LambdaToSecretsmanager } from '@aws-solutions-constructs/aws-lambda-secretsmanager';
31+
32+
const props: LambdaToSecretsmanagerProps = {
33+
lambdaFunctionProps: {
34+
runtime: lambda.Runtime.NODEJS_14_X,
35+
// This assumes a handler function in lib/lambda/index.js
36+
code: lambda.Code.fromAsset(`${__dirname}/lambda`),
37+
handler: 'index.handler'
38+
},
39+
};
40+
41+
new LambdaToSecretsmanager(this, 'test-lambda-secretsmanager-stack', props);
42+
43+
```
44+
45+
## Initializer
46+
47+
``` text
48+
new LambdaToSecretsmanager(scope: Construct, id: string, props: LambdaToSecretsmanagerProps);
49+
```
50+
51+
_Parameters_
52+
53+
* scope [`Construct`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Construct.html)
54+
* id `string`
55+
* props [`LambdaToSecretsmanagerProps`](#pattern-construct-props)
56+
57+
## Pattern Construct Props
58+
59+
| **Name** | **Type** | **Description** |
60+
|:-------------|:----------------|-----------------|
61+
|existingLambdaObj?|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Existing instance of Lambda Function object, if this is set then the lambdaFunctionProps is ignored.|
62+
|lambdaFunctionProps?|[`lambda.FunctionProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.FunctionProps.html)|User provided props to override the default props for the Lambda function.|
63+
|secretProps?|[`secretsmanager.SecretProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.SecretProps.html)|Optional user provided props to override the default props for Secrets Manager|
64+
|existingSecretObj?|[`secretsmanager.Secret`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html)|Existing instance of Secrets Manager Secret object, If this is set then the secretProps is ignored|
65+
|grantWriteAccess?|`boolean`|Optional write access to the Secret for the Lambda function (Read-Only by default)
66+
|secretEnvironmentVariableName?|`string`|Optional Name for the Secrets Manager secret environment variable set for the Lambda function.|
67+
|existingVpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|An optional, existing VPC into which this pattern should be deployed. When deployed in a VPC, the Lambda function will use ENIs in the VPC to access network resources and an Interface Endpoint will be created in the VPC for AWS Secrets Manager. If an existing VPC is provided, the `deployVpc` property cannot be `true`. This uses `ec2.IVpc` to allow clients to supply VPCs that exist outside the stack using the [`ec2.Vpc.fromLookup()`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Vpc.html#static-fromwbrlookupscope-id-options) method.|
68+
|vpcProps?|[`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html)|Optional user-provided properties to override the default properties for the new VPC. `enableDnsHostnames`, `enableDnsSupport`, `natGateways` and `subnetConfiguration` are set by the pattern, so any values for those properties supplied here will be overrriden. If `deployVpc` is not `true` then this property will be ignored.|
69+
|deployVpc?|`boolean`|Whether to create a new VPC based on `vpcProps` into which to deploy this pattern. Setting this to true will deploy the minimal, most private VPC to run the pattern:<ul><li> One isolated subnet in each Availability Zone used by the CDK program</li><li>`enableDnsHostnames` and `enableDnsSupport` will both be set to true</li></ul>If this property is `true` then `existingVpc` cannot be specified. Defaults to `false`.|
70+
71+
## Pattern Properties
72+
73+
| **Name** | **Type** | **Description** |
74+
|:-------------|:----------------|-----------------|
75+
|lambdaFunction|[`lambda.Function`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)|Returns an instance of lambda.Function created by the construct|
76+
|secret|[`secretsmanager.Secret`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html)|Returns an instance of secretsmanager.Secret created by the construct|
77+
|vpc?|[`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html)|Returns an interface on the VPC used by the pattern (if any). This may be a VPC created by the pattern or the VPC supplied to the pattern constructor.|
78+
79+
## Default settings
80+
81+
Out of the box implementation of the Construct without any override will set the following defaults:
82+
83+
### AWS Lambda Function
84+
* Configure limited privilege access IAM role for Lambda function
85+
* Enable reusing connections with Keep-Alive for NodeJs Lambda function
86+
* Enable X-Ray Tracing
87+
* Set Environment Variables
88+
* (default) SECRET_ARN containing the ARN of the secret as return by CDK [secretArn property](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-secretsmanager.Secret.html#secretarn).
89+
* AWS_NODEJS_CONNECTION_REUSE_ENABLED (for Node 10.x and higher functions)
90+
91+
### Amazon SecretsManager Secret
92+
* Enable read-only access for the associated AWS Lambda Function
93+
* Enable server-side encryption using a default KMS key for the account and region
94+
* Creates a new Secret
95+
* (default) random name
96+
* (default) random value
97+
* Retain the Secret when deleting the CloudFormation stack
98+
99+
## Architecture
100+
![Architecture Diagram](architecture.png)
101+
102+
***
103+
&copy; Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
5+
* with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
10+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*/
13+
14+
// Imports
15+
import * as defaults from "@aws-solutions-constructs/core";
16+
import * as lambda from "@aws-cdk/aws-lambda";
17+
import * as secretsmanager from "@aws-cdk/aws-secretsmanager";
18+
import * as ec2 from "@aws-cdk/aws-ec2";
19+
import { Construct } from "@aws-cdk/core";
20+
21+
/**
22+
* @summary The properties for the LambdaToSecretsmanager class.
23+
*/
24+
export interface LambdaToSecretsmanagerProps {
25+
/**
26+
* Existing instance of Lambda Function object, if this is set then the lambdaFunctionProps is ignored.
27+
*
28+
* @default - None
29+
*/
30+
readonly existingLambdaObj?: lambda.Function;
31+
/**
32+
* User provided props to override the default props for the Lambda function.
33+
*
34+
* @default - Default properties are used.
35+
*/
36+
readonly lambdaFunctionProps?: lambda.FunctionProps;
37+
/**
38+
* Existing instance of Secret object, if this is set then secretProps is ignored.
39+
*
40+
* @default - Default props are used
41+
*/
42+
readonly existingSecretObj?: secretsmanager.Secret;
43+
/**
44+
* Optional user-provided props to override the default props for the Secret.
45+
*
46+
* @default - Default props are used
47+
*/
48+
readonly secretProps?: secretsmanager.SecretProps;
49+
/**
50+
* An existing VPC for the construct to use (construct will NOT create a new VPC in this case)
51+
*/
52+
readonly existingVpc?: ec2.IVpc;
53+
/**
54+
* Properties to override default properties if deployVpc is true
55+
*/
56+
readonly vpcProps?: ec2.VpcProps;
57+
/**
58+
* Whether to deploy a new VPC
59+
*
60+
* @default - false
61+
*/
62+
readonly deployVpc?: boolean;
63+
/**
64+
* Optional Name for the Secret environment variable set for the Lambda function.
65+
*
66+
* @default - SECRET_NAME
67+
*/
68+
readonly secretEnvironmentVariableName?: string;
69+
/**
70+
* Optional secret permissions to grant to the Lambda function.
71+
* One of the following may be specified: "Read" or "ReadWrite".
72+
*
73+
* @default - Read only acess is given to the Lambda function if no value is specified.
74+
*/
75+
readonly grantWriteAccess?: string;
76+
}
77+
78+
/**
79+
* @summary The LambdaToSecretsmanager class.
80+
*/
81+
export class LambdaToSecretsmanager extends Construct {
82+
public readonly lambdaFunction: lambda.Function;
83+
public readonly secret: secretsmanager.Secret;
84+
public readonly vpc?: ec2.IVpc;
85+
86+
/**
87+
* @summary Constructs a new instance of the LambdaToSecretsmanager class.
88+
* @param {cdk.App} scope - represents the scope for all the resources.
89+
* @param {string} id - this is a a scope-unique id.
90+
* @param {LambdaToSecretsmanagerProps} props - user provided props for the construct.
91+
* @access public
92+
*/
93+
constructor(scope: Construct, id: string, props: LambdaToSecretsmanagerProps) {
94+
super(scope, id);
95+
96+
if (props.deployVpc || props.existingVpc) {
97+
if (props.deployVpc && props.existingVpc) {
98+
throw new Error("More than 1 VPC specified in the properties");
99+
}
100+
101+
this.vpc = defaults.buildVpc(scope, {
102+
defaultVpcProps: defaults.DefaultIsolatedVpcProps(),
103+
existingVpc: props.existingVpc,
104+
userVpcProps: props.vpcProps,
105+
constructVpcProps: {
106+
enableDnsHostnames: true,
107+
enableDnsSupport: true,
108+
},
109+
});
110+
111+
defaults.AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.SECRETS_MANAGER);
112+
}
113+
114+
// Setup the Lambda function
115+
this.lambdaFunction = defaults.buildLambdaFunction(this, {
116+
existingLambdaObj: props.existingLambdaObj,
117+
lambdaFunctionProps: props.lambdaFunctionProps,
118+
vpc: this.vpc,
119+
});
120+
121+
// Setup the Secret
122+
if (props.existingSecretObj) {
123+
this.secret = props.existingSecretObj;
124+
} else {
125+
this.secret = defaults.buildSecretsManagerSecret(this, 'secret', props.secretProps);
126+
}
127+
128+
// Configure environment variables
129+
const secretEnvironmentVariableName = props.secretEnvironmentVariableName || 'SECRET_ARN';
130+
this.lambdaFunction.addEnvironment(secretEnvironmentVariableName, this.secret.secretArn);
131+
132+
// Enable read permissions for the Lambda function by default
133+
this.secret.grantRead(this.lambdaFunction);
134+
135+
if (props.grantWriteAccess === 'ReadWrite') {
136+
this.secret.grantWrite(this.lambdaFunction);
137+
}
138+
}
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"name": "@aws-solutions-constructs/aws-lambda-secretsmanager",
3+
"version": "0.0.0",
4+
"description": "CDK constructs for defining an interaction between an AWS Lambda function and AWS Secrets Manager.",
5+
"main": "lib/index.js",
6+
"types": "lib/index.d.ts",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/awslabs/aws-solutions-constructs.git",
10+
"directory": "source/patterns/@aws-solutions-constructs/aws-lambda-secretsmanager"
11+
},
12+
"author": {
13+
"name": "Amazon Web Services",
14+
"url": "https://aws.amazon.com",
15+
"organization": true
16+
},
17+
"license": "Apache-2.0",
18+
"scripts": {
19+
"build": "tsc -b .",
20+
"lint": "eslint -c ../eslintrc.yml --ext=.js,.ts . && tslint --project .",
21+
"lint-fix": "eslint -c ../eslintrc.yml --ext=.js,.ts --fix .",
22+
"test": "jest --coverage",
23+
"clean": "tsc -b --clean",
24+
"watch": "tsc -b -w",
25+
"integ": "cdk-integ",
26+
"integ-assert": "cdk-integ-assert",
27+
"integ-no-clean": "cdk-integ --no-clean",
28+
"jsii": "jsii",
29+
"jsii-pacmak": "jsii-pacmak",
30+
"build+lint+test": "npm run jsii && npm run lint && npm test && npm run integ-assert",
31+
"snapshot-update": "npm run jsii && npm test -- -u && npm run integ-assert"
32+
},
33+
"jsii": {
34+
"outdir": "dist",
35+
"targets": {
36+
"java": {
37+
"package": "software.amazon.awsconstructs.services.lambdasecretsmanager",
38+
"maven": {
39+
"groupId": "software.amazon.awsconstructs",
40+
"artifactId": "lambdasecretsmanager"
41+
}
42+
},
43+
"dotnet": {
44+
"namespace": "Amazon.Constructs.AWS.LambdaSecretsManager",
45+
"packageId": "Amazon.Constructs.AWS.LambdaSecretsManager",
46+
"signAssembly": true,
47+
"iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png"
48+
},
49+
"python": {
50+
"distName": "aws-solutions-constructs.aws-lambda-secretsmanager",
51+
"module": "aws_solutions_constructs.aws_lambda_secretsmanager"
52+
}
53+
}
54+
},
55+
"dependencies": {
56+
"@aws-cdk/aws-ec2": "0.0.0",
57+
"@aws-cdk/aws-lambda": "0.0.0",
58+
"@aws-cdk/aws-secretsmanager": "0.0.0",
59+
"@aws-cdk/core": "0.0.0",
60+
"@aws-solutions-constructs/core": "0.0.0",
61+
"constructs": "^3.2.0"
62+
},
63+
"devDependencies": {
64+
"@aws-cdk/assert": "0.0.0",
65+
"@types/jest": "^24.0.23",
66+
"@types/node": "^10.3.0"
67+
},
68+
"jest": {
69+
"moduleFileExtensions": [
70+
"js"
71+
]
72+
},
73+
"peerDependencies": {
74+
"@aws-cdk/aws-ec2": "0.0.0",
75+
"@aws-cdk/aws-lambda": "0.0.0",
76+
"@aws-cdk/aws-secretsmanager": "0.0.0",
77+
"@aws-cdk/core": "0.0.0",
78+
"@aws-solutions-constructs/core": "0.0.0",
79+
"constructs": "^3.2.0"
80+
}
81+
}

0 commit comments

Comments
 (0)