AWS

How to Rotate Secrets with AWS Secret Manager and Lambda?

In the digital landscape, securing digital assets such as database credentials, OAuth tokens, API keys, etc is one of the major concerns of IT experts. AWS Secret Manager allows users to protect the digital assets required to access the applications, resources, and services. These digital assets are known as “Secrets”.

AWS Secret Manager strengthens the security of the application by allowing users to create, store, manage, rotate, modify, and replicate the secrets. Secret Manager can be integrated with other services to access the resources. It continuously audits, monitors quickly detects those secrets that do not meet the compliance requirements.

Quick Outline

This article illustrates the following aspects:

What is Auto Rotating of Secrets in AWS Secret Manager?

Rotation is the process of updating the value of the secret periodically. The secrets will be rotated at the scheduled time provided by the user. When the secret is rotated, the current value of the secret is replaced by a random string provided by the AWS Secret Manager. The services utilizing the secret will now use the updated value of the secret.

How Does Rotation Work in Secret Manager?

Secret Manager uses the Lambda Function to rotate secrets. For this purpose, the Lambda Function will be invoked at the scheduled time for rotating the secrets. The Lambda Function will acquire the value of the secret specified in the code. This value will be then replaced by a random string. There is only one rotation function that can update the value of the secret. This rotation function cannot invoke the nested Lambda functions for the rotation of the secrets. The rotation of the secrets consists of four steps:

New Version of the Secret

In the first rotation, a new version of the secret is created with the label “AWSPENDING”. This new version of the secret follows the exact format as the user-specified key-value pair. The only difference is that the value is updated to any new password, username, etc as specified in the previous key-value pair.

Update Credentials

In the second rotation, the value of the secret will be updated for all the services that require it. For Database services except Oracle, Secure Socket Layer (SSL) or Transport Layer Security (TLS) is used by the Rotation Function for connecting to databases.

Test New Credentials

The credentials labeled as “AWSPENDING” will be used to access the database or service in order to determine if the credentials are updated successfully or not. The rotation function uses the read access for testing the new secrets.

Finish

In the final rotation, the secret’s label will be updated to “AWSCURRENT” from “AWSPENDING”. Similarly, the previous value of the secret will be labeled as “AWSPREVIOUS” in order to maintain the versions.

How to Rotate Secrets With AWS Secret Manager And Lambda?

To rotate secrets with the AWS Secret Manager, below are the steps mentioned:

Step 1: Create a Secret

Visit the Console of AWS Secret Manager by searching it in the search bar of AWS and then selecting it:

On the Secret Manager Console, click the “Store a new secret” button:

In the “Secret type” section, there are several options to create a secret i.e. user can store different Database credentials such as RDS, Redshift, etc. Furthermore, Secret Manager can also be used to store and retrieve API keys, OAuth tokens, etc. As we are creating an API Secret, therefore select the “Other type of secret” option from the different options displayed:

Next comes the “Key/value pairs” section. In this block, the user is required to provide a unique key and its value whose value is to be rotated later. Here, provide a key-value pair in the highlighted text field under the “Key/value” section. Similarly, AWS provides a default encryption method but users can also enable encryption through the customer-managed key. For this demo, select the default settings:

After providing the key and configuring the encryption settings, click on the “Next” button at the bottom of the interface:

Next, provide a unique name for our secret in the “Secret name” text field:

By keeping the remaining settings as default, tap the “Next” button to proceed further:

On the next interface, toggle the Automatic Rotation button to enable this feature. For the moment, we are not enabling it and creating the Lambda Function first:

Keeping the defaults, click on the “Next” button:

In the last step of creating an API secret, the user can review the information provided and edit it in case of incorrect information. After that, click on the “Store” button to create and store the secret:

Reload the interface and the secret has been created successfully. Choose the secret from the AWS Secret Manager dashboard:

Step 2: Create a Lambda Function

The next step is to create a Lambda Function. For this purpose, search the “Lambda” service in the AWS Management Console. Click on the service’s name from the results displayed:

Click on the “Create function” button displayed on the Lambda’s interface:

