AWS Secrets Manager
A managed store for database passwords, API keys, and tokens that compute reads at runtime instead of baking into an image — with optional automatic rotation. Here's when it beats Parameter Store, what it costs, and the secret-handling mistakes Design Beaver catches as you draw.
What Secrets Manager is
Secrets Manager stores a value — a password, an API key, a JSON blob of related credentials — encrypted with KMS, and hands it out over an API call to whoever you’ve granted permission. The point is that the secret never lives in your source code, your container image, or a plaintext environment variable. The running app fetches it at startup or on demand.
Its other headline feature is rotation. Turn it on with a schedule and Secrets Manager invokes a Lambda function to generate a new value and update the secret, with no redeploy on your side. For RDS, Aurora, Redshift, and DocumentDB, AWS supplies that rotation function for you.
Design Beaver models Secrets Manager as a regional store that compute reads from, so it validates as you draw which principals can read a secret and what that read actually requires.
When to use Secrets Manager (and when not to)
Reach for it when the credential should rotate automatically — database passwords are the case it was built for. It also earns its place when several compute principals read one secret and each needs its own IAM grant, or when you want a value injected into an ECS task by reference rather than sitting in the task’s plain environment.
Don’t reach for it for non-sensitive configuration. Feature flags and endpoint URLs belong in SSM Parameter Store standard parameters, which cost nothing per parameter. And if you have a sensitive value you honestly will never rotate, an SSM Parameter Store SecureString is KMS-encrypted and cheaper — rotation is most of what the per-secret fee buys.
Variants: rotation on or off
These aren’t separate products. They’re the two postures you pick when you create a secret, and the choice decides whether you’re getting your money’s worth.
| Option | What it is |
|---|---|
| Secret with managed rotation | Rotation turned on with a schedule; Secrets Manager invokes a rotation Lambda (an AWS-provided one for RDS/Aurora/Redshift/DocumentDB, or your own) to replace the value periodically. The right choice for database credentials. |
| Secret without rotationdefault | A stored secret you update manually. Fine for values that rarely change (some third-party API keys); for these the cost/rotation edge over an SSM SecureString is smaller. |
Secrets Manager pricing in plain English
You pay to store each secret and you pay for the API calls that read it. The second one is the surprise, and it’s entirely in your control.
Pay per secret stored per month, plus a charge per block of API calls (GetSecretValue etc.). No upfront cost.
| Option | Representative rate |
|---|---|
| per-secret | $0.40 per secret per month (prorated by the hour if stored less than a month) |
| per-api-call | $0.05 per 10,000 API calls |
Keeping the bill down
- Cache the secret in the client rather than calling GetSecretValue on every request — API calls are billed per 10k
- For non-rotating, non-sensitive config, use SSM Parameter Store standard parameters (no per-parameter charge) instead
us-east-1 (rates vary by region). Rates as of 2026-07. Verify at the official pricing page before using for real cost estimates — this list is not kept in sync with AWS pricing changes.
How Secrets Manager connects to other services
Every inbound edge is a read, and the permission always sits on the reader — never on Secrets Manager itself.
An ECS task reads a secret at startup — e.g. a DB password or API key injected into the container by reference
A Lambda function reads a secret at runtime via the SDK (or the Secrets Manager extension/layer) to get a DB credential or API key
An application on the EC2 instance reads a secret via the SDK using the instance profile, instead of storing credentials on the instance
An App Runner service reads a secret by referencing it in the service configuration, rather than setting the value as a plain environment variable
RDS Proxy is associated with a Secrets Manager secret holding the database username/password and reads it to open the pooled connection to the database
With rotation turned on, Secrets Manager invokes a rotation Lambda on the configured schedule to generate and store a new secret value
The reader’s own role grants secretsmanager:GetSecretValue (and usually secretsmanager:DescribeSecret) scoped to that secret’s ARN. If you encrypted the secret with a customer-managed KMS key, that same role also needs kms:Decrypt on the key. Inject the value by reference; don’t copy it into the image or a plain environment variable.
ECS is the one worth reading twice, because it has two roles and the right one depends on the delivery path. If your code calls GetSecretValue itself at runtime, the permission goes on the task role. If the task definition’s secrets block injects the value as an environment variable, it goes on the execution role — the agent resolves it before your container starts. Putting it on the wrong one fails in a way that points at the secret rather than at the role.
Rotation runs the other direction, and it works differently. Secrets Manager invokes the rotation Lambda, which is a resource-based permission — the function’s resource policy grants lambda:InvokeFunction to the secretsmanager.amazonaws.com service principal. There’s no execution role attached to Secrets Manager. The rotation function’s own execution role separately needs read and write access to the secret it rotates.
RDS Proxy is the one edge that isn’t application code: the proxy itself reads the database credentials from a secret to open its pooled connections.
What Secrets Manager can’t connect to
A credential store looks like it should touch everything. In practice it only touches the things that read credentials.
No relationship — Route 53 is DNS and Secrets Manager is a credential store; neither reads from nor points at the other
No native direct integration — CloudFront is a CDN in front of an origin and never reads application secrets from Secrets Manager as an architectural edge
No direct integration — a load balancer routes traffic and does not read secrets from Secrets Manager; the compute behind it is what reads the secret
Peer services with no native direct edge — S3 stores objects, Secrets Manager stores secrets; an app would use each independently rather than connecting them
Peer services with no native direct edge — DynamoDB is a data store and Secrets Manager a credential store; there is no drawable connection between them
Anti-patterns Design Beaver catches
These are the three ways a secrets architecture quietly fails to be a secrets architecture.
Hardcoding database credentials or API keys into the container image or plain environment variables
Why it breaksThe secret ends up in image layers, source control, and process listings, and can't be rotated without a redeploy
Do this insteadStore the value in Secrets Manager and inject it by reference (task/execution role granting secretsmanager:GetSecretValue), reading it at runtime
Storing database credentials in a secret but never enabling rotation
Why it breaksA long-lived static credential is exactly what Secrets Manager's rotation exists to eliminate; leaving it off gives up the main reason to pay for Secrets Manager over an SSM SecureString
Do this insteadTurn on scheduled rotation with the AWS-provided rotation Lambda for RDS/Aurora, so the password changes automatically
Storing a secret but granting secretsmanager:GetSecretValue broadly (e.g. on all secrets) instead of scoping it
Why it breaksAny principal with the broad grant can read every secret, defeating per-secret access control
Do this insteadScope GetSecretValue to the specific secret ARN in each principal's role, and use a resource policy on the secret if you need to restrict further
Gotchas that bite in production
- ECS injects at container start. Rotate the secret and the running container keeps the old value until the task restarts. The injected variable isn’t refreshed live.
- Rotation off means a static credential. That’s the same security posture as a hardcoded password, except you’re now also paying for it.
- A broad
GetSecretValuegrant reads every secret. Scope it to the specific ARN in each role. A wildcard grant hands any holder your whole store. - Customer-managed KMS keys need a second permission. Without
kms:Decrypton the key, the read fails even withGetSecretValuecorrectly granted — and the error points at KMS, not at the secret.
Further reading
- Official AWS documentation
- Rotate secrets by Lambda function
- Pass Secrets Manager secrets through ECS environment variables
- Common AWS security anti-patterns
Frequently asked questions
When should you use AWS Secrets Manager instead of SSM Parameter Store?
What IAM permissions does a service need to read a secret?
secretsmanager:GetSecretValue, and usually secretsmanager:DescribeSecret, scoped to that secret's ARN — the Lambda execution role, the EC2 instance profile, or the App Runner instance role. ECS is the one with two answers, and which role you need depends on how the value gets in — if your application code reads the secret at runtime through the SDK, it's the task role; if the task definition's secrets block injects it as an environment variable at container start, it's the execution role, because the agent does that fetch before your code runs. If the secret uses a customer-managed KMS key, that same role also needs kms:Decrypt. Either way the permission lives on the reader, never on Secrets Manager.Does rotating a secret update a running ECS task?
How much does AWS Secrets Manager cost?
GetSecretValue on every request. Verify current rates on the official pricing page before estimating a real bill.Can an Application Load Balancer or CloudFront read from Secrets Manager?
Validate your Secrets Manager architecture as you draw
Design Beaver checks your AWS design in real time — missing queues, invalid connections, and security anti-patterns, caught before you ship. It’s live in beta, free, and runs in your browser. Sign in with Google or GitHub to save your work.
Sign up for free! →Prefer email? Get new features in your inbox: