Use IAM Instance Profiles with Python on Elastic Beanstalk¶
This recipe shows how to grant AWS API access to Elastic Beanstalk instances by using an IAM instance profile instead of static credentials. It is the standard AWS pattern for app-to-service access from EC2-based environments.
Prerequisites¶
- Running Python Elastic Beanstalk environment.
- Permission to manage IAM roles, policies, and instance profiles.
- Target AWS service identified for application access.
What You'll Build¶
You will build an Elastic Beanstalk environment that can call AWS APIs through the instance profile attached to its EC2 instances.
flowchart LR
A[Flask App on Elastic Beanstalk] --> B[EC2 Instance Profile]
B --> C[IAM Role Policy]
C --> D[AWS Service APIs] Steps¶
Step 1: Create an IAM role for Elastic Beanstalk EC2 instances¶
aws iam create-role \
--role-name "$APP_NAME-eb-ec2-role" \
--assume-role-policy-document file://trust-policy.json
Use this trust policy in trust-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Step 2: Attach least-privilege permissions¶
aws iam put-role-policy \
--role-name "$APP_NAME-eb-ec2-role" \
--policy-name "$APP_NAME-app-access" \
--policy-document file://app-access-policy.json
Example app-access-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::$APP_NAME-bucket/*"
}
]
}
Step 3: Create an instance profile and add the role¶
aws iam create-instance-profile \
--instance-profile-name "$APP_NAME-eb-ec2-profile"
aws iam add-role-to-instance-profile \
--instance-profile-name "$APP_NAME-eb-ec2-profile" \
--role-name "$APP_NAME-eb-ec2-role"
Step 4: Attach the instance profile to the environment¶
aws elasticbeanstalk update-environment \
--application-name "$APP_NAME" \
--environment-name "$ENV_NAME" \
--option-settings Namespace=aws:autoscaling:launchconfiguration,OptionName=IamInstanceProfile,Value="$APP_NAME-eb-ec2-profile" \
--region "$REGION"
Step 5: Confirm the app can call AWS without static keys¶
import boto3
from flask import Flask
application = Flask(__name__)
@application.get("/identity-check")
def identity_check():
sts = boto3.client("sts")
identity = sts.get_caller_identity()
return {"arn": identity["Arn"]}
Verification¶
Expected result: the route returns the assumed role ARN for the Elastic Beanstalk instance profile.
Clean Up¶
Detach the instance profile from the environment, then remove the IAM resources:
aws iam remove-role-from-instance-profile \
--instance-profile-name "$APP_NAME-eb-ec2-profile" \
--role-name "$APP_NAME-eb-ec2-role"
aws iam delete-instance-profile \
--instance-profile-name "$APP_NAME-eb-ec2-profile"
aws iam delete-role-policy \
--role-name "$APP_NAME-eb-ec2-role" \
--policy-name "$APP_NAME-app-access"
aws iam delete-role \
--role-name "$APP_NAME-eb-ec2-role"