By clicking on the “Create function” option, Lambda’s interface will open in a new tab. From the displayed interface, select the “Author from scratch” option to create the Lambda function:

Next comes the “Basic information” section. Provide the name for the function in the “Function name” text field. For the Runtime, select the “Python 3.9” option:

Read more: How to Create a Lambda Function With Python Runtime

Click on the “Create function” button by keeping the rest of the settings as default:

The Lambda Function has been successfully created as indicated by the confirmation message from the AWS:

Navigate to the “Code source” section on the interface. Replace the existing code with the following code:

import boto3

def lambda_handler(event, context):
    ARN = event['SecretId']
    token = event['ClientRequestToken']
    step = event['Step']

    # Setup the client
    service_client = boto3.client('secretsmanager')

    # Make sure the version is staged correctly
    metadata = service_client.describe_secret(SecretId=ARN)
    if not metadata['RotationEnabled']:
        raise ValueError("Secret %s is not enabled for rotation" % ARN)
   
    if step == "createSecret":
        create_secret(service_client, ARN, token)

    elif step == "setSecret":
        set_secret(service_client, ARN, token)

    elif step == "testSecret":
        test_secret(service_client, ARN, token)

    elif step == "finishSecret":
        finish_secret(service_client, ARN, token)

    else:
        raise ValueError("Invalid step parameter")


