
Aws Secrets Manager
- 89 installs
- 44 repo stars
- Updated May 22, 2026
- bagelhole/devops-security-agent-skills
aws-secrets-manager is a Claude skill that stores, retrieves, and rotates secrets in AWS Secrets Manager with automatic rotation via Lambda.
About
This skill stores, retrieves, and rotates secrets in AWS Secrets Manager using AWS CLI and boto3. It covers creating JSON and binary secrets, KMS encryption, resource-based access policies, and a four-step Lambda rotation function for database credentials. A developer uses it to replace hardcoded secrets and meet credential-rotation compliance. It includes application integration examples and troubleshooting.
- Create and encrypt secrets with KMS, plus resource-based access policies
- Four-step Lambda rotation function for automatic DB credential rotation
- Application integration examples in Python with boto3
Aws Secrets Manager by the numbers
- 89 all-time installs (skills.sh)
- Ranked #1,052 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
aws-secrets-manager capabilities & compatibility
Free skill; AWS charges per secret and per rotation Lambda invocation
- Capabilities
- azure keyvault · aws s3 · aws vpc
- Works with
- aws
- Use cases
- security audit · devops
- Pricing
- Bring your own API key
What aws-secrets-manager says it does
Store and rotate secrets in AWS Secrets Manager. Configure automatic rotation, access policies, and application integration.
Replacing hardcoded secrets in application code or config files
npx skills add https://github.com/bagelhole/devops-security-agent-skills --skill aws-secrets-managerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 89 |
|---|---|
| repo stars | ★ 44 |
| Last updated | May 22, 2026 |
| Repository | bagelhole/devops-security-agent-skills ↗ |
What it does
Store and automatically rotate application secrets in AWS Secrets Manager instead of hardcoding credentials.
Who is it for?
Replacing hardcoded credentials with managed, rotating secrets on AWS
Skip if: Non-AWS secret stores like HashiCorp Vault or Azure Key Vault
When should I use this skill?
You are storing database credentials or API keys in AWS or need automatic credential rotation
What you get
Secrets stored, KMS-encrypted, access-scoped, and rotating automatically on a schedule.
- Stored KMS-encrypted secret
- Rotation Lambda function
- Resource-based access policy
By the numbers
- Four-step rotation process (createSecret, setSecret, testSecret, finishSecret)
- 32-character generated password in rotation example
Files
AWS Secrets Manager
Securely store, manage, and rotate secrets in AWS.
When to Use This Skill
Use this skill when:
- Storing database credentials, API keys, or tokens in AWS
- Implementing automatic credential rotation for RDS or other services
- Replacing hardcoded secrets in application code or config files
- Integrating secrets into ECS, EKS, or Lambda workloads
- Meeting compliance requirements for secret management and rotation
Prerequisites
- AWS account with appropriate IAM permissions
- AWS CLI v2 installed and configured
- IAM policy allowing
secretsmanager:*actions (or scoped permissions) - For rotation: Lambda execution role and VPC access to target services
- Python 3.9+ with
boto3for SDK examples
Secret Creation and Management
# Create a secret with JSON structure
aws secretsmanager create-secret \
--name myapp/production/database \
--description "Production database credentials" \
--secret-string '{"username":"dbadmin","password":"S3cur3P@ssw0rd!","engine":"postgres","host":"db.internal.example.com","port":5432,"dbname":"myapp"}' \
--tags '[{"Key":"Environment","Value":"production"},{"Key":"Team","Value":"platform"}]'
# Create a secret with KMS encryption (custom key)
aws secretsmanager create-secret \
--name myapp/production/api-key \
--description "Third-party API key" \
--secret-string "ak_live_xxxxxxxxxxxx" \
--kms-key-id alias/secrets-key
# Create a binary secret (certificates, keys)
aws secretsmanager create-secret \
--name myapp/production/tls-cert \
--secret-binary fileb://server.pfx
# Get secret value
aws secretsmanager get-secret-value \
--secret-id myapp/production/database \
--query 'SecretString' --output text | jq .
# Get a specific version
aws secretsmanager get-secret-value \
--secret-id myapp/production/database \
--version-stage AWSPREVIOUS
# Update secret value
aws secretsmanager put-secret-value \
--secret-id myapp/production/database \
--secret-string '{"username":"dbadmin","password":"N3wS3cur3P@ss!","engine":"postgres","host":"db.internal.example.com","port":5432,"dbname":"myapp"}'
# List all secrets
aws secretsmanager list-secrets \
--filters Key=name,Values=myapp/production
# Delete secret (with recovery window)
aws secretsmanager delete-secret \
--secret-id myapp/production/old-key \
--recovery-window-in-days 7
# Restore a deleted secret
aws secretsmanager restore-secret \
--secret-id myapp/production/old-key
# Tag a secret
aws secretsmanager tag-resource \
--secret-id myapp/production/database \
--tags '[{"Key":"RotationEnabled","Value":"true"}]'Automatic Rotation
Enable Rotation
# Enable rotation with an existing Lambda function
aws secretsmanager rotate-secret \
--secret-id myapp/production/database \
--rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSPostgreSQLRotation \
--rotation-rules '{"AutomaticallyAfterDays":30,"ScheduleExpression":"rate(30 days)"}'
# Trigger immediate rotation
aws secretsmanager rotate-secret \
--secret-id myapp/production/database
# Check rotation status
aws secretsmanager describe-secret \
--secret-id myapp/production/database \
--query '{RotationEnabled:RotationEnabled,RotationLambdaARN:RotationLambdaARN,RotationRules:RotationRules,LastRotatedDate:LastRotatedDate}'Lambda Rotation Function
"""rotation_function.py - Custom rotation Lambda for database credentials."""
import boto3
import json
import logging
import psycopg2
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
"""Secrets Manager rotation handler.
The rotation process has four steps:
1. createSecret - Generate new secret value
2. setSecret - Apply the new secret to the target service
3. testSecret - Verify the new secret works
4. finishSecret - Mark rotation complete
"""
secret_arn = event['SecretId']
token = event['ClientRequestToken']
step = event['Step']
client = boto3.client('secretsmanager')
metadata = client.describe_secret(SecretId=secret_arn)
if not metadata.get('RotationEnabled'):
raise ValueError(f"Secret {secret_arn} does not have rotation enabled")
versions = metadata.get('VersionIdsToStages', {})
if token not in versions:
raise ValueError(f"Secret version {token} has no stage for rotation")
if step == "createSecret":
create_secret(client, secret_arn, token)
elif step == "setSecret":
set_secret(client, secret_arn, token)
elif step == "testSecret":
test_secret(client, secret_arn, token)
elif step == "finishSecret":
finish_secret(client, secret_arn, token)
else:
raise ValueError(f"Invalid step: {step}")
def create_secret(client, secret_arn, token):
"""Generate a new secret value."""
current = client.get_secret_value(
SecretId=secret_arn, VersionStage="AWSCURRENT"
)
current_dict = json.loads(current['SecretString'])
new_password = client.get_random_password(
PasswordLength=32,
ExcludeCharacters='/@"\\',
RequireEachIncludedType=True,
)['RandomPassword']
current_dict['password'] = new_password
client.put_secret_value(
SecretId=secret_arn,
ClientRequestToken=token,
SecretString=json.dumps(current_dict),
VersionStages=['AWSPENDING'],
)
logger.info(f"createSecret: New secret version created for {secret_arn}")
def set_secret(client, secret_arn, token):
"""Apply the new secret to the target database."""
pending = client.get_secret_value(
SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING"
)
pending_dict = json.loads(pending['SecretString'])
current = client.get_secret_value(
SecretId=secret_arn, VersionStage="AWSCURRENT"
)
current_dict = json.loads(current['SecretString'])
conn = psycopg2.connect(
host=current_dict['host'],
port=current_dict.get('port', 5432),
user=current_dict['username'],
password=current_dict['password'],
dbname=current_dict.get('dbname', 'postgres'),
)
conn.autocommit = True
with conn.cursor() as cur:
cur.execute(
"ALTER USER %s WITH PASSWORD %s",
(pending_dict['username'], pending_dict['password']),
)
conn.close()
logger.info(f"setSecret: Password updated in database for {secret_arn}")
def test_secret(client, secret_arn, token):
"""Verify the new secret works."""
pending = client.get_secret_value(
SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING"
)
pending_dict = json.loads(pending['SecretString'])
conn = psycopg2.connect(
host=pending_dict['host'],
port=pending_dict.get('port', 5432),
user=pending_dict['username'],
password=pending_dict['password'],
dbname=pending_dict.get('dbname', 'postgres'),
)
conn.close()
logger.info(f"testSecret: New credentials verified for {secret_arn}")
def finish_secret(client, secret_arn, token):
"""Finalize the rotation by updating version stages."""
metadata = client.describe_secret(SecretId=secret_arn)
versions = metadata.get('VersionIdsToStages', {})
current_version = None
for version_id, stages in versions.items():
if "AWSCURRENT" in stages:
if version_id == token:
logger.info("finishSecret: Version already marked AWSCURRENT")
return
current_version = version_id
break
client.update_secret_version_stage(
SecretId=secret_arn,
VersionStage="AWSCURRENT",
MoveToVersionId=token,
RemoveFromVersionId=current_version,
)
logger.info(f"finishSecret: Rotation complete for {secret_arn}")Rotation Lambda Terraform
resource "aws_lambda_function" "rotation" {
filename = "rotation_function.zip"
function_name = "secrets-rotation-postgresql"
role = aws_iam_role.rotation.arn
handler = "rotation_function.lambda_handler"
runtime = "python3.11"
timeout = 60
vpc_config {
subnet_ids = var.private_subnet_ids
security_group_ids = [aws_security_group.rotation.id]
}
environment {
variables = {
SECRETS_MANAGER_ENDPOINT = "https://secretsmanager.${var.region}.amazonaws.com"
}
}
}
resource "aws_lambda_permission" "secrets_manager" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.rotation.function_name
principal = "secretsmanager.amazonaws.com"
statement_id = "AllowSecretsManager"
}
resource "aws_secretsmanager_secret_rotation" "db" {
secret_id = aws_secretsmanager_secret.db.id
rotation_lambda_arn = aws_lambda_function.rotation.arn
rotation_rules {
automatically_after_days = 30
}
}Application Integration
Python SDK
import boto3
import json
from functools import lru_cache
def get_secret(secret_name: str, region: str = "us-east-1") -> dict:
"""Retrieve and parse a secret from AWS Secrets Manager."""
client = boto3.client("secretsmanager", region_name=region)
response = client.get_secret_value(SecretId=secret_name)
if "SecretString" in response:
return json.loads(response["SecretString"])
else:
import base64
return base64.b64decode(response["SecretBinary"])
@lru_cache(maxsize=32)
def get_cached_secret(secret_name: str) -> dict:
"""Cached secret retrieval. Clear cache on rotation events."""
return get_secret(secret_name)
# Usage
creds = get_secret("myapp/production/database")
connection_string = (
f"postgresql://{creds['username']}:{creds['password']}"
f"@{creds['host']}:{creds['port']}/{creds['dbname']}"
)ECS Task Definition
{
"containerDefinitions": [
{
"name": "myapp",
"image": "ghcr.io/acme/myapp:v1.0.0",
"secrets": [
{
"name": "DB_USERNAME",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/database:username::"
},
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/database:password::"
},
{
"name": "API_KEY",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/production/api-key"
}
]
}
],
"executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole"
}EKS with External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets-manager
namespace: production
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: myapp/production/database
property: username
- secretKey: password
remoteRef:
key: myapp/production/database
property: passwordResource-Based Policy
# Restrict secret access to specific roles
aws secretsmanager put-resource-policy \
--secret-id myapp/production/database \
--resource-policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789:role/myapp-ecs-task-role",
"arn:aws:iam::123456789:role/myapp-lambda-role"
]
},
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "us-east-1"
}
}
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "secretsmanager:GetSecretValue",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalAccount": "123456789012"
}
}
}
]
}'Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
AccessDeniedException on GetSecretValue | IAM policy missing permission | Add secretsmanager:GetSecretValue to the role; check resource-based policy |
| Rotation fails with Lambda timeout | Lambda cannot reach database | Ensure Lambda is in same VPC with route to DB; check security groups |
| Secret value is empty after rotation | createSecret step failed | Check Lambda CloudWatch logs; verify random password generation works |
| ECS container fails to start | Secret ARN format incorrect | Use full ARN with :: for JSON key extraction; verify secret exists |
| Application uses old credentials after rotation | Client caching stale values | Implement cache invalidation on rotation; reduce cache TTL |
| Rotation Lambda permission error | Missing lambda:InvokeFunction permission | Add aws_lambda_permission for secretsmanager.amazonaws.com principal |
| KMS decrypt fails | Secret KMS key policy missing role | Add the accessing role to the KMS key policy's kms:Decrypt principals |
Best Practices
- Enable automatic rotation with 30-day intervals minimum
- Use resource-based policies in addition to IAM policies (defense in depth)
- Encrypt secrets with customer-managed KMS keys (not default)
- Implement least-privilege access (only the roles that need each secret)
- Use secret versioning for safe rollback during rotation issues
- Monitor secret access with CloudTrail and alert on unusual patterns
- Structure secret names hierarchically:
{app}/{env}/{secret-type} - Never log secret values; log only secret ARNs and access metadata
- Test rotation in staging before enabling in production
- Set up CloudWatch alarms for rotation failures
Related Skills
- hashicorp-vault - Multi-cloud secrets
- aws-iam - IAM policies
- azure-keyvault - Azure secret management
- gcp-secret-manager - GCP secret management
AWS Secrets Manager Patterns
Basic Operations
# Create secret
aws secretsmanager create-secret \
--name myapp/database \
--secret-string '{"username":"admin","password":"secret123"}'
# Get secret
aws secretsmanager get-secret-value --secret-id myapp/database
# Update secret
aws secretsmanager update-secret \
--secret-id myapp/database \
--secret-string '{"username":"admin","password":"newsecret"}'
# Delete secret
aws secretsmanager delete-secret --secret-id myapp/database --force-delete-without-recoveryAutomatic Rotation
# Lambda rotation function
def lambda_handler(event, context):
secret_id = event['SecretId']
token = event['ClientRequestToken']
step = event['Step']
if step == "createSecret":
create_secret(secret_id, token)
elif step == "setSecret":
set_secret(secret_id, token)
elif step == "testSecret":
test_secret(secret_id, token)
elif step == "finishSecret":
finish_secret(secret_id, token)Terraform
resource "aws_secretsmanager_secret" "db" {
name = "myapp/database"
tags = {
Environment = "production"
}
}
resource "aws_secretsmanager_secret_version" "db" {
secret_id = aws_secretsmanager_secret.db.id
secret_string = jsonencode({
username = "admin"
password = random_password.db.result
})
}
# Rotation
resource "aws_secretsmanager_secret_rotation" "db" {
secret_id = aws_secretsmanager_secret.db.id
rotation_lambda_arn = aws_lambda_function.rotation.arn
rotation_rules {
automatically_after_days = 30
}
}Application Integration
Python (boto3)
import boto3
import json
def get_secret(secret_name):
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId=secret_name)
return json.loads(response['SecretString'])
# Usage
creds = get_secret('myapp/database')
connection = connect(
host=creds['host'],
user=creds['username'],
password=creds['password']
)ECS Task Definition
{
"containerDefinitions": [{
"secrets": [{
"name": "DATABASE_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:myapp/database:password::"
}]
}]
}Lambda
# SAM template
Environment:
Variables:
SECRET_ARN: !Ref DatabaseSecret
Policies:
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Ref DatabaseSecretRelated skills
FAQ
Does this skill support automatic secret rotation?
Yes, it enables rotation with a Lambda function using the four-step createSecret, setSecret, testSecret, finishSecret process.
Can it restrict who reads a secret?
Yes, it applies resource-based policies to restrict secret access to specific IAM roles.