AWS Secrets Manager

By Vishvesh Patel · DevOps EngineerUpdated September 11, 2026

Store, rotate and retrieve secrets with AWS Secrets Manager. Resource policies, automatic rotation, caching, cost, and when Parameter Store is the better choice.

Secrets Manager stores credentials encrypted with KMS, controls access through IAM, logs every read to CloudTrail, and, the part that justifies its price, rotates supported secrets automatically without anyone touching a config file.

That last capability is the deciding factor. If you don't need rotation, Parameter Store does the same job for free.

Creating a secret

aws secretsmanager create-secret \
  --name prod/payments/db \
  --description "Aurora credentials for the payments service" \
  --secret-string '{"username":"payments","password":"REPLACE_ME","host":"db.internal","port":5432}'
{
    "ARN": "arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/db-AbCdEf",
    "Name": "prod/payments/db",
    "VersionId": "8f3c1e2a-..."
}

Note the six random characters AWS appends to the ARN. They're deliberate: they stop a deleted secret's name from being immediately reusable by someone who might inherit its permissions. It also means you can't construct a secret ARN by hand, if you're writing IAM policies, either look the ARN up or end the resource with a wildcard: arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/db-*.

Store JSON rather than a bare string. Rotation functions expect structured fields, and it lets one secret carry the host and port alongside the credentials.

Use a naming convention with a path-like shape, <env>/<service>/<purpose>, because IAM policies can then grant a service everything under its own prefix:

{
  "Effect": "Allow",
  "Action": "secretsmanager:GetSecretValue",
  "Resource": "arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/*"
}

Reading a secret

aws secretsmanager get-secret-value \
  --secret-id prod/payments/db \
  --query SecretString --output text

In application code, retrieve at startup and cache, never call Secrets Manager on every request:

import json, boto3
from botocore.exceptions import ClientError

_cache = {}

def get_secret(name: str, region: str = "us-east-1") -> dict:
    if name in _cache:
        return _cache[name]
    client = boto3.client("secretsmanager", region_name=region)
    try:
        response = client.get_secret_value(SecretId=name)
    except ClientError as err:
        # ResourceNotFoundException here is almost always a region mismatch.
        raise RuntimeError(f"Could not read secret {name}: {err}") from err
    _cache[name] = json.loads(response["SecretString"])
    return _cache[name]

API calls cost $0.05 per 10,000, which sounds trivial until a service handling 500 requests per second fetches on every one, that's about $65 a month to read a value that changes quarterly. Worse, you'll hit the API throttling limit and take an outage. AWS publishes language-specific caching libraries that handle refresh-on-rotation properly; use one rather than the naive dictionary above if your secrets actually rotate.

On Kubernetes, mount secrets through the Secrets Store CSI driver with the AWS provider instead of calling the API from application code. On ECS, reference the secret ARN directly in the task definition and let the agent inject it as an environment variable:

"secrets": [
  {
    "name": "DB_PASSWORD",
    "valueFrom": "arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/db-AbCdEf:password::"
  }
]

The trailing :password:: selects a single JSON key, so the container gets just that value rather than the whole document.

Rotation

Rotation is the feature you're paying for. Secrets Manager invokes a Lambda function on a schedule that creates a new credential, tests it, and promotes it, while the old one stays valid until the switch completes, so running applications don't break.

For RDS, Aurora, Redshift and DocumentDB, AWS supplies the rotation function:

aws secretsmanager rotate-secret \
  --secret-id prod/payments/db \
  --rotation-lambda-arn arn:aws:lambda:us-east-1:111122223333:function:SecretsManagerRDSPostgreSQLRotationSingleUser \
  --rotation-rules AutomaticallyAfterDays=30

Rotation moves version staging labels rather than overwriting anything:

LabelMeaning
AWSCURRENTThe active version (what get-secret-value returns by default)
AWSPENDINGCreated but not yet promoted
AWSPREVIOUSThe prior version, retained for rollback

There are two strategies. Single-user rotation changes the password on one database user; there's a brief window where a cached old password fails, so applications need retry logic. Alternating-user rotation maintains two users and swaps between them, which removes that window entirely. Use alternating users for anything that can't tolerate a failed connection.

Test rotation before trusting it. A rotation function that can't reach the database, wrong subnet, missing security group rule, fails silently on a schedule, and you find out months later when someone checks:

aws secretsmanager rotate-secret --secret-id prod/payments/db --rotate-immediately
aws secretsmanager describe-secret --secret-id prod/payments/db \
  --query '{LastRotated:LastRotatedDate,LastAttempt:LastRotationDate,Status:RotationEnabled}'

Deletion has a waiting period

aws secretsmanager delete-secret \
  --secret-id prod/payments/db \
  --recovery-window-in-days 30

Secrets don't delete immediately. The minimum recovery window is 7 days and the default is 30. During that window the secret is unreadable but restorable:

aws secretsmanager restore-secret --secret-id prod/payments/db

