Using the AWS Parameters and Secrets Lambda Extension to retrieve a secret value

Given that it is considered insecure to store a secret value as a Lambda environment variable, a possible solution is to store it in AWS Secrets Manager and programmatically access it as needed. There is however a cost for every retrieval of the secret value from AWS Secrets Manager. To reduce such costs, we can make use of the AWS Parameters and Secrets Lambda Extension. We effectively apply it as a lambda layer and invoke an API endpoint to obtain the secret value.

The steps to do so are listed at https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html

  1. Add it as a lambda layer. You need to find the specific ARN for your region in which your lambda resides. For eu-central-1, it's arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:12.

List of ARNs: https://docs.aws.amazon.com/systems-manager/latest/userguide/ps-integration-lambda-extensions.html#ps-integration-lambda-extensions-add

resource "aws_lambda_function" "lambda" { 
  function_name = var.lambda_function_name
  role          = aws_iam_role.lambda_exec.arn
  handler       = "index.handler"
  ...
 
  layers = ["arn:aws:lambda:eu-central-1:187925254637:layer:AWS-Parameters-and-Secrets-Lambda-Extension:12"]
}        

2. Add the secretsmanager:GetSecretValue permission on the secret(s) (that you have created in AWS Secrets Manager) to the lambda executor role.

resource "aws_iam_role" "lambda_exec" {
  name = "${var.lambda_function_name}-executor"
  ...
  inline_policy {
    name   = "${var.lambda_function_name}-lambda-executor-policy-secrets"
    policy = data.aws_iam_policy_document.secrets.json
  }
}
 
data "aws_iam_policy_document" "secrets" {
  statement {
    actions   = ["secretsmanager:GetSecretValue"]
    resources = var.secrets_arns
  }
}        

3. Refactor your code to retrieve the secret value using the extension. The following example uses the default extension settings.

const getSecretValue = async (secretName: string) => {
    const url = `https://localhost:2773/secretsmanager/get?secretId=${secretName}`
    const response = await fetch(url, {
        method: 'GET',
        headers: {
            'X-Aws-Parameters-Secrets-Token': process.env.AWS_SESSION_TOKEN!,
        },
    });
 
    if (response.ok) {
        const data = await response.json()
        return data.SecretString
    } else {
        throw new Error(`Failed to retrieve secret ${secretName}`)
    }
}        

4. If you are using SSM Parameter Store instead, you will need to provide the kms:Decrypt permission (assuming you are using SecureString) in addition to ssm:GetParameter

const getParameterValue = async (parameterName: string, isSecureString: boolean) => {
    const url = `https://localhost:2773/systemsmanager/parameters/get?name=${parameterName}&withDecryption=${isSecureString}`
   const response = await fetch(url, {
      method: 'GET',
      headers: {
          'X-Aws-Parameters-Secrets-Token': process.env.AWS_SESSION_TOKEN!
      }
   })

  if (response.ok) {
     const data = await response.json()
     return data.Parameter.Value
  } else {
    throw new Error(`Failed to retrieve parameter ${parameterName}`)
  }
}        





要查看或添加评论,请登录

William Ku的更多文章

社区洞察

其他会员也浏览了