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
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}`)
}
}