Secrets Manager Secrets Should Be Rotated Frequently
More Info:
Ensure that the rotation interval for your AWS Secrets Manager secrets is configured to meet security and compliance requirements. Prior to running this rule by the Cloud Conformity engine, the rotation interval (in days) must be configured in the rule settings, on your Cloud Conformity account dashboard. Amazon Secrets Manager rotation feature represents the automatic process that periodically change your secrets information to make it more difficult for attackers to access the services and resources secured with these secrets.
Risk Level
Medium
Address
Security
Compliance Standards
AWSWAF
Remediation
How to ensure secrets are rotated frequently
Using AWS Console
- Identify the secrets that need to be rotated - This includes access keys, database passwords, API keys, and other sensitive information. (In the Cloudanix Console, navigate to "Misconfig" page and look for Affected Assets for "Secrets Manager Secrets Should Be Rotated Frequently" Policy.)
- Create a rotation schedule - Determine how often the secrets need to be rotated. This can be based on industry standards or any compliance requirements.
- Use AWS Secrets Manager or AWS Systems Manager Parameter Store - These services automate the rotation process for you. You can create a rotation policy that specifies when and how to rotate the secrets.
- Update applications and services - After the secrets are rotated, update the applications and services that use them with the new values.
- Test the rotation process - Regularly test the rotation process to ensure that it is working as expected.
- Monitor the rotation process - Monitor the rotation process to ensure that it is running on schedule and that there are no errors or issues.
Triage and Remediation
- Remediation
Remediation
Using Console
Below are concise, step-by-step AWS Console instructions to remediate “Secrets Manager Secrets Should Be Rotated Frequently” for secrets encrypted with AWS KMS.
1. Identify Non-Rotating Secrets
- Sign in to the AWS Management Console.
- Go to Secrets Manager:
- Services → Secrets Manager.
- In Secrets, look for secrets where:
- Rotation configuration column is “Disabled” or rotation interval is longer than your policy (e.g., >30 days).
You’ll remediate each of these secrets.
2. Enable Rotation for a Secret
Perform this for each non-compliant secret.
- In Secrets Manager, click the secret name.
- In the secret’s detail page, choose Rotate secret (or Edit rotation if already enabled but not compliant).
2.1 Choose Rotation Strategy
- On the Rotation configuration page:
- Check “Enable automatic rotation”.
- Set Rotation schedule:
- Choose “Every X days” and enter your required frequency
(e.g., 30 for monthly rotation).
- Choose “Every X days” and enter your required frequency
2.2 Choose or Create Rotation Lambda Function
-
Under Rotation function, choose one:
- If you already have a rotation Lambda for this type (e.g., RDS, DocumentDB, Redshift, etc.):
- Select “Use an existing Lambda function” and pick the function.
- If you don’t have one:
- Select “Create a new Lambda function”.
- Choose the secret type / database type (e.g., RDS, other database, custom).
- Follow the wizard to create the Lambda:
- Select the VPC, subnets, and security groups if the target is in a private network.
- Secrets Manager will create a template Lambda function with the correct rotation logic for that backend.
- If you already have a rotation Lambda for this type (e.g., RDS, DocumentDB, Redshift, etc.):
-
Click Next, then Save / Enable rotation.
Secrets Manager will now:
- Use your KMS key (already associated with the secret) to encrypt the new versions.
- Automatically invoke the Lambda on your schedule to rotate the secret.
3. Verify KMS Key Permissions (If Rotation Fails)
If rotation errors occur, you may need to adjust the KMS CMK policy:
- Go to AWS KMS:
- Services → Key Management Service → Customer managed keys.
- Click the CMK used by the secret (shown on the secret’s detail page under Encryption key).
- Under Key policy:
- Ensure the IAM role used by the rotation Lambda function has:
kms:Encryptkms:Decryptkms:GenerateDataKeykms:DescribeKey
- Ensure the IAM role used by the rotation Lambda function has:
- Save the key policy if edited.
4. Confirm Rotation Is Working
- Back in Secrets Manager, open the secret.
- Confirm:
- Rotation configuration shows Enabled and the correct interval.
- Secret versions show multiple versions over time (after the first rotation occurs).
- Optionally, click Rotate secret now to test the configuration immediately.
Repeat for all flagged secrets until all have automatic rotation enabled at the desired frequency.
Using CLI
Below is how to remediate “Secrets Manager Secrets Should Be Rotated Frequently” for AWS using the AWS CLI. This covers enabling automatic rotation for an AWS Secrets Manager secret (which is encrypted with KMS).
1. Identify the secret(s) that need rotation
aws secretsmanager list-secrets --query 'SecretList[].Name'
Or filter by tag / name pattern as needed.
2. (One-time) Create a rotation Lambda function
If you don’t already have a rotation Lambda, you need one. For RDS or other standard engines, use an AWS-provided template from the console or AWS docs; for CLI-only, this is the basic outline:
- Create an IAM role for the Lambda with permissions to:
secretsmanager:GetSecretValuesecretsmanager:PutSecretValuesecretsmanager:UpdateSecretVersionStage- Any permissions needed to update the target (e.g., RDS, API key, etc.)
Example trust policy file lambda-trust-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
Create role:
aws iam create-role \
--role-name SecretsRotationRole \
--assume-role-policy-document file://lambda-trust-policy.json
Attach basic Lambda logging and Secrets Manager permissions (adjust ARNs/permissions as needed):
aws iam attach-role-policy \
--role-name SecretsRotationRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam put-role-policy \
--role-name SecretsRotationRole \
--policy-name SecretsRotationPolicy \
--policy-document file://secrets-rotation-inline-policy.json
Your secrets-rotation-inline-policy.json should at minimum include:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:PutSecretValue",
"secretsmanager:UpdateSecretVersionStage"
],
"Resource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:*"
},
{
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/YOUR_KMS_KEY_ID"
}
]
}
Then create the Lambda function (ZIP file must contain your rotation code):
aws lambda create-function \
--function-name my-secret-rotation-fn \
--runtime python3.11 \
--role arn:aws:iam::ACCOUNT_ID:role/SecretsRotationRole \
--handler lambda_function.lambda_handler \
--zip-file fileb://rotation_function.zip \
--timeout 300
You can reuse this Lambda for multiple secrets of the same type.
3. Enable automatic rotation on a secret
Pick a rotation interval (e.g., 30 days). Example for my-app-secret:
SECRET_ARN=$(aws secretsmanager describe-secret \
--secret-id my-app-secret \
--query 'ARN' --output text)
Enable rotation:
aws secretsmanager rotate-secret \
--secret-id "$SECRET_ARN" \
--rotation-lambda-arn arn:aws:lambda:REGION:ACCOUNT_ID:function:my-secret-rotation-fn \
--rotation-rules AutomaticallyAfterDays=30
If rotation Lambda is already attached and you only need to adjust frequency:
aws secretsmanager update-secret-rotation \
--secret-id "$SECRET_ARN" \
--rotation-rules AutomaticallyAfterDays=30
4. Verify rotation configuration
aws secretsmanager describe-secret \
--secret-id "$SECRET_ARN" \
--query '{RotationEnabled:RotationEnabled,Rules:RotationRules}'
You should see RotationEnabled: true and AutomaticallyAfterDays: 30 (or your chosen value).
5. (Optional) Enable KMS key rotation (separate from secret rotation)
If your secret uses a customer-managed KMS key and you also want that key to rotate annually:
aws kms enable-key-rotation --key-id YOUR_KMS_KEY_ID
Check status:
aws kms get-key-rotation-status --key-id YOUR_KMS_KEY_ID
This configuration ensures Secrets Manager secrets are automatically rotated on the schedule you define, with encryption handled by KMS.
Using Python
Below is a concise step‑by‑step guide to remediate “Secrets Manager secrets should be rotated frequently” for an AWS KMS‑encrypted secret using Python. This covers:
- What you need set up
- Creating a Python rotation function (Lambda)
- Attaching it to the secret with a rotation schedule
1. Prerequisites
- Existing secret in AWS Secrets Manager, encrypted with a KMS CMK (customer‑managed key or AWS managed key).
- IAM role for Lambda with at least:
secretsmanager:GetSecretValuesecretsmanager:PutSecretValuesecretsmanager:UpdateSecretVersionStage- Any permissions required to change the underlying credentials (e.g., RDS, user store, etc.).
- Python 3.x Lambda runtime.
2. Rotation Model to Use
Decide how new credentials are generated. Example scenarios:
- RDS or other DB password: You call the DB to change password and then update the secret.
- API keys: You call the provider to issue a new key, then update the secret.
- KMS key material itself is not “rotated” by Secrets Manager. Instead, you rotate:
- Either the credentials that are stored in the secret (such as DB creds, API keys that are encrypted with KMS),
- Or you enable KMS key rotation directly on CMKs separately (outside of Secrets Manager):
aws kms enable-key-rotation --key-id <your-key-id>
Below assumes we are rotating credentials stored in the secret that are KMS‑encrypted, which is what the misconfiguration usually refers to.
3. Python Rotation Lambda – Core Template
AWS Secrets Manager expects the Lambda to implement a lambda_handler that supports these steps:
createSecretsetSecrettestSecretfinishSecret
3.1. Basic Lambda Skeleton (Python)
Create a new Lambda function with Python 3.x and paste:
import boto3
import json
import os
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
secrets_client = boto3.client('secretsmanager')
def lambda_handler(event, context):
"""Entry point for Secrets Manager rotation."""
logger.info(f"Event: {json.dumps(event)}")
step = event['Step']
secret_arn = event['SecretId']
token = event['ClientRequestToken']
# Validate version and stages
metadata = secrets_client.describe_secret(SecretId=secret_arn)
if 'RotationEnabled' in metadata and not metadata['RotationEnabled']:
raise ValueError("Secret rotation not enabled for this secret.")
versions = metadata['VersionIdsToStages']
if token not in versions:
raise ValueError("Secret version not set as part of rotation.")
if 'AWSCURRENT' in versions[token]:
logger.info("Version already AWSCURRENT, nothing to do.")
return
elif 'AWSPENDING' not in versions[token]:
raise ValueError("Secret version not set to AWSPENDING for rotation.")
if step == 'createSecret':
create_secret(secret_arn, token)
elif step == 'setSecret':
set_secret(secret_arn, token)
elif step == 'testSecret':
test_secret(secret_arn, token)
elif step == 'finishSecret':
finish_secret(secret_arn, token)
else:
raise ValueError("Invalid step parameter")
def create_secret(secret_arn, token):
"""
Generate a new secret value and store it as the AWSPENDING version.
This is where you actually *generate* the new credentials.
"""
logger.info("createSecret step")
# Get current secret as baseline, if needed
current = secrets_client.get_secret_value(
SecretId=secret_arn,
VersionStage='AWSCURRENT'
)
current_secret_str = current['SecretString']
current_secret = json.loads(current_secret_str)
# Example: rotate a password field
new_password = generate_password()
new_secret = current_secret.copy()
new_secret['password'] = new_password
# Store AWSPENDING version
secrets_client.put_secret_value(
SecretId=secret_arn,
ClientRequestToken=token,
SecretString=json.dumps(new_secret),
VersionStages=['AWSPENDING']
)
def set_secret(secret_arn, token):
"""
Apply the pending credentials to the target resource (DB, service, etc.).
For example, update DB user password here.
"""
logger.info("setSecret step")
pending = secrets_client.get_secret_value(
SecretId=secret_arn,
VersionId=token,
VersionStage='AWSPENDING'
)
pending_secret = json.loads(pending['SecretString'])
# Example: apply to a DB; replace with your logic
# update_database_password(
# username=pending_secret['username'],
# password=pending_secret['password'],
# host=pending_secret['host'],
# ...
# )
def test_secret(secret_arn, token):
"""
Verify the pending credentials actually work against the target resource.
"""
logger.info("testSecret step")
pending = secrets_client.get_secret_value(
SecretId=secret_arn,
VersionId=token,
VersionStage='AWSPENDING'
)
pending_secret = json.loads(pending['SecretString'])
# Example: try login/connection using pending_secret
# if not test_database_connection(pending_secret):
# raise ValueError("Pending secret failed validation")
def finish_secret(secret_arn, token):
"""
Mark the pending version as current (AWSCURRENT) and demote old versions.
"""
logger.info("finishSecret step")
metadata = secrets_client.describe_secret(SecretId=secret_arn)
versions = metadata['VersionIdsToStages']
current_version = None
for version, stages in versions.items():
if 'AWSCURRENT' in stages:
current_version = version
break
# Set AWSCURRENT to the new version
secrets_client.update_secret_version_stage(
SecretId=secret_arn,
VersionStage='AWSCURRENT',
MoveToVersionId=token,
RemoveFromVersionId=current_version
)
def generate_password(length=32):
"""
Helper: generate a strong password. Customize policy as needed.
"""
import string
import secrets as sec
alphabet = string.ascii_letters + string.digits + string.punctuation
return ''.join(sec.choice(alphabet) for _ in range(length))
Replace the commented update_database_password / test_database_connection bits with the actual logic for your use case (API, DB, etc.).
4. Configure the Lambda for Rotation
- Create the Lambda (console or CLI) with the above code.
- Attach an IAM role allowing:
secretsmanager:GetSecretValue,PutSecretValue,DescribeSecret,UpdateSecretVersionStage- Any service‑specific actions (e.g.,
rds:ModifyDBInstance, or API client permissions).
- Ensure Lambda environment has necessary config values (e.g., DB endpoint, user, etc.) if not stored in the secret.
5. Enable Rotation on the Secret (via Console or Python)
5.1. Using AWS Console
- Go to Secrets Manager → select the secret.
- Click Rotate secret.
- Choose Use an existing Lambda function and select the Lambda created above.
- Set rotation schedule (e.g., every 30 days).
- Save.
5.2. Using Python (boto3)
import boto3
secrets_client = boto3.client('secretsmanager')
secret_arn = "<your-secret-arn>"
lambda_arn = "<your-lambda-arn>"
response = secrets_client.rotate_secret(
SecretId=secret_arn,
RotationLambdaARN=lambda_arn,
RotationRules={
'AutomaticallyAfterDays': 30 # adjust as needed
},
RotateImmediately=True # perform an immediate rotation
)
print(response)
This:
- Attaches the rotation Lambda.
- Sets rotation interval (e.g., 30 days).
- Triggers an immediate rotation cycle if
RotateImmediately=True.
6. Ensure KMS Key Rotation (Optional but Recommended)
If you use a customer‑managed KMS key to encrypt the secret, enable key rotation:
aws kms enable-key-rotation --key-id <your-kms-key-id>
Or via boto3:
import boto3
kms = boto3.client('kms')
kms.enable_key_rotation(
KeyId='<your-kms-key-id>'
)
This rotates the key’s cryptographic material annually, complementing secret rotation.
If you share what type of credential is stored in the secret (RDS, API key, etc.), I can adapt the setSecret and testSecret functions with concrete code.
Using Terraform
resource "aws_kms_key" "SECRET_KMS_KEY" {
description = "KMS key used to encrypt Secrets Manager secrets"
deletion_window_in_days = 30
# ...any additional required arguments (e.g., policy) ...
}
# Enable automatic annual rotation on the CMK used for Secrets Manager
resource "aws_kms_key_rotation" "SECRET_KMS_KEY_ROTATION" {
key_id = aws_kms_key.SECRET_KMS_KEY.key_id
enabled = true
}
Substitute:
SECRET_KMS_KEYwith the Terraform name you use for the KMS key that encrypts your Secrets Manager secrets.
This change does not force replacement of the KMS key; it toggles rotation in place.
Verification: terraform plan should show an aws_kms_key_rotation resource being created (or updated) with enabled = true for the target key and no replacement of the aws_kms_key itself.