Post

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.

Week 2 — Day 8: AWS Secrets Manager & Parameter Store

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

  1. Secrets Manager → Store a new secret
  2. Secret type: Credentials for Amazon RDS database (or “Other type of secret” for custom)
  3. Enter username and password
  4. Select the RDS instance (Secrets Manager links the secret to the DB for rotation)
  5. Name: prod/myapp/db-password
  6. 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):

  1. Secrets Manager → select your secret → Edit rotation
  2. Enable automatic rotation
  3. Rotation schedule: every 30 days
  4. 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:

  1. Lambda creates a new password on the database
  2. Updates the secret in Secrets Manager
  3. Tests the new credentials
  4. 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 ManagerParameter Store
Cost~$0.40/secret/monthFree (Standard tier)
Auto rotationYes (built-in)No
Cross-accountYesLimited
Max size65KB4KB (Standard), 8KB (Advanced)
Best forDB passwords, API keys needing rotationConfig values, feature flags, non-rotating secrets

Use Secrets Manager when you need rotation. Use Parameter Store for everything else.


Parameter Types

TypeDescription
StringPlaintext value
StringListComma-separated list
SecureStringEncrypted with KMS

Always use SecureString for sensitive values.


Creating Parameters

  1. Systems Manager → Parameter Store → Create parameter
  2. Name: /prod/myapp/api-key
  3. Tier: Standard
  4. Type: SecureString
  5. KMS key: use your CMK or the default aws/ssm key
  6. Value: paste your secret value
  7. 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.

  1. Secrets Manager → Store a new secret → Other type of secret
  2. Key: username, value: dbadmin
  3. Key: password, value: S3cr3tP@ssword!
  4. Name: lab/testapp/db-creds → Store

Secrets Manager → the newly created secret showing its name, ARN, and “Last retrieved” timestamp

  1. 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']}")
  1. 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

  1. Go back to Secrets Manager → enable rotation for the secret using the Lambda template
  2. Trigger rotation manually: Actions → Rotate secret immediately
  3. 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:GetSecretValue on *
  • ECS and Lambda can inject secrets directly via the secrets block — no custom code needed for basic cases

References


You can find me online at:

My signature image

This post is licensed under CC BY 4.0 by the author.