How to Move a Plaintext Secret to AWS Secrets Manager
An env var like DB_PASSWORD shows up in your deployment manifest, every container layer, and docker inspect output - all potential leak surfaces. AWS Secrets Manager keeps the secret out of all of those. Here's how to refactor the fetch.
Why env vars are the wrong place for secrets
When you write DB_PASSWORD=supersecret in a Kubernetes manifest or a
docker run -e command, that value is now in:
- the manifest committed to version control
docker inspect <container>output - readable by anyone with Docker socket access- CI/CD logs if the env dump is ever printed
- any crash dump or debug output that calls
os.environ
AWS Secrets Manager centralizes secrets, scopes access via IAM, and supports rotation. The app fetches the secret at boot - the plaintext never lives in a deployment config.
The refactor
Replace the env-var read with a boto3 call:
import os
import boto3
def load_password() -> str:
sm = boto3.client(
"secretsmanager",
endpoint_url=os.environ.get("AWS_ENDPOINT_URL"), # moto in dev
region_name=os.environ.get("AWS_DEFAULT_REGION", "us-east-1"),
)
return sm.get_secret_value(SecretId="app/db/password")["SecretString"]
Call load_password() once at startup and cache the result - not on every
request. The endpoint_url parameter lets you point at a local mock (moto)
during development and real AWS in production without changing the code.
Create the secret (one-time setup)
aws secretsmanager create-secret \
--name app/db/password \
--secret-string "supersecret"
Verify it was stored correctly:
aws secretsmanager get-secret-value --secret-id app/db/password
IAM policy (least privilege)
The pod's IAM role should grant GetSecretValue on the specific secret ARN
only - not a wildcard over all secrets in the account:
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:app/db/password-*"
}
Caching and rotation
Fetch once at boot and cache in a module-level variable. For long-running services, refresh periodically (every few minutes) so the app picks up rotated secrets without a redeploy:
import time
_cached_password = None
_fetched_at = 0
TTL = 300 # 5 minutes
def get_password() -> str:
global _cached_password, _fetched_at
if time.time() - _fetched_at > TTL:
_cached_password = load_password()
_fetched_at = time.time()
return _cached_password
Storing structured secrets
Secrets Manager supports JSON strings, which lets you store multiple fields under one secret:
aws secretsmanager create-secret \
--name app/db \
--secret-string '{"host":"db.internal","port":5432,"password":"supersecret"}'
Parse it with json.loads(value) after fetching.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Replacing os.environ secret reads with a boto3 Secrets Manager fetch
- Scoping an IAM policy to GetSecretValue on a specific secret ARN
- Caching the fetched secret and refreshing it periodically to survive rotation
FAQ
Why is storing a DB password in an environment variable a security risk?
Env vars appear in deployment manifests, docker inspect output, CI logs, and crash dumps - any of these can leak the plaintext secret. AWS Secrets Manager keeps the secret out of all of those and scopes access via IAM.
How do I fetch a secret from AWS Secrets Manager in Python?
Use boto3: boto3.client('secretsmanager').get_secret_value(SecretId='app/db/password')['SecretString']. Fetch once at startup and cache it - do not call this on every request.
How do I test AWS Secrets Manager locally without a real AWS account?
Use moto, a Python library that mocks AWS APIs locally. Set AWS_ENDPOINT_URL=http://localhost:5000 and pass it as endpoint_url to boto3.client - the same code works against real AWS in production.
What is AWS Secrets Manager?
AWS Secrets Manager stores secrets like database passwords and API keys, encrypts them with KMS, controls access with IAM, and can rotate them automatically. Apps fetch the secret at runtime instead of hardcoding it.
What is the difference between AWS KMS and Secrets Manager?
KMS manages encryption keys and performs encrypt/decrypt; Secrets Manager stores the actual secret values and uses KMS to encrypt them. Use KMS for keys, Secrets Manager for the secrets themselves.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →