@jialin.huang
FRONT-ENDBACK-ENDNETWORK, HTTPOS, COMPUTERCLOUD, AWS, Docker
To live is to risk it all Otherwise you are just an inert chunk of randomly assembled molecules drifting wherever the Universe blows you

© 2024 jialin00.com

Original content since 2022

back
RSS

The Confusing assumeRole and Trust Policy

The IAM Role, IAM User, Trust Relationship, Trust… I initially thought I only needed to understand the basic units like Users, Roles paired with Policies, which seemed simple and easy to get. But then I found more abstract terms like assumeRole and Trust policy, so I'm writing this article to help me remember these concepts.

TL;DR

assumeRole is useful in situations where you don't want to specify users or list a bunch of access permissions for S3. Instead, you only allow users with assumeRole permission, and those who meet the assumeRole requirements get temporary access.

Just like…

Instead of giving everyone a permanent pass, it's better to let anyone have a chance to see if they qualify and get a temporary pass. And this pass has a time limit too, so it will expire automatically when you're done using it.

Or…

  • Even if you're on the guest list (trust policy)
  • You still need the actual invitation (user or resource policy) to get in

Trusted Policy

IAM Role with Trust Policy

  • A Role is just a collection of permission definitions
  • Roles are used by other entities (like Users)

In simple terms, it defines who (principal) I trust to assume my role

When you create a Role, there's a Trust Relationship tab that won't be empty.

For example, the basic AWSServiceRoleForECS:

This code means: ECS service is a trusted entity/unit that can assume this role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ecs.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Or you can also customize it, like appleRole:

This code means: Not only can AWS services be Principals, but the Principal field can also include external entities or other AWS accounts.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    // Within AWS: other users or other AWSaccounts
                    "arn:aws:iam::ACCOUNT-ID-1:user/username1",
                    "arn:aws:iam::ACCOUNT-ID-2:root",
                    "arn:aws:iam::ACCOUNT-ID-3:role/some-role",
                    
                    // or use array is fine
                    ["arn:aws:iam::ACCOUNT-ID-4:user/*"]  // all users under spec account
                ],
                // Outside AWS: through OIDC
                "Federated": [
                    "cognito-identity.amazonaws.com",  // AWS Cognito
                    "accounts.google.com",  // Google
                    "graph.facebook.com",   // Facebook
                    "www.amazon.com"        // Amazon
                ],
                // for aws services
                "Service": [
                    "lambda.amazonaws.com",
                    "ec2.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Required IAM User Permissions

What roles can I assume? This is defined in the Resource

Just being mentioned in the Role's Principal isn't enough - I still need to declare in my policy that "I'm allowed to assume certain roles"

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::ACCOUNT-ID:role/appleRole"
        }
    ]
}

When I need to do something, like accessing S3, I first need to get a temporary pass, with controllable access duration.

S3 Bucket Policy

Depending on the situation:

  • If the IAM Role itself has S3-related permissions
    • No need to specify in S3 Bucket Policy, Bucket Policy can be empty
  • If Bucket Policy exists, it needs to explicitly allow that role like this:
    {
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ACCOUNT-ID:role/appleRole"
            },
            "Action": ["s3:GetObject", "s3:ListBucket"],
            "Resource": [
                "arn:aws:s3:::my-bucket",
                "arn:aws:s3:::my-bucket/*"
            ]
        }]
    }

Benefits of this design

You do not have to distribute or embed long-term AWS security credentials with an application.
You can provide access to your AWS resources to users without having to define an AWS identity for them. Temporary credentials are the basis for roles and identity federation.

… After temporary security credentials expire, they cannot be reused. You can specify how long the credentials are valid, up to a maximum limit.
  • code
    // Import the AWS SDK
    const AWS = require('aws-sdk');
    
    // Create an STS client
    const sts = new AWS.STS();
    
    // Parameters for assume role operation
    const params = {
      RoleArn: 'arn:aws:iam::ACCOUNT_ID:role/S3AccessRole',
      RoleSessionName: 'S3AccessSession',
      DurationSeconds: 3600 // Set explicit duration - 1 hour (can be 900-43200 seconds)
    };
    
    sts.assumeRole(params, (err, data) => {
    
      const credentials = data.Credentials;
      
      // Configure AWS to use the temporary credentials
      const s3 = new AWS.S3({
        accessKeyId: credentials.AccessKeyId,
        secretAccessKey: credentials.SecretAccessKey,
        sessionToken: credentials.SessionToken
      });
      
      // Now you can use the S3 client with the temporary credentials
      // For example, list buckets
      s3.listBuckets((err, data) => {
        if (err) {
          console.error('Error: ', err);
        } else {
          console.log('Buckets:', data.Buckets);
        }
      });
    });

https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html

EOF