AWS Secrets Manager
Almost every application needs a password somewhere: a database login, an API key, an OAuth token. Hard-coding these in your code or config files is dangerous, because anyone who reads the source can steal them. AWS Secrets Manager is a managed service that stores these sensitive values encrypted, controls exactly who can read them with fine-grained permissions, and — its standout feature — can automatically change (rotate) passwords on a schedule so a leaked credential becomes useless quickly. This page shows how to store, read, and rotate secrets, and when to reach for Secrets Manager versus the cheaper Parameter Store.
What Secrets Manager actually stores
A secret is a small piece of named, encrypted data. It can be a single string (like an API key) or structured JSON (like {"username":"admin","password":"..."}). AWS encrypts every secret at rest using AWS KMS (Key Management Service — AWS’s service for managing encryption keys). You never see the encryption happening; it just works.
Each secret has:
- A name (e.g.
prod/db/credentials) — slashes are just naming convention, not folders. - An ARN (Amazon Resource Name — a unique ID for the resource).
- One or more versions, so rotation can keep the old value around briefly while clients switch over.
When to use this: any time your app needs a credential at runtime and you want strong access control, an audit trail, and (optionally) automatic rotation. When NOT to: for plain, non-secret configuration values like a feature flag or a region name — use Parameter Store for those.
Storing a secret
Console steps
- Open the AWS Management Console and go to Secrets Manager.
- Click Store a new secret.
- Choose Other type of secret (or Credentials for Amazon RDS database if it’s a database login).
- Enter the key/value pairs, e.g. key
password, values3cr3t-Pa55!. - Leave the encryption key as
aws/secrets-manager(the default AWS-managed KMS key) unless you need your own. - Click Next, give it a name like
prod/db/credentials, then Next again. - Skip rotation for now and click Store.
CLI equivalent
aws secretsmanager create-secret \
--name prod/db/credentials \
--description "Production database login" \
--secret-string '{"username":"admin","password":"s3cr3t-Pa55!"}'
Output:
{
"ARN": "arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/db/credentials-AbCdEf",
"Name": "prod/db/credentials",
"VersionId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
Retrieving a secret
Your application reads the secret at runtime using the SDK or CLI. AWS decrypts it on the fly (assuming the caller has permission).
aws secretsmanager get-secret-value --secret-id prod/db/credentials
Output:
{
"Name": "prod/db/credentials",
"VersionId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"SecretString": "{\"username\":\"admin\",\"password\":\"s3cr3t-Pa55!\"}",
"VersionStages": ["AWSCURRENT"]
}
The actual value is in SecretString. In code you’d call the equivalent SDK method (e.g. GetSecretValue in the AWS SDK for your language) and parse the JSON.
Cost gotcha: Secrets Manager charges per secret per month plus per API call. Calling
get-secret-valueon every single web request gets expensive fast and adds latency. Fetch the secret once at startup (or cache it for a few minutes) and reuse it in memory. The AWS-provided client-side caching libraries do this for you.
Controlling who can read it
Access is governed by IAM (Identity and Access Management — AWS’s permissions system). You attach a policy to a role allowing only the specific secret it needs:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/db/credentials-*"
}
]
}
The trailing -* matters: Secrets Manager appends six random characters to the ARN, so the wildcard lets the policy survive recreation.
Automatic rotation (the headline feature)
Rotation means Secrets Manager periodically generates a new password, updates the credential in the target system (like an RDS database), and stores the new value — all without downtime. It does this by invoking a Lambda function. For Amazon RDS, RDS Proxy, Redshift, and DocumentDB, AWS provides ready-made rotation functions, so you barely write any code.
Console steps
- Open your secret in the Secrets Manager console.
- Under Rotation configuration, click Edit rotation.
- Turn on Automatic rotation and choose a schedule (e.g. every 30 days).
- For an RDS secret, pick Use a Lambda function provided by Secrets Manager and select your database.
- Save. Secrets Manager creates the Lambda and tests the first rotation.
CLI equivalent
aws secretsmanager rotate-secret \
--secret-id prod/db/credentials \
--rotation-lambda-arn arn:aws:lambda:us-east-1:111122223333:function:SecretsManagerRDSRotation \
--rotation-rules '{"AutomaticallyAfterDays": 30}'
When to use rotation: database and service credentials that should change regularly for compliance or to limit damage from a leak. When NOT to: secrets you cannot programmatically change (e.g. a third-party API key with no rotation API) — rotating those just breaks things.
Secrets Manager vs Parameter Store
Systems Manager (SSM) Parameter Store also stores values, and its SecureString type encrypts them with KMS for free. The big differences are rotation and cost.
| Feature | Secrets Manager | SSM Parameter Store (SecureString) |
|---|---|---|
| Encryption at rest | Yes (KMS) | Yes (KMS) |
| Built-in automatic rotation | Yes (managed Lambda for RDS etc.) | No (you build it yourself) |
| Cross-account sharing | Yes (resource policies) | Limited |
| Price | ~$0.40 per secret/month + ~$0.05 per 10k API calls | Standard params free; Advanced ~$0.05/param/month |
| Best for | DB credentials needing rotation, shared secrets | Plain config and cheap, static secrets |
Rule of thumb: choose Secrets Manager when you need automatic rotation or cross-account secret sharing. Otherwise, Parameter Store SecureString does the same encrypted storage for free or far cheaper.
Best practices
- Cache secrets in memory at startup; never call
get-secret-valueon every request. - Grant IAM access to specific secret ARNs, not
*— least privilege limits blast radius. - Enable automatic rotation for all database credentials, and test that your app reconnects after a rotation.
- Use clear naming like
env/service/purpose(e.g.prod/payments/db) so policies and audits are readable. - Store structured JSON for related values (username + password) in one secret rather than many.
- Use Parameter Store for non-rotating, non-shared secrets to save money.
- Review CloudTrail logs to see who read each secret and when.