Skip to content
AWS aws security 5 min read

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

  1. Open the AWS Management Console and go to Secrets Manager.
  2. Click Store a new secret.
  3. Choose Other type of secret (or Credentials for Amazon RDS database if it’s a database login).
  4. Enter the key/value pairs, e.g. key password, value s3cr3t-Pa55!.
  5. Leave the encryption key as aws/secrets-manager (the default AWS-managed KMS key) unless you need your own.
  6. Click Next, give it a name like prod/db/credentials, then Next again.
  7. 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-value on 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

  1. Open your secret in the Secrets Manager console.
  2. Under Rotation configuration, click Edit rotation.
  3. Turn on Automatic rotation and choose a schedule (e.g. every 30 days).
  4. For an RDS secret, pick Use a Lambda function provided by Secrets Manager and select your database.
  5. 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.

FeatureSecrets ManagerSSM Parameter Store (SecureString)
Encryption at restYes (KMS)Yes (KMS)
Built-in automatic rotationYes (managed Lambda for RDS etc.)No (you build it yourself)
Cross-account sharingYes (resource policies)Limited
Price~$0.40 per secret/month + ~$0.05 per 10k API callsStandard params free; Advanced ~$0.05/param/month
Best forDB credentials needing rotation, shared secretsPlain 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-value on 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.
Last updated June 15, 2026
Was this helpful?