Always use IAM Roles and never use any explicit access/secret keys in production. Read more about EC2 instance roles here, the same applies to ECS IAM Roles.
In your ECS case you should:
- Create IAM Role with permissions to
s3:GetObject
from the S3 bucket.
- Attach that IAM Role to your ECS Task as a
TaskRole
.
- If you are using ECS Fargate instead of EC2-based ECS you will also need an
ExecutionRole
that essentially gives Fargate the permissions to launch your task.
In CloudFormation template it would be something like this:
Parameters:
S3BucketName:
Type: String
Resources:
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
NetworkMode: awsvpc
TaskRoleArn: !Ref TaskRole
ExecutionRoleArn: !Ref ExecutionRole
RequiresCompatibilities:
- FARGATE
Cpu: ...
Memory: ...
ContainerDefinitions:
- ...
TaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ ecs-tasks.amazonaws.com ]
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: TaskAccess
PolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- s3:GetObject
Effect: Allow
Resource:
- !Sub "arn:aws:s3:::${S3BucketName}/*"
ExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ ecs-tasks.amazonaws.com ]
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
However there is often no point downloading public images from S3 to your Flask web app. Instead make the images public in S3 and refer directly to them from your HTML with <img src="https://your-bucket-name.s3.amazonaws.com/whatever/image.jpg"/>
.
If the images are not public you still shouldn't download them to Flask and instead create pre-signed URLs that provide time-limited access to the files in S3. Again linking directly to the S3 location without downloading the files from S3 to Flask first.
Hope that helps :)