DEV Community

AlpeshKumbhare
AlpeshKumbhare

Posted on

AWS Secrets Management: Secrets Manager vs Parameter Store vs KMS — The Complete Decision Guide

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                  │
└──────────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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']
Enter fullscreen mode Exit fullscreen mode

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)    │
└─────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

For EKS Specifically

Two clean patterns:

  1. External Secrets Operator — syncs Secrets Manager / Parameter Store into Kubernetes secrets
  2. 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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Summary

AWS secrets management comes down to matching the store to the need:

  1. Secrets Manager — rotating secrets, database credentials, cross-region/cross-account. Worth $0.40/secret/month for the rotation and integration.
  2. Parameter Store — configuration and static secrets. Free standard tier makes it the default for anything not rotating.
  3. 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)