--force-delete-without-recovery skips the window and is irreversible. It also blocks reusing that name for the duration, which trips up teardown-and-recreate scripts in test environments.

Secrets Manager or Parameter Store?

Secrets ManagerParameter Store (SecureString)
Storage cost$0.40 per secret per monthFree (Standard tier)
API cost$0.05 per 10,000 callsFree (Standard), throughput limits apply
Automatic rotationBuilt in, managed functions for RDSBuild it yourself
Cross-account accessResource policiesNot supported directly
Max size64 KB4 KB Standard / 8 KB Advanced
Random ARN suffixYesNo

The honest guidance: use Parameter Store for configuration and for secrets you rotate manually or rarely. API keys, webhook tokens, third-party credentials. Use Secrets Manager for database credentials, anything that must rotate on a schedule, and anything shared across accounts. At $0.40 per secret per month, putting 200 config values in Secrets Manager costs $960 a year for something Parameter Store does for nothing.

Quick reference

TaskCommand
Createaws secretsmanager create-secret --name <n> --secret-string <s>
Readaws secretsmanager get-secret-value --secret-id <n>
Updateaws secretsmanager put-secret-value --secret-id <n> --secret-string <s>
Listaws secretsmanager list-secrets
Rotate nowaws secretsmanager rotate-secret --secret-id <n> --rotate-immediately
Rotation statusaws secretsmanager describe-secret --secret-id <n>
Delete (recoverable)aws secretsmanager delete-secret --secret-id <n> --recovery-window-in-days 30
Restoreaws secretsmanager restore-secret --secret-id <n>

Key takeaways

  • Rotation is what you're paying for. Without it, Parameter Store does the same job free.
  • ARNs carry a random six-character suffix, so IAM resource patterns need a trailing -*.
  • Store JSON, not bare strings: rotation functions expect structured fields.
  • Cache in the application. Per-request reads cost real money and will hit API throttling.
  • Test rotation deliberately. A rotation Lambda with no network path to the database fails quietly forever.
  • Deletion waits 7 to 30 days and the name stays reserved, which breaks naive teardown scripts.

Check your understanding

Exercise

An IAM policy that never matches

A policy allows secretsmanager:GetSecretValue on "arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/db". The application still gets AccessDenied. Why?

Exercise

Choosing a rotation strategy

A payment service cannot tolerate a single failed database connection. Which rotation strategy fits?


Frequently Asked Questions

Should I use Secrets Manager or Parameter Store?

Use Parameter Store for configuration values and for secrets you rarely rotate. It stores SecureStrings encrypted with KMS at no cost in the Standard tier. Use Secrets Manager when you need automatic rotation, cross-account sharing via resource policies, values larger than 4 KB, or a managed rotation function for RDS and Aurora. The cost difference is the deciding factor at scale: Secrets Manager is $0.40 per secret per month, so a few hundred values add up quickly for a capability many of them don't need.

How much does Secrets Manager cost?

$0.40 per secret per month, prorated hourly, plus $0.05 per 10,000 API calls. Ten database credentials is about $4 a month, which is nothing. The cost trap is API calls from an application that fetches on every request instead of caching, at high request rates that runs into tens of dollars a month and will hit API throttling limits before it hits your budget.

Why does my application get ResourceNotFoundException for a secret that exists?

Usually a region mismatch. Secrets are regional, and the SDK defaults to whatever region the environment supplies, which may not be where the secret lives. Set the region explicitly in the client. The other frequent cause is a partially-created secret in a CreateSecret that failed, or a secret that's inside its deletion recovery window. During that window it exists but is unreadable, and describe-secret will show a DeletedDate.

Can I recover a deleted secret?

Yes, if it was deleted with a recovery window. The default is 30 days and the minimum is 7, and aws secretsmanager restore-secret --secret-id <name> brings it back within that period. If it was deleted with --force-delete-without-recovery, it is gone permanently. That flag also reserves the name for a period, which is a common source of failures in scripts that tear down and recreate test environments.

How do I inject a secret into a container without calling the API in my code?

On ECS, reference the secret ARN in the task definition's secrets block and the agent injects it as an environment variable at start-up; appending :key:: to the ARN pulls a single field out of a JSON secret. On EKS, use the Secrets Store CSI driver with the AWS provider, which mounts the secret as a file and can sync it to a native Kubernetes Secret. Both approaches keep the credential out of your image, out of your source, and out of application code.

What happens to running applications while a secret rotates?

Rotation promotes a new version by moving the AWSCURRENT staging label; the previous version keeps the AWSPREVIOUS label and remains readable. With alternating-user rotation both credentials authenticate successfully throughout, so nothing fails. With single-user rotation there is a brief window where a cached old password is rejected, so applications need to catch authentication failures, re-read the secret, and retry. This is the main reason to prefer alternating users for anything latency- or availability-sensitive.

Continue Learning

Explore Related Topics

When it breaks

Related Resources