def create_secret(service_client, ARN, token):

    service_client.get_secret_value(SecretId=ARN, VersionStage="AWSCURRENT")

    # Now try to get the secret version, if that fails, put a new secret
    try:
        service_client.get_secret_value(SecretId=ARN, VersionId=token, VersionStage="AWSPENDING")
    except service_client.exceptions.ResourceNotFoundException:
        # Generate a random password
        passwd = service_client.get_random_password(ExcludeCharacters='/@"\'\')
        # Put the secret
        service_client.put_secret_value(SecretId=ARN, ClientRequestToken=token, SecretString=passwd['
RandomPassword'], VersionStages=['AWSPENDING'])


def set_secret(service_client, ARN, token):
    print("No database user credentials to update...")


def test_secret(service_client, ARN, token):
    print("No need to testing against any service...")


def finish_secret(service_client, ARN, token):
   
    # First describe the secret to get the current version
    metadata = service_client.describe_secret(SecretId=ARN)

    for version in metadata["VersionIdsToStages"]:
        if "AWSCURRENT" in metadata["VersionIdsToStages"][version]:
            if version == token:
                # The correct version is already marked as current, return
                return

            # Finalize by staging the secret version current
            service_client.update_secret_version_stage(SecretId=ARN, VersionStage="AWSCURRENT", MoveToVersionId=token, RemoveFromVersionId=version)
            break

To apply and save changes to the function, click on the “Deploy” button:

Step 3: Create an IAM Policy

For this Lambda function to rotate the secrets, there are certain permissions that are required to be configured. For this purpose, click on the “Configurations” tab on the Lambda Interface:

Click on the “Permissions” tab from the left sidebar. Under the Execution role section, click on the “Role” option under the “Role name” field:

This will display the following interface. From the sidebar, click on the “Policies” option under the “Access Management” section:

On the IAM Policies interface, click on the “Create policy” button to configure the required permissions for the function:

Search and select the “Secret Manager” from the results under the “Select a service” block. Tap the “Next” button to proceed further:

After selecting the Service, we have to specify the “Actions”. In the Actions allowed section, configure the following actions for the Secret Manager service. From the Read section:

  • DescribeSecret
  • GetRandomPassword
  • GetSecretValue

Similarly, in the Write section, allow the following actions:

  • PutSecretValue
  • UpdateSecretVersionStage

Under the “Actions allowed” section, there is the “Resources” block. To implement rotation for a specific secret, provide the ARN of the secret. The ARN of the resource is unique which is provided by AWS to identify different resources. Click on the “Add Arn” option to specify the ARN of the secret:

Head back to the Secret Manager dashboard and choose the secret’s name. From the Secret details interface, tap the button to copy the ARN of the secret:

Paste the ARN in the Specify ARNs window of the IAM policy. Also, click the “This account” button as the secret is configured inside the current account. After that, click on the “Add ARNs” button:

Click on the “Next” button after specifying the ARN:

Type the name in the following highlighted text field on the Policy details interface. The description is optional. However, the user can also custom provide the description for the policy:

Scroll down to the bottom of the interface and click on the “Create policy” button:

Step 4: Attach Policy

From the Permissions tab of the Lambda function, again tap the “Role name” option:

Scroll down the IAM role interface and tap the “Add permissions” button. From the drop-down list, click the “Attach policies” option:

Search the name of the policy that we have just created earlier. Select the policy from the displayed results:

Click on the “Add permissions” button to attach the policy:

The policy was successfully attached to the role:

Step 5: Invoke Lambda Function

Go to the Lambda Function interface and click the Configuration tab. Tap the “Permissions” option from the Configurations tab:

Scroll down to the “Resource-based policy statements” section. Tap the “Add permissions” button from this section:

Select the “AWS service” option from the Policy statement section:

In the Service text field, select the “Secret Manager” from a different option. Provide a unique identifier in the “Statement ID” text field. The “Principal” is provided as default by the AWS:

Select the “lambda:InvokeFunction” in the Action’s text field and hit the “Save” button:

The changes are successfully applied:

Step 6: Enable Automatic Rotation

Choose the secret’s name from the AWS Secret Manager Dashboard and click on it:

Scroll down the interface and click the “Edit rotation” button from the “Rotation configuration” section:

From the displayed dialog box, toggle the “Automatic rotation” button to enable the rotation under the “Configure automatic rotation” section:

In the “Rotation schedule” section, there are two types of schedules provided.

Schedule expression builder: In this option, the user can specify the time for the rotation by providing values in the following highlighted option.

At the moment, select the “Schedule expression builder” option. In the Time unit text field, we have selected the “Weeks” option and provided the value “2” in Weeks. Users can select any day for the rotation from the “Day of Week” options. Similarly, the start time field follows the 24-hour format. Specifying the “2” value in the text field means that the rotation will occur at 2 A.M:

Schedule Expression: The Schedule expression is composed of the rate() and cron():

Rate(): The rate expression follows a specific format:

rate(Value, Unit)

Where Value is the positive integer and Unit can be hour, hours, day, or days.

  • rate( 1 hour): it means that the rotation will occur after every 1 hour.
  • rate ( 8 days): means that the rotation will occur after every 8 days.

Cron(): This expression follows the below-mentioned format:

cron(Minutes Hours Day-of-month Month Day-of-week Year)

In this format, the user can specify minutes, months, days, years, etc. Below mentioned is an example:

  • cron(0 8 ? * MON-FRI *): This expression means that the rotation will occur every 8 A.M from Monday to Friday.

To learn more about rate() and cron(), the official document is provided by AWS.

In the Rotation function block, select the Lambda function in the “Lambda rotation function” text field. Click the “Save” button to configure and apply changes:

The rotation has been enabled successfully:

Above the Rotation configuration is the Secret value block. Click on the “Retrieve secret value” button:

Here, we can see that the value of the secret has been rotated and changed:

That is all from this guide.

Bonus Tip: Benefits of Rotating Secrets

The following are the benefits of rotating secrets in AWS Secret Manager:

Improved Security: The security of the credentials of the application is greatly improved by automating the rotation of secrets. This is because the value is replaced by the random string which minimizes the risk of security compromise.

Cost Optimal Solution: Rotation of the secret does not incur any additional charges.

Enhanced Flexibility: This rotation of secrets provides flexibility in workflow to the developers. The secrets are rotated and updated for every service that requires these credentials.

Conclusion

To automate secret rotation, create a Lambda function with permissions to access the secret and enable the automatic rotation to invoke the Lambda function. The Lambda function will access the secret specified in the code and will replace its value with a random string. The rotation will occur at the scheduled time. This article presents a step-by-step demonstration for automating rotation in Secret Manager using AWS Lambda.

About the author

Shameen Shahid

I am a self-motivated technical content writer. I hold a bachelor’s degree in computer science an have expertise in AWS and want to share my knowledge with the world.