I am trying to use IAM roles to control access to S3 in my application. However, I don't have all the pieces in place to make this work. When running in AWS, my code is throwing a "missing credentials." exception, so obviously I've missed a step.
I was under the impression that without specifying the credentials, the SDK would default to using the identity of the container, but that doesn't seem to be the case. I assume that either my code is wrong, or the Assume Role policy that I've created isn't specifying the right principal. I just haven't been able to figure out from the docs what I'm supposed to be doing.
My other thought is maybe I need to create a separate role for access to the S3 bucket, and then write some code to assume that role, and use those credentials in my s3 client.
Any help would be appreciated.
I'm using Terraform to set up my infrastructure, and have included the relevant excerpts below. At the end of the post, I've included my Typescript code for accessing S3.
Current configuration
- I've defined a role for my ECS Fargate Task
resource "aws_iam_role" "ecs_task_execution_role" {
name = "ecsTaskExecutionRole"
assume_role_policy = data.aws_iam_policy_document.ecs_task_execution_role.json
}
- I've defined an Assume Role policy for this task
data "aws_iam_policy_document" "ecs_task_execution_role" {
version = "2012-10-17"
statement {
sid = ""
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
- I've defined an IAM Policy that governs access to the S3 bucket in question:
resource "aws_iam_policy" "read_write_image_storage" {
name = "${var.environment}-read-write-image-storage"
description = "Allows read access to s3 bucket in the ${var.environment} environment"
policy = jsonencode({
Version = "2012-10-17",
Statement = [{
Effect = "Allow",
Action = [
"s3:*"
],
Resource = [
aws_s3_bucket.image_storage.arn,
]
}]
})
}
- I've attached the policy to the role under which my containers are running:
resource "aws_iam_role_policy_attachment" "read_write_image_storage" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = aws_iam_policy.read_write_image_storage.arn
}
- In my node.js code running in the container associated with this task I spin up a default S3 client, and try to use it to access the bucket:
const s3config = {
region: process.env.AWS_REGION,
};
const s3 = new S3(s3config);
export const putBlob = async (key: string, blob: Buffer) => {
// save buffer to an AWS S3 bucket
const params = {
Bucket: process.env.AWS_ATTACHMENT_STORAGE_BUCKETNAME,
Key: key,
Body: blob,
ContentType: "image/png",
};
try {
console.debug("Saving image to S3");
const result = await s3.upload(params).promise();
} catch(e) {
console.error(e.message) // MissingCredentials
throw 2
}
}
- I've defined the Fargate task to use the role defined in step 1
resource "aws_ecs_task_definition" "webapp" {
family = "webapp-task"
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = jsonencode([
{
"name" : "MyContainerDefinition",
"image" : "MyContainerImage",
"cpu" : 256,
"memory" : 512,
"essential" : true,
"portMappings" : [
{
"containerPort" : 80,
"hostPort" : 80,
"protocol" : "tcp"
}
],
}
])
}```
CodePudding user response:
You have to setup task_role_arn. This is different then execution_role_arn
.