How to securely use secrets in AWS Lambda functions with AWS Lambda Powertools

How to securely use secrets in AWS Lambda functions with AWS Lambda Powertools

·

10 min read

AWS Lambda functions are typically the main compute service used in serverless architectures in AWS. You can write your serverless application in your choice of several different supported languages (Python and TypeScript to name a few) and not need to worry about managing the infrastructure. But one thing you will still need to manage is the secure handling of secrets for use in your serverless application.

Your Lambda function may need to use secret values in some scenarios such as:

  • Using database credentials to connect to a database.

  • Using API keys to perform authorized calls to an API endpoint.

  • Using encryption keys to encrypt or decrypt sensitive data.

When handling secret values in your Lambda functions, you should avoid having these visible as plain text anywhere (in your code, configuration files or environment variables). Fortunately, AWS provides several services for you to store secret values which can be accessible from your AWS Lambda functions. The two that I would like to cover in this blog post are:

  • AWS Systems Manager (SSM) Parameter Store (Secure String)

  • AWS Secrets Manager

Your Lambda function code will need a small amount of additions to retrieve secrets from these services. This is easy to achieve by using AWS Lambda Powertools. Continue reading to see how this can be done!

Comparing AWS SSM Parameter Store (Secure String) with AWS Secrets Manager

The first decision to make is which AWS service to use to store your secrets. Your secrets will then need to be retrieved from the service by you Lambda functions. To help you decide, the table below gives a comparison between AWS Systems Manager SSM Parameter Store (Secure String) and AWS Secrets Manager.

AWS SSM Parameter Store (Secure String)AWS Secrets Manager
High level service descriptionKey value store for application configuration. The SecureString parameter type can be used to store sensitive data.Purpose built for secrets management and rotation.
Encryption at restYes - using AWS Key Management ServiceYes - using AWS Key Management Service
Encryption in transitYes - HTTPS (TLS) connection to AWS Systems Manager API endpoint.Yes - HTTPS (TLS) connection to AWS Secrets Manager API endpoint.
CostsLower - Standard types only charges for higher API call throughput. Advances types charges per parameter per month and per API call.Higher - Charges per secret per month and per API call.
Data max sizeStandard: 4 KB, Advanced: 8 KB64 KB
Built-in secret rotationNoYes - managed secrets rotation for Aurora, ECS, RDS and Redshift. Also rotation using Lambda functions with AWS or community provided templates or build your own.
VersioningYes - Version history and version labelsYes - Version stage labels for current, previous and pending. Custom version labels. Versions have unique IDs.
Access auditingYes - with AWS CloudTrailYes - with AWS CloudTrail

Generally, if you need to perform regular rotation of your secrets, I would recommend using AWS Secrets Manager and taking advantage of secret rotation features. In most all other cases, I would otherwise recommend using to AWS SSM Parameter Store Secure String to keep costs low.

Using SSM Parameter Store Secure Strings in AWS Lambda functions

Create a SSM Parameter Store Secure String

You can create a SSM Parameter Store Store Secure String to store your secret values from the AWS Systems Manager Parameter Console (https://console.aws.amazon.com/systems-manager/parameters) with the following steps:

  1. Choose Create Parameter.

  2. Provide a Name (e.g. /examples/lambda/secret) and optional Description.

  3. Under Type, select SecureString.

  4. For simplicity, under KMS key source select My current account then under KMS Key ID select alias/aws/ssm.

  5. In the Value box, enter you secret value in the Value (e.g. EXAMPLE-SECRET-VALUE).

  6. Complete the create of the parameter by choosing Create parameter.

The below image shows an example creation of a parameter named /examples/lambda/ssm-param-secret.

Create the Lambda function to retrieve the SSM Parameter Store Secure String

We will next create a Lambda function that uses AWS Lambda Powertools Parameters utility to retrieve the secret value from the SSM Parameter Secure String. AWS Lambda Powertools is available for Python, TypeScript, Java and .NET. For reference, below are links to the Parameters utility documentation for each language:

In this example we will use the Python 3.12 runtime. The Python runtime has AWS Lambda Powertools available as a public Lambda Layer which saves us from having to provide the python package ourselves.

Create a new Lambda function from the AWS Lambda function console (https://console.aws.amazon.com/lambda) with the following steps:

  1. Choose Create function.

  2. Select Author from scratch.

  3. Provide a Function name (e.g. example-ssm-param-securestring-usage)

  4. Under Runtime select Python 3.12.

  5. Under Architecture select x86_64.

  6. Leave all other settings as default then choose Create function.

The below image shows the creation of a Lambda function with the name example-ssm-param-securestring-usage.

To add the AWS Lambda Powertools Lambda Layer, in the created Lambda function, under Code tab, in the Layers section (scroll to the bottom), choose Add a layer.

Under Layer source select AWS layers, then under AWS layers select the latest version of “AWSLambdaPowertoolsPython”.

The image below shows adding the layer with the latest version being “AWSLambdaPowertoolsPythonV3-python312” Version 3.

We need to provide the Lambda function execution role with read access to the SSM Parameter Store Secure String. To do this use the following steps:

  1. In your Lambda function, under the Configuration tab, in the Execution role section under Role name, choose the role. This should open the default created Lambda function execution role in the Identity and Access Management (IAM) console.

  2. In the Permissions policies section, choose Add permissions then Create inline policy.

  3. In the Specify permissions step, in the Policy editor section choose JSON and paste the following policy. In the Resources field, change {Region}, {Account} to your own appropriate values. Change /examples/lambda/ssm-param-secret to you SSM parameter name if different.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter"
            ],
            "Resource": [
                "arn:aws:ssm:{Region}:{Account}:parameter/examples/lambda/ssm-param-secret"
            ]
        }
    ]
}
  1. Choose Next then in the Review and create step provide a Policy name (e.g. SSMParametersRead) then choose Create policy.

Your Lambda function execution role should look something like the image below:

Sample code using Python

Back to your Lambda function, under the Code tab, in the Code source section, enter the following Python code snippet.

from aws_lambda_powertools.utilities import parameters

def lambda_handler(event, context):
    secret_value = parameters.get_parameter("/examples/lambda/ssm-param-secret", decrypt=True)
    print(f"SSM Parameter Secure String example retrieval: {secret_value}")
    return {
        'statusCode': 200,
        'body': "Successfully retrieved SSM Parameter Secure String"
    }

On line 4 is the use of the AWS Lambda Powertools utility function parameters.get_parameter(). In this function, you can provide name of you SSM Parameter Store Secure String as the first argument (e.g. "/examples/lambda/ssm-param-secret"). The named argument of decrypt=True should also be provided so that the output parameter value is decrypted.

Choose the Deploy then Test with any test event payload.

The example code demonstrates how you can retrieve secret values from SSM Parameter Store Secure String with a few lines of code. You will see the decrypted secret value (i.e. EXAMPLE-SECRET-VALUE) printed out in the function logs as a result of the print() function. Obviously, you should not be printing or logging secret value in your production environments.

Sample code using TypeScript

Below is sample TypeScript code for retrieving a SSM Parameter Secure String. It is the equivalent of the Python example above.

import { getParameter } from '@aws-lambda-powertools/parameters/ssm';

export const handler = async (event) => {
  const secret_value = await getParameter('/examples/lambda/ssm-param-secret', {decrypt: true});
  console.log(`SSM Parameter Secure String example retrieval: ${secret_value}`);
  const response = {
    statusCode: 200,
    body: JSON.stringify('Successfully retrieved SSM Parameter Secure String'),
  };
  return response;
};

Using AWS Secrets Manager secret in AWS Lambda functions

Create a new secret in AWS Secrets Manager

