Use AWS Secrets Manager with Python on Elastic Beanstalk¶
This recipe shows how to read application secrets from AWS Secrets Manager at runtime from a Python Elastic Beanstalk environment. It keeps credentials out of source control and avoids storing long-lived secret values directly in environment properties.
Prerequisites¶
- Running Python Elastic Beanstalk environment.
- Instance profile permission for
secretsmanager:GetSecretValueon the target secret. - Existing secret in AWS Secrets Manager.
boto3available in the application environment.
What You'll Build¶
You will build a Flask route that loads a JSON secret from AWS Secrets Manager by using the Elastic Beanstalk instance profile.
flowchart LR
A[Flask App on Elastic Beanstalk] --> B[EC2 Instance Profile]
B --> C[AWS Secrets Manager]
C --> D[Application Secret JSON] Steps¶
Step 1: Create a secret and record its ARN¶
aws secretsmanager create-secret \
--name "$APP_NAME/database" \
--secret-string '{"username":"appuser","password":"<db-password>"}' \
--region "$REGION"
Step 2: Grant the Elastic Beanstalk instance profile access¶
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:$REGION:<account-id>:secret:$APP_NAME/database-*"
}
]
}
Attach the policy to the instance profile role used by your environment.
Step 3: Store the secret identifier as an environment property¶
aws elasticbeanstalk update-environment \
--application-name "$APP_NAME" \
--environment-name "$ENV_NAME" \
--option-settings Namespace=aws:elasticbeanstalk:application:environment,OptionName=APP_SECRET_ID,Value="$APP_NAME/database" \
--region "$REGION"
Step 4: Load the secret in Flask with boto3¶
import json
import os
import boto3
from flask import Flask
application = Flask(__name__)
def get_secret(secret_id: str) -> dict:
client = boto3.client("secretsmanager", region_name=os.environ["AWS_REGION"])
response = client.get_secret_value(SecretId=secret_id)
return json.loads(response["SecretString"])
@application.get("/secret-check")
def secret_check():
secret = get_secret(os.environ["APP_SECRET_ID"])
return {
"username": secret["username"],
"password_loaded": bool(secret["password"])
}
Step 5: Deploy and validate¶
Verification¶
Expected result: the route returns the secret metadata without exposing the raw password value.
Clean Up¶
aws secretsmanager delete-secret \
--secret-id "$APP_NAME/database" \
--force-delete-without-recovery \
--region "$REGION"
Also remove the IAM policy statement and the APP_SECRET_ID environment property when you no longer need the integration.