Understanding AWS's Handling of Deleted IAM Roles in Policies

4 minute read
Content level: Intermediate
1

The context of this post is to bring awareness of this behavior. Some customers might want to know how they can track down all the resources where a deleted role is part of the resource or trust policy. Some others might have been dealing for hours troubleshooting an access denied after accidentally delete and recreate a IAM Role

When you delete an AWS Identity and Access Management (IAM) role, you may notice that AWS doesn't simply remove the role's Amazon Resource Name (ARN) from policies and configurations that previously referenced it. Instead, if the Principal element in a role trust policy contains an ARN that points to the deleted IAM role, the policy will load the role's unique principal ID instead of the role ARN, because the role no longer exists.

So, what's the deal with this behavior? Let's dive into the details.

The Security Rationale Behind this behavior

When you delete an IAM role, there's a potential security risk if someone were to recreate a new role with the same name as the deleted role, that new role could potentially inherit the access permissions of the previously deleted role, granting unintended access to resources.

To mitigate this risk, AWS implements a security measure: [1] If your Principal element in a role trust policy contains an ARN that points to a specific IAM role, then that ARN transforms to the role unique principal ID when you save the policy. This unique role ID takes the form of AROAXXXXXXXXXXXXXXXX, where X are a random characters and AROA means that it belongs to a role as stated in this documentation [2]

By using this unique role ID, AWS ensures that even if a new role is created with the same name as the deleted role, it cannot accidentally inherit the access permissions of the previously deleted role, maintaining the intended access boundaries.

Where Does This Behavior Apply?

The behavior of replacing a deleted role ARN with a unique role ID applies to any policies or configurations that referenced the deleted role, including:

  • IAM trust relationships (trust policies)
  • Resource-based policies (e.g., S3 bucket policies, KMS key policies)
  • Any other policies or configurations that granted permissions to the deleted role

Imagine you had a role (RoleA) with a trust policy that allowed a specific role (MyDeletedRole) to assume it:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<account-id>:role/MyDeletedRole"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

After deleting the MyDeletedRole role, AWS will modify this trust policy statement to replace the role ARN with the unique role ID, like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "AROAXXXXXXXXXXXXXXXX"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

CloudFormation Deployments and Drift

It's important to be aware of how this behavior can impact your CloudFormation deployments. If you have an IAM role (let's call it RoleB) deployed via a CloudFormation template, and its trust policy references another IAM role (RoleA) that gets deleted outside of the CloudFormation deployment, it will create a drift in your stack.

Here's an example CloudFormation template that demonstrates this scenario:

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "CloudFormation template demonstrating drift caused by deleted IAM role reference",
  "Resources": {
    "RoleB": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "AWS": "arn:aws:iam::123456789012:role/RoleA"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "RoleName": "RoleB"
      }
    }
  }
}

In this template, the trust policy of RoleB references the ARN arn:aws:iam::123456789012:role/RoleA. If the RoleA role is deleted outside of this CloudFormation deployment it will be detected as a drift. This happens because CloudFormation will call the IAM API when checking for drifts on its resources, as the ARN for the RoleB returned by IAM API is a unique ID instead of the ARN defined in the template. This will cause RoleB to be detected as MODIFIED.

Enter image description here

To resolve this drift, you would need to update the CloudFormation template by removing the reference to RoleA from the trust policy of RoleB. Alternatively, you could delete the RoleB resource from the stack and then recreate it with the updated trust policy.

This behavior applies to any policies or configurations that referenced the deleted role, ensuring that access boundaries are maintained and preventing accidental privilege escalation or unauthorized access. While this behavior may seem unexpected initially, it's a security measure implemented by AWS to protect your resources and maintain the intended access controls, even after roles are deleted. Understanding this behavior can help you plan for and manage access configurations more effectively, especially when dealing with frequently changing or ephemeral IAM roles.


IAM role principals

[1] https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html#principal-roles

IAM identifiers

[2] https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids

2 Comments

Is there any way to determine what the role ARN was after noticing that it has been replaced by the role ID?

Also, could the role have been originally specified in the resource policy by using the role ID - would this grant access to the principal? If so, would this work in cross account scenarios?

The concern is, when noticing a role ID in a resource policy, consider two different implications:

  1. The role was deleted and the role ARN was replaced by the role ID. This is the likely scenario you have described.

  2. A malicious actor has inserted a role ID into a resource policy from an unknown account. It appears to be harmless based on this article, but if it would successfully grant access, there is no way for the resource owner to identify that this corresponds to a role from an unknown account.

replied 8 months ago

@Jack In the first case, the CloudTrail event generated when the policy was originally set would contain the principal ID in the requestParameters element in the form in which it was specified to the API. Typically, a legitimate user would specify the principal ARN or account ID, both containing the owning account ID.

In the second case, if AWS Config is set up, configured, and properly authorised to record the resource type associated with the policy in question (such as S3 buckets to record the bucket policies or IAM roles to collect the role trust policies), the snapshots and/or configuration history collected by AWS Config would contain the full ARN of the role, user, or account principal, regardless of the format used to specify the principal when the policy was set.

As long as the principal still exists, the standard Get* and Describe* APIs that AWS Config uses to harvest policy data will contain the principal ID reverse-translated into its ARN form. Third-party CMDB tools or custom solutions that harvest policy data would also benefit from this built-in functionality and see the full ARNs.

EXPERT
replied 4 months ago