You can create a new secret in AWS Secrets Manager to store you secrets from the AWS Secrets Manager Console (https://console.aws.amazon.com/secretsmanager) with the following instructions:

  1. Choose Store a new secret.

  2. In the Secret type section, select Other type of secret.

  3. In the Key/value pairs section provide key name (e.g. ExampleSecret) and your secret value as the value (e.g. EXAMPLE-SECRET-VALUE)

  4. For simplicity, in the the Encryption key section, select aws/secretsmanager. Then choose Next.

  5. In the Secret name and description section provide a Secret name (e.g. /examples/secret-manager/lambda/secret) and a optional Description. Then choose Next.

  6. In the Configure rotation - optional step choose Next.

  7. In the Review step choose Store.

After creating the secret, take note of the Secret ARN. This will be needed later in your Lambda function execution role policy.

Create the Lambda function to retrieve the Secrets Manager secret

Retrieving secrets from AWS Secrets Manager in the Lambda function is very similar to retrieving fromSSM Parameter Store. AWS Lambda Powertools Parameter utility can also be used to retrieve secrets from Secrets Manager.

Create a new Lambda function using the Python runtime with a new name (e.g. example-secrets-manager-secret-usage) and with AWS Lambda Powertools Lambda Layer using the same steps in Create the Lambda function to retrieve the SSM Parameter Secure String.

To provide the Lambda function with access to retrieve the secret from Secrets Manager, add the following inline policy (example name SecretsManagerRead) to the Lambda function execution role. Replace {SecretARN} with your secret ARN.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "{SecretARN}"
        }
    ]
}

Your Lambda function execution IAM role should like the image below.

Sample code using Python

In your Lambda function, under the Code tab, in the Code source section, enter the following Python code snippet.

from aws_lambda_powertools.utilities import parameters
import json

def lambda_handler(event, context):
    secret_object = parameters.get_secret("/examples/secret-manager/lambda/secret")
    secret_value = json.loads(secret_object)["ExampleSecret"]
    print(f"Secrets Manager secret example retrieval: {secret_value}")
    return {
        'statusCode': 200,
        'body': "Successfully retrieved Secrets Manager secret"
    }

On line 4 is the use of the AWS Lambda Powertools utility function parameters.get_secret(). In this function, you provide the name of your Secrets Manager secret (e.g. /examples/secret-manager/lambda-secret) as the argument. Unlike the parameters.get_parameter() function for retrieving SSM Parameters, there is no decrypt argument. The function will return the decrypted secret value without it.

Another thing to point out is that the secret is stored as a JSON string in Secrets Manager (due to creating it using the AWS Console). The json python module is used to load the JSON string in to a Python dictionary where we can then obtain the secret value by providing the key name (.e.g. ExampleSecret).

Choose the Deploy then Test with any test event payload.

The example code is very similar to the SSM Parameter Secure String example. You will see the decrypted secret value (i.e. EXAMPLE-SECRET-VALUE) printed out in the function logs as a result of the print() function.

Sample code using TypeScript

Below is sample TypeScript code for retrieving a Secrets Manager secret. It is the equivalent of the Python example above.

import { getSecret } from '@aws-lambda-powertools/parameters/secrets';

export const handler = async (event) => {
  const secret_object = await getSecret('/examples/secret-manager/lambda/secret');
  let secret_value = JSON.parse(secret_object).ExampleSecret;
  console.log(`Secrets Manager secret example retrieval: ${secret_value}`);
  const response = {
    statusCode: 200,
    body: JSON.stringify('Successfully retrieved Secrets Manager secret'),
  };
  return response;
};

Summary

Hopefully this blow posts shows how easy it is to use secrets in AWS Lambda functions using AWS Lambda Powertools Parameters and few lines of code.

For AWS lambda functions using the Python runtime, you can use the AWS Lambda Powertools Parameters utility with:

from aws_lambda_powertools.utilities import parameters
  • You can use AWS SSM Parameter Store Secure String to store you secret values then use the function parameters.get_parameter("YOUR_PARAM_NAME", decrypt=True) to retrieve them.

  • You can use AWS Secrets Manager secret to store your secret values then use the function parameters.get_secret(“YOUR_SECRET_NAME”) to retrieve them.

For AWS Lambda functions using TypeScript (NodeJS) runtime, you can use the AWS Lambda Powertools Parameters utility with:

import { getParameter } from '@aws-lambda-powertools/parameters/ssm';
import { getSecret } from '@aws-lambda-powertools/parameters/secrets';
  • You can use AWS SSM Parameter Store Secure String to store you secret values then use the function await getParameter("YOUR_PARAM_NAME", {decrypt: true}) to retrieve them.

  • You can use AWS Secrets Manager secret to store your secret values then use the function await getSecret(“YOUR_SECRET_NAME”) to retrieve them.

AWS Lambda Powertools with the Parameters utility is also available for Java and .NET.