What steps should I take to allow my code in an AWS Fargate container to take on an IAM role while accessing S3 using Node.js?

I've been working on implementing IAM roles to manage S3 access in my application, but I seem to be missing a crucial step. While running my code in AWS, I encountered a "missing credentials" exception, indicating that something is not configured correctly.

I initially thought that the SDK would default to using the container's identity if credentials were not specified, but that doesn't appear to be the case. It seems like either my code is incorrect or the Assume Role policy I set up is not specifying the correct principal. Unfortunately, I haven't been able to find clear guidance in the documentation.

One possibility I'm considering is creating a separate role specifically for accessing the S3 bucket and then writing code to assume that role and use those credentials with the S3 client.

Any assistance would be greatly appreciated.

I'm utilizing Terraform for infrastructure setup and have included relevant extracts below. Towards the end of this post, you'll find my Typescript code for interacting with S3.

Current setup

  1. I've defined an ECS Fargate Task role:
resource "aws_iam_role" "ecs_task_execution_role" {
  name = "ecsTaskExecutionRole"
  assume_role_policy = data.aws_iam_policy_document.ecs_task_execution_role.json
}
  1. I've established 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"]
        }
    }
}
  1. I've defined an IAM Policy for managing access to the specific S3 bucket:
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,
        ]
     }]
    })
}
  1. I've attached the policy to the role under which the containers are operating:
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
}
  1. Within the node.js code executed in the associated container, I initiate a default S3 client and attempt to interact with 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
    }
}
  1. The Fargate task has been configured to utilize the role as 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"
        }
      ],
    }
  ])
}

Answer №1

Setting up the task_role_arn is crucial. It should not be confused with the execution_role_arn in this context.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Expo constants failing to load on web due to unresolved manifest object issue

When setting up Firebase Auth in my expo app (using Google Auth), I needed to store my firebase variables in a .env file containing API_KEYS, AuthDomain, and more. To access these environment variables, I utilized expo constants in my firebase.ts file. Ini ...

What is the method to ensure that the children of an object strictly adhere to a specific interface or inherit from it?

Is there a way to ensure that an interface extends from another interface in TypeScript? For example: export interface Configuration { pages: { home: IHome; about: IAbout; // How can we make IAbout extend IPage? contact: IPage; }; } inte ...

What is the process for initiating an Angular 2 Materialize component?

I'm new to using angular2 materialize and I've found that the CSS components work perfectly fine. However, I'm facing an issue when it comes to initializing components like 'select'. I'm unsure of how or where to do this initi ...

What prevents me from employing my nestjs unique decorator within a constructor?

I am looking to develop a personalized decorator that fetches tenant information. This is the current code snippet I have: export type TenantInfo = { token: string id: string } export const TenantInfo = createParamDecorator( (data: unknown, cont ...

Encountering an error in testing with Typescript, Express, Mocha, and Chai

After successfully creating my first server using Express in TypeScript, I decided to test the routes in the app. import app from './Server' const server = app.listen(8080, '0.0.0.0', () => { console.log("Server is listening on ...

Arrays causing Typescript compilation errors

There are a pair of typescript documents: one file as a module that implements the Client class export class Client { the other file as the main document that imports the module and generates an array of clients import c = module("client ...

Utilize NgRx's dispatch method to pass a payload and update the store

Exploring the world of ngRx is a new journey for me. I am currently in the process of establishing a store that will receive updates triggered by actions from components. NgRx create methods are being utilized to craft actions and reducers for this purpose ...

Converting Javascript tools into Typescript

I'm currently in the process of migrating my Ionic1 project to Ionic2, and it's been quite an interesting journey so far! One challenge that I'm facing is how to transfer a lengthy list of utility functions written in JavaScript, like CmToFe ...

AWS Lambda serverless deployment of Angular Universal is failing to detect javascript files in the dist/browser directory

After following the steps in this tutorial for deploying to a lambda function, I encountered some issues. When testing it using serverless offline, I kept getting 404 errors for each compiled JS file. However, once I deployed it, the errors changed to 403. ...

When you find that the plugins on pub.dev do not offer web support, consider utilizing npm packages for Flutter web development

I am currently working on developing a cross-platform app using Flutter for iOS, Android, and web. However, some plugins do not support web. Fortunately, I came across npm packages that provide the same functionality and I am considering integrating them. ...

Guide to crafting a reply using nestjs exception filters with nestfastify

I'm facing a challenge with writing custom HTTP responses from NestJS exception filters. Currently, I am using the Nest Fastify framework instead of Express. I have created custom exception filters to handle UserNotFoundException in the following mann ...

Effectively managing user access by authorizing levels and securing routes

Below is the code snippet for a protected route where the authentication status is managed by Redux. If there is no token saved in local storage, the isAuthenticated state is set to false. This code snippet is for protecting routes: import PropTypes from & ...

Extract nested values within objects and arrays, and return the complete type of the original object

I have a dataset that resembles the structure of IconItems: { title: "Category title", description: "Example description", lists: [ { id: "popular", title: "Popular", items: [ { ...

Async and Await with Typescript

After searching extensively, I couldn't find a similar issue. I am working with Ionic 4 in Angular 7 along with Typescript 3.16. I have multiple 'TimeSpan' values that I need to retrieve using a function from the HTML like so: <ion-input ...

Expanding unfamiliar categories

Currently, I am working with Gutenberg blocks in a headless manner. Each Gutenberg block is defined by the following structure: type Block = { name: string; className?: string; key?: string | number; clientId: string; innerBlocks: Block ...

Utilizing a method from a separate class in Ionic 2

Having trouble using the takePicture() function from camera.ts in my home.ts. I keep getting an error message saying "No provider for CameraPage!" Any assistance on how to resolve this issue would be greatly appreciated, as I am new to this language and ju ...

Exploring the JSON Array in Angular5 with the power of ngFor

Currently, I am working on a project using Angular5 and encountering an issue with the *ngFor directive. The model class I have defined looks like this: export class FetchApi { value: Array<String>; api_status: string; api_version: string; d ...

What steps should I take to instruct TypeScript to package a third-party library from the node_modules directory?

I am looking to configure the TypeScript Compiler in such a way that it utilizes node_modules/firebase/firebase.d.ts for typechecking my code, and also includes node_modules/firebase/firebase.js in the files where I import firebase functionalities. Althoug ...

Using Typescript and ThreeJS, include new elements to the environment within the loader

Can someone help me with the following code snippet? export class LandingPageComponent implements OnInit { scene: THREE.Scene; (...) ngOnInit() { this.scene = new THREE.Scene(); var loader = new THREE.JSONLoader(); loader.load("../../assets/fire_lion.j ...

Ways to retrieve the returned value from the JS FETCH API outside of its scope

As a beginner in Typescript React and the Ionic framework, I am trying to use the JS FETCH API to fetch data from a third-party source. However, I am struggling to access this fetched data outside of the fetch function. If anyone could provide some guidan ...