AWS Secrets Manager Tutorial: Storing and Rotating Secrets
A practical guide to AWS Secrets Manager: creating secrets, retrieving them from apps, automatic rotation, IAM access control, and choosing it over SSM Parameter Store.
What you'll learn
- ✓What Secrets Manager does and when to pick it over Parameter Store
- ✓How to create, version, and retrieve secrets
- ✓How automatic rotation works under the hood
- ✓IAM and KMS patterns for least-privilege access
- ✓Pitfalls and cost-control tips for production
Prerequisites
- •Familiarity with [AWS IAM basics](/blog/aws-iam-roles-and-policies)
AWS Secrets Manager stores sensitive strings — database passwords, API keys, OAuth tokens — encrypted at rest with KMS, retrieved over IAM-authenticated APIs, and optionally rotated automatically. It costs more than SSM Parameter Store but earns its keep when you need rotation, cross-account sharing, or versioned secrets with staging labels.
What and Why
A secret in Secrets Manager is just a JSON blob (or plain string) wrapped in a managed envelope: a name, a KMS key, a rotation policy, and a set of versions tagged with staging labels like AWSCURRENT and AWSPREVIOUS. Your app reads the secret by name and always gets the current version unless you ask otherwise.
Why not just use environment variables? Env vars get committed by accident, leak in logs, and never rotate. Why not Parameter Store SecureString? It is cheaper and great for config, but it lacks first-class rotation, cross-region replication, and the staging-label workflow that makes zero-downtime credential changes possible.
Pick Secrets Manager when secrets must rotate on a schedule, when multiple services share a database password that may change, or when you need cross-account access via resource policies.
Mental Model
Each secret has a stable name and an unbounded version history. AWS labels exactly one version as AWSCURRENT. Rotation creates a new version, tests it, then atomically moves the AWSCURRENT label. The previous version keeps AWSPREVIOUS for one cycle so in-flight requests don’t break. Your code always asks for AWSCURRENT.
secret: prod/db/password
v1 [AWSPREVIOUS]
v2 [AWSCURRENT]
v3 [AWSPENDING] (during rotation)
When rotation finishes successfully, v3 becomes AWSCURRENT, v2 becomes AWSPREVIOUS, and v1 loses its label.
Hands-on Example
Create a secret holding a database password, fetch it from an app, and enable rotation.
aws secretsmanager create-secret \
--name prod/orders/db \
--description "Orders RDS master password" \
--secret-string '{"username":"orders","password":"S3edChange!"}'
In a Node.js app, fetch it on startup:
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
const sm = new SecretsManagerClient({});
const res = await sm.send(new GetSecretValueCommand({ SecretId: "prod/orders/db" }));
const { username, password } = JSON.parse(res.SecretString);
Attach an IAM policy to the app role granting only secretsmanager:GetSecretValue on that exact ARN, plus kms:Decrypt on the KMS key.
Lambda rotator + Secrets Manager + RDS
Step 1 createSecret: new password generated -> AWSPENDING
Step 2 setSecret: ALTER USER on RDS to new password
Step 3 testSecret: connect using AWSPENDING -> ok?
Step 4 finishSecret: move AWSCURRENT label to new version
v(n) [AWSCURRENT] --> [AWSPREVIOUS]
v(n+1)[AWSPENDING] --> [AWSCURRENT] Enable rotation with a managed Lambda template:
aws secretsmanager rotate-secret \
--secret-id prod/orders/db \
--rotation-lambda-arn arn:aws:lambda:us-east-1:123:function:SecretsManagerRDSRotation \
--rotation-rules AutomaticallyAfterDays=30
The first rotation runs immediately. From then on, your password silently rolls every 30 days and your app picks it up on the next cache miss.
Common Pitfalls
- Caching forever. Apps that fetch the secret at boot and never refresh will break the moment rotation runs. Use the AWS Secrets Manager client-side caching library or a TTL of a few minutes.
- Wildcard IAM resources.
Resource: "*"onGetSecretValueis an audit finding waiting to happen. Pin to specific ARNs. - Forgotten KMS permissions. A correct Secrets Manager policy still fails if the role cannot
kms:Decryptthe underlying key — especially when using customer-managed keys. - Rotating without testing. The default RDS rotation Lambda only works for the master user. Custom users or non-RDS targets need a custom Lambda; test it in staging first.
- Cost surprise. Secrets cost USD 0.40 per secret per month plus API calls. A microservice fleet hitting one secret thousands of times per minute racks up bills fast — cache aggressively.
Production Tips
Use a hierarchical naming convention like env/service/purpose so policies and dashboards can wildcard cleanly per environment. Replicate critical secrets to a DR region with replicate-secret-to-regions. Tag every secret with owner and service so cost reports stay readable.
Wire CloudTrail events for GetSecretValue into your SIEM — sudden access from unexpected principals is a red flag. For local dev, never hard-code; use the same SDK call with a dev secret and IAM role assumed by your laptop.
Wrap-up
Secrets Manager is the right home for credentials that need to rotate, version, or cross account boundaries. Create the secret, lock the IAM and KMS policies, cache reads in your app, and let scheduled rotation handle the rest. The extra cost over Parameter Store buys you a real rotation story and a much cleaner incident timeline.
Related articles
- AWS AWS IAM Policies vs Roles Cheatsheet
A quick-reference guide to the difference between IAM users, roles, policies, and trust relationships, with examples you can paste into your AWS account today.
- AWS AWS IAM Basics: Users, Roles, and Policies
Learn AWS IAM fundamentals: root vs IAM users, JSON policies, roles for services, least privilege, and common pitfalls that lead to security incidents.
- DevOps AWS S3 Bucket Policies Explained
How S3 bucket policies, IAM policies, and ACLs interact, how to write least-privilege bucket policies, and patterns for cross-account access without footguns.
- AWS AWS CodeBuild and CodeDeploy Tutorial: Build and Ship on AWS
Learn how to wire AWS CodeBuild and CodeDeploy together to build artifacts, run tests, and deploy to EC2, ECS, or Lambda with blue/green and canary strategies.