简体   繁体   中英

Pass AWS SM Secret Key to Lambda Environment with CDK

I am having some trouble getting a specific Secrets Manager Secret key value to pass it to my lambda through CDK.

After some time I finally realized that my SecretValue is only resolved when I actually deploy this to lambda, and not while running local through SAM CLI. By doing

cdk.SecretValue.secretsManager(secretId).toString()

I get something like "{\"apiKey\":\"sdfsdf-sdfsdf-sddsf\"}" , but I want to rather have the apiKey directly. Unfortunately, in my CDK code, I cannot JSON:parse(...secretsManager(..).toString()) as this will only be resolved once deployed. Before, the value is simply: {{resolve:secretsmanager:apiKey:SecretString:::}} (which seems to be a Token: https://docs.aws.amazon.com/cdk/latest/guide/tokens.html )

So I guess I would need some way to tell CDK how to use the rendered value, maybe by passing a callback that transforms the rendered result - is that possible? Are there any other tools I can use in my CDK setup that allow me to receive a specific key from a secret so that I can pass it to lambda directly?

I hope the problem is understandable. Thanks in advance for your help.

You need to use Secret . You can use any of the static from methods to get the secret. From there you can use the secretValueFromJson method to get the value.

Example (secret for Postgres db):

    import * as secretsmanager from '@aws-cdk/aws-secretsmanager';

    const dbSecret = secretsmanager.Secret.fromSecretNameV2(this, 'db-secret', 'db-secret-name');
    const dbUser = dbSecret.secretValueFromJson('username').toString();
    const dbPass = dbSecret.secretValueFromJson('password').toString();
    const dbName = dbSecret.secretValueFromJson('dbname').toString();

in 2022

Using .toString() on Secrets seems no longer accepted without calling .unsafeUnwrap() first. As far as the documentation goes:

If you don't call this method, using the secret value directly in a string context or as a property value somewhere will produce an error.

For me, it produced the error on cdk deploy :

Resolution error: Synthing a secret value to Resources(...) Using a SecretValue here risks exposing your secret. Only pass SecretValues to constructs that accept a SecretValue property, or call AWS Secrets Manager directly in your runtime code. Call 'secretValue.unsafeUnwrap()' if you understand and accept the risks..

Solution

  1. as the message suggests try to use frameworks, which accept a SecretValue, or if you don't have the chance (as in my case I am trying to use Prisma, and it doesn't accept it yet )

  2. use .unsafeUnwrap() . Like:

const getValueFromSecret = (secret: ISecret, key: string): string => {
  return secret.secretValueFromJson(key).unsafeUnwrap()
}

// usage (e.g. in Lambda stack)
const password = getValueFromSecret(secret, 'password')

I solved this for Parameter Store with AWS SDK, here's an extract from my stack.ts:

import { SSM } from 'aws-sdk'

const ssmSDK = new SSM()

async function fetchParam(name: string): Promise<string> {
  try {
    const param = await ssmSDK
      .getParameter({
        Name: name,
        WithDecryption: true,
      })
      .promise()
    if (!param.Parameter || !param.Parameter.Value) {
      throw new Error(`${name} parameter not found!`)
    }
    return param.Parameter.Value
  } catch (err) {
    throw new Error(`failed to fetch ${name} parameter!`)
  }
}

export async function buildSearchServiceStack(
  scope: cdk.App,
  id: string,
  props?: cdk.StackProps
): Promise<cdk.Stack> {
  const stack = new cdk.Stack(scope, id, props)

  const [jwtSecret, elasticPassword] = await Promise.all([
    fetchParam(`/shared/jwt/SECRET`),
    fetchParam('/shared/elasticsearch/URL')])
// ..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM