How to get Secrets Manager Values in AWS CDK

avatar

Borislav Hadzhiev

Last updated: Apr 14, 2022

banner

Photo from Unsplash

Getting Secrets Manager Values in AWS CDK #

The AWS Secrets Manager service allows us to store, manage and rotate secrets that we need to use to access databases, APIs, etc.

For the purposes of this demo I'll create a secret using the AWS CLI:

shell
aws secretsmanager create-secret --name databasePassword \ --description "The password for a database" \ --secret-string "dogsandcats123"

If we look at the Secrets manager console, we can see that the secret has been provisioned:

secrets manager console

Getting Secret Manager Values by Secret Name in CDK #

The easiest way to get a Secrets Manager value in AWS CDK is via the fromSecretNameV2 static method on the Secret construct.

The code for this article is available on GitHub

I'll provision a CDK stack, consisting of a single Lambda function and I'll pass the secret to the Lambda as an environment variable:

lib/cdk-starter-stack.ts
import * as lambda from 'aws-cdk-lib/aws-lambda'; import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs'; import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); // 👇 get access to the secret object const dbPasswordSecret = secretsmanager.Secret.fromSecretNameV2( this, 'db-pwd-id', 'databasePassword', ); const myFunction = new NodejsFunction(this, 'my-function', { // 👇 set secret value as ENV variable environment: { SECRET_NAME: dbPasswordSecret.secretName, SECRET_VALUE: dbPasswordSecret.secretValue.toString(), }, runtime: lambda.Runtime.NODEJS_16_X, memorySize: 1024, timeout: cdk.Duration.seconds(5), handler: 'main', entry: path.join(__dirname, `/../src/my-lambda/index.js`), }); } }
If you still use CDK version 1, switch to the cdk-v1 branch in the GitHub repository.

The code of the lambda function could be as simple as:

src/my-lambda/index.js
async function main(event) { console.log('SECRET_NAME 👉', process.env.SECRET_NAME); console.log('SECRET_VALUE 👉', process.env.SECRET_VALUE); return {body: JSON.stringify({message: 'SUCCESS'}), statusCode: 200}; }

In the code snippet we invoked the fromSecretNameV2 static method on the Secret construct to get access to the object that represents a Secrets Manager secret.

The fromSecretNameV2 static method takes 3 parameters:

  1. the scope in which the method is invoked
  2. the id of the secret in the construct tree
  3. the name of the secret

We also defined a Lambda function and passed it two environment variables - SECRET_NAME and SECRET_VALUE.

I'll now deploy the CDK stack:

shell
npx aws-cdk deploy

Next, I'll invoke the Lambda function by using the Test functionality in the Lambda console. If we look at the log output from the lambda invocation we can see that we successfully accessed the Secrets Manager value:

lambda secret logs

Getting Secret Manager values by Secret ARN in CDK #

The most flexible way to get Secrets Manager values by ARN is using the fromSecretAttributes method on the Secret construct.

lib/cdk-starter-stack.ts
import * as lambda from 'aws-cdk-lib/aws-lambda'; import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs'; import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; import * as cdk from 'aws-cdk-lib'; import * as path from 'path'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps) { super(scope, id, props); // 👇 get secret by partial ARN const dbPasswordSecret = secretsmanager.Secret.fromSecretAttributes( this, 'db-pwd-id', { secretPartialArn: 'arn:aws:secretsmanager:us-east-1:123456789:secret:databasePassword', }, ); const myFunction = new NodejsFunction(this, 'my-function', { // 👇 set secret value as ENV variable environment: { SECRET_NAME: dbPasswordSecret.secretName, SECRET_VALUE: dbPasswordSecret.secretValue.toString(), }, runtime: lambda.Runtime.NODEJS_16_X, memorySize: 1024, timeout: cdk.Duration.seconds(5), handler: 'main', entry: path.join(__dirname, `/../src/my-lambda/index.js`), }); } }

In the code snippet we used the fromSecretAttributes static method to get the Secret value. The method takes 3 parameters:

  1. the scope in which the method is invoked
  2. the id of the imported Secret in the construct tree
  3. an attributes object, which has 3 properties:
    • secretPartialArn - the ARN of the secret, without the 6 character Secrets Manager suffix
    • secretCompleteArn - the complete ARN of the secret, including the 6 character Secrets Manager suffix
    • encryptionKey - the encryption key used to encrypt the secret, in case we don't use the default Secrets Manager key

Get Secrets Manager Value by ARN - Alternative #

A more direct approach to get a Secrets Manager value by ARN is to use the fromSecretCompleteArn or fromSecretPartialArn static methods on the Secret class.

The complete arn includes the 6 character suffix added by the secrets manager service, whereas the partial arn does not.

An example of using the fromSecretPartialArn static method looks like:

lib/cdk-starter-stack.ts
const dbPasswordSecret = secretsmanager.Secret.fromSecretPartialArn( this, 'db-pwd-id', 'arn:aws:secretsmanager:us-east-1:123456789:secret:databasePassword', );

The third parameter the function takes is the partial arn of the Secret.

Here is an example of using the fromSecretCompleteArn static method:

lib/cdk-starter-stack.ts
const dbPasswordSecret = secretsmanager.Secret.fromSecretCompleteArn( this, 'db-pwd-id', 'arn:aws:secretsmanager:us-east-1:123456789:secret:databasePassword-bmst1b', );

The third parameter the function takes is the complete Secret ARN with the 6 character suffix.

If we try to synth a stack, where we didn't provide the complete arn, with the 6 character suffix to fromSecretCompleteArn we get an error:

Error: secretCompleteArn does not appear to be complete; missing 6-character suffix

complete arn error

Clean up #

In order to delete a secret using the AWS CLI, we can issue the delete-secret command:

shell
aws secretsmanager delete-secret \ --secret-id databasePassword \ --recovery-window-in-days 7

Where the --secret-id flag can be either the ARN of the secret or the secret's name.

Further Reading #

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.