Week 2 — Day 8: AWS Secrets Manager & Parameter Store
A full walkthrough of AWS Secrets Manager and SSM Parameter Store — how to store, rotate, and retrieve secrets securely without hardcoding credentials anywhere.
The Problem With Hardcoded Credentials
Hardcoded credentials in source code, environment variables in plaintext, or .env files committed to git — these are among the most common causes of cloud breaches. The fix is centralized secrets management.
AWS offers two services for this:
- Secrets Manager — for secrets that need automatic rotation (DB passwords, API keys)
- SSM Parameter Store — for configuration values and simpler secrets (no auto-rotation needed)
AWS Secrets Manager
What It Stores
- Database credentials (RDS, Redshift, DocumentDB)
- API keys and OAuth tokens
- SSH keys
- Any arbitrary text or binary up to 65KB
Creating a Secret
- Secrets Manager → Store a new secret
- Secret type: Credentials for Amazon RDS database (or “Other type of secret” for custom)
- Enter username and password
- Select the RDS instance (Secrets Manager links the secret to the DB for rotation)
- Name:
prod/myapp/db-password - Store
— Secrets Manager → Store a new secret wizard showing the secret type selection (RDS credentials) and the username/password fields
Naming convention: Use a path structure like env/app/secret-name — it helps with IAM policies and organization.
Retrieving a Secret
From CLI:
1
2
3
4
aws secretsmanager get-secret-value \
--secret-id prod/myapp/db-password \
--query SecretString \
--output text
From Python (boto3):
1
2
3
4
5
6
7
8
9
10
import boto3
import json
client = boto3.client('secretsmanager', region_name='ap-southeast-1')
response = client.get_secret_value(SecretId='prod/myapp/db-password')
secret = json.loads(response['SecretString'])
db_user = secret['username']
db_pass = secret['password']
— Secrets Manager → a secret detail page showing the secret name, ARN, description, rotation status, and the “Retrieve secret value” button
The application never stores the password — it calls Secrets Manager at runtime. The IAM role on the EC2/Lambda must have secretsmanager:GetSecretValue permission on that specific secret ARN.
IAM Policy for Secret Access
1
2
3
4
5
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:ap-southeast-1:123456789:secret:prod/myapp/*"
}
Scope to the exact path — don’t allow * on all secrets.
Automatic Secret Rotation
Secrets Manager can automatically rotate secrets on a schedule using a Lambda function.
For RDS (supported natively):
- Secrets Manager → select your secret → Edit rotation
- Enable automatic rotation
- Rotation schedule: every 30 days
- Rotation function: use the AWS-provided template for your DB engine
— Secrets Manager → Edit rotation panel showing “Automatic rotation” toggled on, rotation schedule set to 30 days, and the Lambda function ARN selected
What happens during rotation:
- Lambda creates a new password on the database
- Updates the secret in Secrets Manager
- Tests the new credentials
- Marks rotation complete
Your application using get_secret_value automatically gets the new password on the next call — no redeployment needed.
Secrets Manager in ECS and Lambda
ECS task definition — inject secret as environment variable:
1
2
3
4
5
6
7
8
{
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:ap-southeast-1:123456789:secret:prod/myapp/db-password"
}
]
}
Lambda — reference secret as environment variable: Same pattern — reference the secret ARN in the Lambda environment variables config.
— ECS task definition JSON editor showing the “secrets” block with a secret ARN reference for DB_PASSWORD
SSM Parameter Store
Secrets Manager vs Parameter Store
| Secrets Manager | Parameter Store | |
|---|---|---|
| Cost | ~$0.40/secret/month | Free (Standard tier) |
| Auto rotation | Yes (built-in) | No |
| Cross-account | Yes | Limited |
| Max size | 65KB | 4KB (Standard), 8KB (Advanced) |
| Best for | DB passwords, API keys needing rotation | Config values, feature flags, non-rotating secrets |
Use Secrets Manager when you need rotation. Use Parameter Store for everything else.
Parameter Types
| Type | Description |
|---|---|
String | Plaintext value |
StringList | Comma-separated list |
SecureString | Encrypted with KMS |
Always use SecureString for sensitive values.
Creating Parameters
- Systems Manager → Parameter Store → Create parameter
- Name:
/prod/myapp/api-key - Tier: Standard
- Type: SecureString
- KMS key: use your CMK or the default
aws/ssmkey - Value: paste your secret value
- Create
— SSM Parameter Store → Create parameter form showing the name “/prod/myapp/api-key”, type SecureString, and KMS key selection
Retrieving Parameters
CLI:
1
2
3
4
5
6
7
8
9
10
11
12
# Get a single parameter (decrypted)
aws ssm get-parameter \
--name /prod/myapp/api-key \
--with-decryption \
--query Parameter.Value \
--output text
# Get all parameters under a path
aws ssm get-parameters-by-path \
--path /prod/myapp/ \
--with-decryption \
--recursive
Python:
1
2
3
4
5
6
7
8
9
import boto3
ssm = boto3.client('ssm', region_name='ap-southeast-1')
response = ssm.get_parameter(
Name='/prod/myapp/api-key',
WithDecryption=True
)
api_key = response['Parameter']['Value']
— Terminal showing the output of the get-parameter CLI command returning the decrypted value
Parameter Store in ECS and Lambda
ECS task definition:
1
2
3
4
5
6
7
8
{
"secrets": [
{
"name": "API_KEY",
"valueFrom": "arn:aws:ssm:ap-southeast-1:123456789:parameter/prod/myapp/api-key"
}
]
}
The same secrets block in ECS task definitions works for both Secrets Manager and Parameter Store — just change the ARN format.
Lab — Store and Retrieve a DB Password
Objective: Store a fake DB password in Secrets Manager, retrieve it in a Python script.
- Secrets Manager → Store a new secret → Other type of secret
- Key:
username, value:dbadmin - Key:
password, value:S3cr3tP@ssword! - Name:
lab/testapp/db-creds→ Store
— Secrets Manager → the newly created secret showing its name, ARN, and “Last retrieved” timestamp
- Create a Python script locally:
1
2
3
4
5
6
7
8
9
10
import boto3
import json
client = boto3.client('secretsmanager', region_name='ap-southeast-1')
response = client.get_secret_value(SecretId='lab/testapp/db-creds')
creds = json.loads(response['SecretString'])
print(f"User: {creds['username']}")
print(f"Pass: {creds['password']}")
- Run the script — confirm it retrieves the values without them being in the code
— Terminal showing the Python script output printing the username and password retrieved from Secrets Manager
- Go back to Secrets Manager → enable rotation for the secret using the Lambda template
- Trigger rotation manually: Actions → Rotate secret immediately
- Re-run the script — it should return the new rotated password
— Secrets Manager → secret detail showing rotation enabled, last rotated timestamp updated, and rotation status “Successful”
Key Takeaways
- Never hardcode credentials — retrieve them at runtime from Secrets Manager or Parameter Store
- Use Secrets Manager when you need automatic rotation — especially for DB passwords
- Use Parameter Store for non-rotating config values — it’s free at the Standard tier
- Scope IAM permissions to specific secret paths — never
secretsmanager:GetSecretValueon* - ECS and Lambda can inject secrets directly via the
secretsblock — no custom code needed for basic cases

