AWS Secrets Manager: Tutorial & best practices
AWS Secrets Manager vs KMS: Differences & synergies
AWS Secrets Manager vs. Parameter Store: Features, cost & more
AWS CLI Secrets Manager: In-depth tutorial with examples
AWS Secrets Manager with Terraform: Tutorial & examples
AWS KMS key rotation: Tutorial & best practices
AWS Secrets Manager for Kubernetes: Tutorial & best practices
AWS Secrets Manager alternatives: A comprehensive analysis
AWS Lambda Secrets Manager best practices
AWS Vault: Tutorial, best practices & limitations
AWS CDK Secrets Manager tutorial & best practices
SSM Parameter Store: Tutorial & best practices
Secrets management is a vital part of building robust cloud applications as it helps improve your applications' security by keeping sensitive information safe. AWS Secrets Manager is a popular tool for securing sensitive data such as API keys, tokens, database credentials, and passwords. With secret rotation, access control, and optional auditing capabilities, AWS Secrets Manager can help manage secrets throughout their lifecycle.
This article demonstrates how you can leverage Secrets Manager with AWS Cloud Development Kit (CDK), an open-source software development framework, to model and provision your AWS infrastructure as code. We will detail how to use AWS CDK to provision and reference secrets in Secrets Manager. We will also review other AWS CDK secrets manager options, like Parameter Store, and how integration with third-party tools can help improve secret AWS CDK secrets manager workflows.
The table below summarizes the key concepts that will be covered in this article.
AWS CDK provides construct libraries for handling secrets and parameters using Secrets Manager and Parameter Store. Let’s take a quick look at the common use cases for secrets and parameters in a CDK project.
Some of the commonly used secrets in CDK projects are:
Some of the common parameters used along with CDK are:
Now that we’ve gone through the common secrets and parameters used in CDK, let’s learn how we can use CDK to provision and retrieve these secrets in your project.
We will use the TypeScript CDK construct libraries to provision Secret Manager and SSM Parameter Store resources.
To provision Secret Manager using AWS CDK, you must include the aws-cdk-lib/aws-secretsmanager module in your CDK project.
The following example demonstrates how to create a Secret Manager secret for database credentials.
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
4
5export class SecretManagerCdkStack extends cdk.Stack {
6 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
7 super(scope, id, props);
8
9 // Secret Manager Credentials
10 const secret = new secretsmanager.Secret(this, 'SampleSecret', {
11 secretName: '/stage/credentials',
12 generateSecretString: {
13 secretStringTemplate: JSON.stringify({ username: 'admin' }),
14 generateStringKey: 'password',
15 },
16 });
17 }
18}
To create a Secret Manager store with a custom KMS encryption key, use the following code:
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
4import * as kms from 'aws-cdk-lib/aws-kms';
5
6export class SecretManagerCdkStack extends cdk.Stack {
7 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
8 super(scope, id, props);
9 // KMS Key
10 const key = kms.Key.fromKeyArn(this, 'secretManagerKey', 'arn:aws:kms:ap-south-1:126345658785:key/8cd94c7e-ef37-4423-9bf7-2b0642fab0ef');
11
12 // Secret Manager Credentials
13 const secret = new secretsmanager.Secret(this, 'SampleSecret', {
14 secretName: '/stage/credentials',
15 generateSecretString: {
16 secretStringTemplate: JSON.stringify({ username: 'admin' }),
17 generateStringKey: 'password',
18 },
19 encryptionKey: key,
20 });
21 }
22}
To create a Secret Manager store for use cases such as API keys, use the following code:
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
4
5export class SecretManagerCdkStack extends cdk.Stack {
6 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
7 super(scope, id, props);
8
9 // Secret Manager API Key
10 const apiKey = new secretsmanager.Secret(this, 'SampleApiKey', {
11 secretName: '/stage/api-key',
12 generateSecretString: {
13 secretStringTemplate: JSON.stringify({ apiKey: 'asdasdasd' }),
14 generateStringKey: 'apiKey',
15 },
16 });
17 }
18}
For the purpose of this article, let’s look at how we can inject the new Secret Manager value into a Lambda function:
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
4
5export class SecretManagerCdkStack extends cdk.Stack {
6 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
7 super(scope, id, props);
8
9 // Secret Manager API Key
10 const apiKey = new secretsmanager.Secret(this, 'SampleApiKey', {
11 secretName: '/stage/api-key',
12 generateSecretString: {
13 secretStringTemplate: JSON.stringify({ apiKey: 'asdasdasd' }),
14 generateStringKey: 'apiKey',
15 },
16 });
17
18 // Associate Secret Manager with Lambda
19 const sampleLambda = new lambda.Function(this, 'SampleLambda', {
20 runtime: lambda.Runtime.NODEJS_18_X,
21 handler: 'index.handler',
22 code: lambda.Code.fromInline(`exports.handler = async (event) => { console.log("Hello World"); return { statusCode: 200, body: JSON.stringify('Hello from Lambda!') }; };`),
23 environment: {
24 API_KEY_ID: apiKey.secretValue.unsafeUnwrap().toString(), // This is not recommended
25 },
26 });
27 }
28}
Note that for security purposes, it is recommended to retrieve the secret at Lambda runtime logic to avoid exposing the secret in the CloudFormation template. For this, pass the secret ARN as an environment variable to the lambda function instead of passing the secret value directly.
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
4
5export class SecretManagerCdkStack extends cdk.Stack {
6 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
7 super(scope, id, props);
8
9 // Secret Manager API Key
10 const apiKey = new secretsmanager.Secret(this, 'SampleApiKey', {
11 secretName: '/stage/api-key',
12 generateSecretString: {
13 secretStringTemplate: JSON.stringify({ apiKey: 'asdasdasd' }),
14 generateStringKey: 'apiKey',
15 },
16 });
17
18 // Associate Secret Manager with Lambda
19 const sampleLambda = new lambda.Function(this, 'SampleLambda', {
20 runtime: lambda.Runtime.NODEJS_18_X,
21 handler: 'index.handler',
22 code: lambda.Code.fromInline(`exports.handler = async (event) => { console.log("Hello World"); return { statusCode: 200, body: JSON.stringify('Hello from Lambda!') }; };`),
23 environment: {
24 API_KEY_ID: apiKey.secretArn // Note that we’re passing the secret ARN here
25 },
26 });
27 }
28}
To retrieve an existing Secret Manager secret in your CDK project using the Secret Manager ARN, use the following code:
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
4import * as lambda from 'aws-cdk-lib/aws-lambda';
5
6export class SecretManagerCdkStack extends cdk.Stack {
7 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
8 super(scope, id, props);
9
10 // Secret Manager secretKey
11 const secretKey = secretsmanager.Secret.fromSecretCompleteArn(this, 'secretKey', 'arn:aws:secretsmanager:ap-south-1:1234567895:secret:prod/secretKey-2pUG9Y');
12
13 // Associate Secret Manager with Lambda
14 const sampleLambda = new lambda.Function(this, 'SampleLambda', {
15 runtime: lambda.Runtime.NODEJS_18_X,
16 handler: 'index.handler',
17 code: lambda.Code.fromInline(`exports.handler = async (event) => { console.log("Hello World"); return { statusCode: 200, body: JSON.stringify('Hello from Lambda!') }; };`),
18 environment: {
19 API_KEY_ID: secretKey.secretValue.unsafeUnwrap().toString(), // This is not recommended
20 },
21 });
22 }
23}
To provision Parameter Store with the AWS CDK, include the aws-cdk-lib/aws-ssm module in your CDK project.
The following example demonstrates how you can create an SSM Parameter Store:
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as ssm from 'aws-cdk-lib/aws-ssm';
4
5export class SecretManagerCdkStack extends cdk.Stack {
6 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
7 super(scope, id, props);
8
9 // Parameter Store
10 const sampleStore = new ssm.StringParameter(this, 'SecretKey', {
11 parameterName: '/sample/secretvalue',
12 stringValue: 'asdasadas',
13 description: 'Sample secret value',
14 tier: ssm.ParameterTier.STANDARD,
15 });
16 }
17}
To inject a Parameter Store value into a Lambda function, use the following code:
1import * as cdk from 'aws-cdk-lib';
2import { Construct } from 'constructs';
3import * as ssm from 'aws-cdk-lib/aws-ssm';
4
5export class SecretManagerCdkStack extends cdk.Stack {
6 constructor(scope: Construct, id: string, props?: cdk.StackProps) {
7 super(scope, id, props);
8
9 // Parameter Store
10 const sampleStore = new ssm.StringParameter(this, 'SecretKey', {
11 parameterName: '/sample/secretvalue',
12 stringValue: 'asdasadas',
13 description: 'Sample secret value',
14 tier: ssm.ParameterTier.STANDARD,
15 });
16
17 // Associate Secret Manager with Lambda
18 const sampleLambda = new lambda.Function(this, 'SampleLambda', {
19 runtime: lambda.Runtime.NODEJS_18_X,
20 handler: 'index.handler',
21 code: lambda.Code.fromInline(`exports.handler = async (event) => { console.log("Hello World"); return { statusCode: 200, body: JSON.stringify('Hello from Lambda!') }; };`),
22 environment: {
23 SECRET_VALUE: sampleStore.stringValue, // This is not recommended
24 },
25 });
26 }
27}
Similar to the Secrets Manager example mentioned above, using this method is not recommended for security reasons as it can expose the secret value. Instead, pass the secret ARN as an environment variable to the lambda function so that you can fetch the secret during runtime.
To learn more about which secret management solution suits your use case and to understand the difference between them, follow this detailed AWS guide by Doppler.
AWS CDK faces the following limitations when it comes to secret management using Secrets Manager and Parameter Store in CDK projects:
Doppler is a third-party secrets management tool that can integrate with AWS CDK and address the limitations mentioned above. Doppler provides a user-friendly platform for managing secrets, configurations, and credentials. It can enhance the CDK development experience in the following ways:
While AWS CDK can lay the foundation for infrastructure as code in your projects, it’s essential to acknowledge the limitations within CDK when it comes to handling secrets effectively. Challenges such as dependency management between CDK projects, external secret rotation, limited support for secret types, and the absence of built-in auditing and logging capabilities can introduce complexities and hinder a productive development experience. Integrating Doppler with AWS CDK can significantly enhance the secrets management experience in your projects. Developers can mitigate these limitations by leveraging Doppler’s more efficient, secure, and agile solution for managing secrets and configurations in their AWS environments.
Trusted by the world’s best DevOps and security teams. Doppler is the secrets manager developers love.
Please confirm your cookie preferences. You can change your selection at any time by clicking on the "Cookie Preferences" button in the footer of every page.