Rotate RDS credentials with AWS Secrets Manager
AWS Secrets Manager has turnkey rotation for RDS — it provisions a new password, updates the database, and stores the new value. Your Python app’s only job is to pick up the change without a failed query. This page handles the app side, extending AWS Secrets Manager Integration.
Problem 1: caching the password forever
# ANTI-PATTERN: connection built once with a password that will rotate
ENGINE = create_engine(get_secret("prod/rds")["password"]) # stale after rotation
When Secrets Manager rotates the password, every connection in this pool fails.
Problem 2: fetching on every query
# ANTI-PATTERN: an ASM call per query — throttled and slow
def query():
pw = get_secret("prod/rds")["password"] # API call per query
This hammers the Secrets Manager API and adds latency to every database call.
Secure implementation
# db/rds.py
import json, time, boto3
from pydantic import SecretStr
from sqlalchemy import create_engine
_client = boto3.client("secretsmanager")
_cache: dict | None = None
_loaded = 0.0
TTL = 300 # below the rotation interval
def _creds() -> dict:
global _cache, _loaded
if _cache is None or time.monotonic() - _loaded > TTL:
raw = _client.get_secret_value(SecretId="prod/rds")["SecretString"]
_cache, _loaded = json.loads(raw), time.monotonic()
return _cache
def make_engine():
c = _creds()
pw = SecretStr(c["password"]).get_secret_value()
return create_engine(f"postgresql://{c['username']}:{pw}@{c['host']}/{c['dbname']}",
pool_pre_ping=True) # drops dead connections after rotation
The TTL cache picks up the rotated password within the window; pool_pre_ping=True discards connections invalidated by the rotation so SQLAlchemy reconnects with the new credential.
Gotchas & version-specific behaviour
- Secrets Manager RDS rotation uses two AWS-managed users alternately — both work during the overlap, so a short TTL never sees a hard cutover.
- Set the cache TTL below the rotation interval.
pool_pre_ping=True(SQLAlchemy) is the cheapest way to drop connections killed by rotation.- Grant the rotation Lambda its own role; the app only needs
GetSecretValue.
Production parity checklist
- Rotation is enabled on the RDS secret with an AWS-managed schedule.
- The app caches credentials with a TTL below the rotation interval.
- The connection pool drops stale connections (
pool_pre_ping). - App IAM is scoped to
GetSecretValueon the secret ARN. - A staging test forces rotation and asserts no failed queries.
Conclusion
Let Secrets Manager rotate the RDS password; on the app side a short-TTL cache plus pool_pre_ping makes the change invisible. For the general pattern, see Automated Secret Rotation Patterns.