IAM Role Trust Update – What You Need to Know

When it comes to assuming roles, AWS is changing an aspect of how trust policy is evaluated; here is a quick digest of what this change may mean to you.

Lior Zatlavi By Lior Zatlavi
IAM Role Trust Update – What You Need to Know

Co-authored by Noam Dahan.

ICYMI, on September 21, 2022, AWS announced they are changing an aspect of how trust policy is evaluated when it comes to assuming roles. While we highly recommend reading the entire announcement as it’s packed with valuable information about the change, we thought it would be useful to provide the community with a quick digest of what exactly happened and what this change may mean to you.

What is changing?

In the past, IAM roles implicitly trusted themselves; that is, they could assume themselves if they had an IAM (identity-based) policy attached that allowed them to do so. This was different from how all other IAM roles were treated as they had to be included in the trust relationship of the role.

To cite an example from the AWS announcement, if we had a role called RoleA in account 123456789012, the trust relationship policy below would be required and necessary to allow RoleB to assume RoleA:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:role/RoleB"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

In the past, RoleA could assume itself, even if it was not included in the trust policy, as long as it had an identity-based policy attached to it allowing it to do so, such as this:

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::123456789012:role/RoleA"
  }
}

This is no longer the case. Implicit self-trust for IAM roles is no more. If you want a new IAM role to be able to assume itself, you should make the trust explicit and include the role in its own trust relationship, like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/RoleB",
                    "arn:aws:iam::123456789012:role/RoleA"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

If you recently (between June 30, 2022, and September 21, 2022) had an IAM role that assumed itself without an explicit trust, the implicit self-trust will continue to apply for it until February 15, 2023. However for any new roles or roles that did not assume themselves you will now experience the new behavior – that is, without an explicit trust the role will not be able to assume itself – so you must add an explicit trust in your role’s trust policy.

Why is it changing?

In one word -- consistency; it makes a ton of sense that self-assumption by an IAM role be treated the same as assumption by any other IAM role. This uniformity is a welcome change -- it makes the practice of understanding the evaluation logic that AWS IAM utilizes more straight-forward by removing this hidden caveat.

How can it affect you?

If you have IAM roles that rely on self-assumption in their operation and currently don’t explicitly include themselves in the trust relationship policy, they may already be denied access to assuming themselves (see “What is changing?”).

While this behavior is extremely rare (according to the announcement, only approximately 0.0001% of all IAM roles utilize it), it might be used somewhere in your deployments. Not treating this issue might cause your infrastructure unexpected (and somewhat hard to debug) disruptions of service -- and for this reason you should be aware of it.

What should you do?

As with many issues, the first step toward having control is gaining proper visibility into where this kind of behavior is utilized. We should mention that, in the announcement, Amazon states that it has already started notifying customers that have the behavior in their accounts.

Probably the best way to do this is to look for assumeRole events where the session issuer ARN is the same as the ARN of the IAM role performing the assumeRole. The announcement from AWS has some great examples of how to do this using Athena and/or CloudTrail Lake.

You could also use the following script we wrote utilizing AWS’s CLI (note that you should modify the start and end times, and specify the profile used by the CLI):

( echo "Time,Identity ARN,Event ID, Session ARN";
aws cloudtrail --region us-east-2 --profile <CLI_PROFILE_NAME> lookup-events --start-time "2022-10-01T13:00:00Z" --end-time "2022-10-02T13:00:00Z"
    --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole --query "Events[*].CloudTrailEvent" 
    --output text \
    | jq -r ". | select(.eventSource == \"sts.amazonaws.com\" and .eventType == \"AwsApiCall\" and .errorCode == null
    and .eventName == \"AssumeRole\" and .userIdentity.type == \"AssumedRole\"
    and .userIdentity.sessionContext.sessionIssuer.arn[12:] == .resources[].ARN[12:])
    | [.eventTime, .userIdentity.arn, .eventID, .userIdentity.sessionContext.sessionIssuer.arn] | @csv") | column -t -s'",'

To run this command, you will need to have a principal that is entitled to the cloudtrail:LookupEvents permission in the relevant account. You can use this IAM permission policy to grant it:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "lookupevents",
            "Effect": "Allow",
            "Action": "cloudtrail:LookupEvents",
            "Resource": "*"
        }
    ]
}

Once you have found all the relevant occurrences you then need to decide what your strategy is moving forward.

The simplest thing of course would be to add explicit trust for the IAM role in its trust policy. This will maintain its ability to assume itself.

However, it’s often not a recommended approach to use self-assumption on an IAM role, and its usage actually indicates a mistaken use of AWS resources (a very elaborate list is detailed in the IAM role trust update announcement). There are actually very few cases for which it makes sense for this behavior. A couple of such use cases mentioned in the announcement are “scoping down” permissions using a session policy (that is, using the IAM role with different permissions for different scenarios) and assuming a target computing role in production and in development with the same code -- and even these two use cases have recommended replacements.

In conclusion, we highly recommend you take this opportunity to reconsider the approach of using self-assumption and replace any instances of it with a viable, better practice alternative.

Lior Zatlavi
Sr. Cloud Security Architect, Ermetic
liorzat@ermetic.com

Noam Dahan,
Research Lead, Ermetic
noam@ermetic.com