Secrets management is one of those decisions you make on day zero and regret in month six if you get it wrong. Pick the wrong store and you'll either rewrite your bootstrap code later or pay thousands a year for configuration that could have been stored for free.
AWS gives you two primary stores — Secrets Manager and Systems Manager Parameter Store — plus KMS underpinning both. They overlap enough to be confusing but differ enough that the choice matters. This guide breaks down when to use each, with cost, rotation, and access patterns.
The Core Distinction
┌──────────────────────────────────────────────────────────────────┐
│ SECRETS MANAGER │ PARAMETER STORE (SSM) │
│ │ │
│ Purpose-built for │ General-purpose config store │
│ SECRETS that rotate │ that ALSO holds secrets │
│ │ │
│ • Automatic rotation │ • Free standard tier │
│ • Cross-region replica │ • Config + secrets together │
│ • Cross-account sharing │ • Hierarchical paths │
│ • ~$0.40/secret/month │ • SecureString via KMS │
│ • Built-in DB integration│ • No native rotation │
└──────────────────────────────────────────────────────────────────┘
One-line rule: If it needs to rotate, use Secrets Manager. If it's configuration (even encrypted config), use Parameter Store.
Quick Decision Matrix
| Requirement | Use |
|---|---|
| Database credentials with auto-rotation | Secrets Manager |
| API keys that must rotate on schedule | Secrets Manager |
| Cross-region secret replication | Secrets Manager |
| Cross-account secret sharing | Secrets Manager |
| Application config (URLs, feature flags) | Parameter Store (Standard) |
| Static secrets that rarely change | Parameter Store (SecureString) |
| Free tier / cost-sensitive | Parameter Store (Standard) |
| Large parameters (up to 8KB) | Parameter Store (Advanced) |
| Encryption keys themselves | KMS |
AWS Secrets Manager
Purpose-built for secrets that need lifecycle management — rotation, replication, and controlled sharing.
Key Capabilities
| Feature | Detail |
|---|---|
| Automatic rotation | Lambda-driven rotation on a schedule (built-in support for RDS, Aurora, Redshift, DocumentDB) |
| Cross-region replication | Replicate secrets to other regions for DR and low-latency access |
| Cross-account access | Resource policies allow sharing secrets across accounts |
| Version staging | AWSCURRENT / AWSPENDING / AWSPREVIOUS labels for safe rotation |
| KMS encryption | All secrets encrypted with KMS (customer-managed or AWS-managed key) |
| Fine-grained IAM | Control access per secret via IAM + resource policies |
Automatic Rotation
This is the killer feature. For supported databases, Secrets Manager handles the entire rotation dance:
Rotation schedule triggers (e.g., every 30 days)
│
▼
Lambda rotation function:
1. Create new credential (AWSPENDING)
2. Update credential in the database
3. Test new credential works
4. Mark new credential AWSCURRENT
5. Old credential → AWSPREVIOUS (grace period)
Applications always request AWSCURRENT — they get the latest valid credential without knowing rotation happened.
Retrieving a Secret
import boto3, json
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId='prod/db/credentials')
secret = json.loads(response['SecretString'])
# Use secret['username'], secret['password']
Best practice: Cache the secret (SDK caching library or Lambda extension) — don't call get_secret_value on every request. It's an API call with cost and latency.
Cost
- $0.40 per secret per month
- $0.05 per 10,000 API calls
At 100 secrets, that's ~$40/month before API calls. This adds up — which is why you shouldn't put non-rotating config here.
Systems Manager Parameter Store
A general-purpose hierarchical store for configuration and secrets. The free standard tier makes it the default home for anything that doesn't need rotation.
Parameter Types
| Type | Encrypted | Use For |
|---|---|---|
| String | No | Plain config (URLs, region names, feature flags) |
| StringList | No | Comma-separated lists |
| SecureString | Yes (KMS) | Secrets that don't need auto-rotation |
Standard vs Advanced Tier
| Feature | Standard | Advanced |
|---|---|---|
| Cost | Free | $0.05/parameter/month |
| Max parameters | 10,000 | 100,000 |
| Max value size | 4 KB | 8 KB |
| Parameter policies (expiration, notification) | ❌ | ✅ |
| Higher throughput | ❌ | ✅ |
Hierarchical Organization
Parameter Store shines with path-based hierarchies:
/myapp/prod/db/host
/myapp/prod/db/port
/myapp/prod/api/endpoint
/myapp/staging/db/host
/myapp/dev/db/host
Fetch an entire branch with one call:
import boto3
ssm = boto3.client('ssm')
response = ssm.get_parameters_by_path(
Path='/myapp/prod/',
Recursive=True,
WithDecryption=True
)
# Returns all prod parameters in one call
Retrieving a Parameter
import boto3
ssm = boto3.client('ssm')
value = ssm.get_parameter(
Name='/myapp/prod/db/password',
WithDecryption=True # decrypts SecureString via KMS
)['Parameter']['Value']
Secrets Manager vs Parameter Store: Side by Side
| Criteria | Secrets Manager | Parameter Store |
|---|---|---|
| Primary purpose | Secrets with lifecycle | Config + secrets |
| Automatic rotation | ✅ Built-in | ❌ (DIY with Lambda + EventBridge) |
| Cost | $0.40/secret/month | Free (Standard) |
| Cross-region replication | ✅ Native | ❌ (manual) |
| Cross-account | ✅ Resource policies | ✅ (via RAM / advanced) |
| Max value size | 64 KB | 4 KB (Std) / 8 KB (Adv) |
| Version history | ✅ Staging labels | ✅ Version numbers |
| DB integration | ✅ RDS/Aurora/Redshift/DocDB | ❌ |
| Hierarchical paths | ❌ (naming convention only) | ✅ Native |
| KMS encryption | ✅ Always | ✅ (SecureString only) |
Where KMS Fits
KMS (Key Management Service) is the encryption layer underneath both — it doesn't store secrets, it manages the keys that encrypt them.
┌─────────────────────────────────────────────────┐
│ Secrets Manager / Parameter Store (SecureString) │
│ │ │
│ │ encrypts secret value using... │
│ ▼ │
│ KMS Key (customer-managed or AWS-managed) │
└─────────────────────────────────────────────────┘
When You Interact With KMS Directly
- Envelope encryption for your own data (encrypt files, EBS, S3 objects)
- Key policies controlling who can decrypt (even admins can be excluded)
- Cross-account key sharing for shared encrypted resources
- Audit — every decrypt operation logged to CloudTrail
KMS vs CloudHSM
| KMS | CloudHSM | |
|---|---|---|
| Management | Fully managed | You manage the HSM |
| Tenancy | Multi-tenant (FIPS 140-2 L3 available) | Single-tenant dedicated HSM |
| Use case | 99% of encryption needs | Strict compliance requiring dedicated hardware |
| Cost | Per key + per request | Per HSM hour (expensive) |
Rule: Use KMS unless a specific regulation mandates dedicated single-tenant HSMs.
Access Patterns
For EC2 / ECS / EKS
Use IAM roles (instance profile, task role, IRSA) — never hardcode credentials:
Application → assumes IAM role → role has secretsmanager:GetSecretValue
→ on specific secret ARN only (least privilege)
For EKS Specifically
Two clean patterns:
- External Secrets Operator — syncs Secrets Manager / Parameter Store into Kubernetes secrets
- Secrets Store CSI Driver — mounts secrets directly into pods as volumes (never stored in etcd)
For Lambda
Use the Parameters and Secrets Lambda Extension — caches secrets locally, reducing API calls and latency:
Lambda → localhost:2773 (extension cache) → Secrets Manager (only on cache miss)
Cost Optimization
The most common mistake: storing everything in Secrets Manager.
| Scenario | Wrong (costly) | Right |
|---|---|---|
| 200 app config values | 200 × $0.40 = $80/month in Secrets Manager | Parameter Store Standard = free |
| 5 database passwords (rotating) | Parameter Store + custom rotation Lambda (fragile) | Secrets Manager = $2/month + reliable rotation |
| Feature flags | Secrets Manager | Parameter Store or AppConfig |
| TLS private keys | Parameter Store SecureString | Secrets Manager (needs rotation) or ACM |
Strategy: Config → Parameter Store (free). Rotating secrets → Secrets Manager (worth the cost). Non-rotating secrets → Parameter Store SecureString.
Rotation Without Secrets Manager
If you must rotate a Parameter Store secret (to save cost), build it yourself:
EventBridge Scheduler (every 30 days)
│
▼
Lambda rotation function:
1. Generate new credential
2. Update the target system
3. Update Parameter Store SecureString
4. Notify dependents (or they poll)
But honestly — if you need reliable rotation, Secrets Manager's $0.40/month is cheaper than maintaining this yourself. Only DIY when you have many secrets and rotation is simple.
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Everything in Secrets Manager | Paying $0.40/month for static config | Config → Parameter Store (free) |
| Hardcoded secrets in code/env vars | Exposure risk, no rotation | IAM role + Secrets Manager/Parameter Store |
| Calling GetSecretValue every request | Latency + API cost | Cache (SDK caching or Lambda extension) |
| No least-privilege on secret access | Any role can read all secrets | Scope IAM to specific secret ARNs |
| SecureString for rotating DB creds | Manual rotation is fragile | Secrets Manager with auto-rotation |
| No CloudTrail on secret access | Can't audit who read what | Enable CloudTrail (both services log) |
| Committing secrets to Git | Permanent exposure | git-secrets pre-commit + rotate immediately |
Decision Flowchart
START
│
├── Is it an encryption KEY (not a secret value)?
│ └── YES → KMS (or CloudHSM if dedicated HSM required)
│
├── Does it need automatic rotation?
│ └── YES → Secrets Manager
│
├── Is it a database credential (RDS/Aurora/Redshift/DocDB)?
│ └── YES → Secrets Manager (native integration)
│
├── Does it need cross-region replication?
│ └── YES → Secrets Manager
│
├── Is it a secret that rarely/never rotates?
│ └── YES → Parameter Store (SecureString)
│
└── Is it plain configuration?
└── YES → Parameter Store (String, Standard tier — free)
Summary
AWS secrets management comes down to matching the store to the need:
- Secrets Manager — rotating secrets, database credentials, cross-region/cross-account. Worth $0.40/secret/month for the rotation and integration.
- Parameter Store — configuration and static secrets. Free standard tier makes it the default for anything not rotating.
- KMS — the encryption layer under both. Direct use for envelope encryption and key policies.
The guiding principle: Don't pay Secrets Manager prices for Parameter Store problems. Config and static values go in Parameter Store (free). Reserve Secrets Manager for what actually needs rotation, replication, or database integration. And never — ever — hardcode secrets in code or environment variables when an IAM role + managed store does it securely.
Alpesh Kumbhare is an AWS Architect at Atos, specializing in AWS security architecture and cloud infrastructure automation. Connect on LinkedIn.
Top comments (0)