Use the Knowledge Base AI to help improve your Cloud Posture

Prevent IAM Role Chaining

Trend Vision One™ provides continuous assurance that gives peace of mind for your cloud infrastructure, delivering over 1100 automated best practice checks.

Risk Level: High (not acceptable risk)

Ensure that IAM Role Chaining method is not used to grant temporary access to cloud resources within your AWS environment. IAM Role Chaining can add unnecessary complexity and increase the risk of unauthorized access. It can also make troubleshooting and managing permissions more difficult. By simplifying access policies, you can reduce these risks and enhance security.

This rule can help you work with the AWS Well-Architected Framework.

Security

IAM Role Chaining represents a mechanism within AWS cloud that facilitates granting temporary access to resources by enabling a sequence of trust relationships through role assumption. It is especially useful in scenarios where a user or process needs to access resources across multiple AWS accounts or environments. This feature supports granular access control, modular system design, and the implementation of the least privilege principle. Moreover, it enhances security by using temporary credentials, reducing the risks associated with long-term access keys. Despite these benefits, avoiding IAM Role Chaining is often recommended as a best practice due to its inherent complexity and potential security pitfalls. The process of assuming multiple roles sequentially introduces layers of abstraction that can complicate understanding and managing permissions. Misconfigurations or oversights in these chains can lead to unintended access, increasing the likelihood of security vulnerabilities. Furthermore, it amplifies the risk of the Confused Deputy problem, where a malicious actor could exploit the trust relationships between roles to gain unauthorized access. By minimizing or avoiding role chaining, organizations can reduce these risks and maintain clearer, more manageable access policies. Instead of chaining roles, designing direct and explicit trust relationships between the necessary entities or using more straightforward access control policies can achieve similar objectives with reduced operational and security risks.


Audit

To determine if IAM Role Chaining is used within your AWS cloud account, perform the following operations:

Using AWS Console

01 Sign in to the AWS Management Console.

02 Navigate to Identity and Access Management (IAM) console available at https://console.aws.amazon.com/iam/.

03 In the left navigation panel, under Access management, choose Users.

04 Click on the name (link) of the IAM user that you want to examine.

05 Select the Permissions tab to view the IAM policies attached to the selected user.

06 In the Permissions policies section, click on the Expand button (i.e., plus icon) available next to each managed/inline policy to display its policy document in JSON format.

07 Examine each IAM policy to determine whether the selected user assumes an IAM role using long-term credentials. To allow role assumption, the policy must use an IAM role for the "Resource" element, with "Effect" set to "Allow", and "Action" set to "sts:AssumeRole". If the user assumes an IAM role, as shown in the example below, copy the name of the assumed IAM role, i.e., \<RoleA\>:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "sts:AssumeRole",
			"Resource": "arn:aws:iam::<Account-Id>:role/<RoleA>"
		}
	]
}

08 In the left navigation panel, under Access management, choose Roles.

09 Click inside the Search box, paste the name of the IAM role copied in step 7, and press Enter to find the role assumed by your IAM user.

10 Click on the name (link) of the IAM role returned as a search result, i.e., \<RoleA\>.

11 Select the Permissions tab to view the IAM policies attached to the selected role.

12 In the Permissions policies section, click on the Expand button (i.e., plus icon) available next to each managed/inline policy to display its policy document in JSON format.

13 Examine each IAM policy to determine whether the selected role assumes another IAM role. To allow role assumption, the policy must use another IAM role for the "Resource" element, with "Effect" set to "Allow", and "Action" set to "sts:AssumeRole". If the role assumes another IAM role, as shown in the example below, copy the name of the assumed IAM role, i.e., \<RoleB\>:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "sts:AssumeRole",
			"Resource": "arn:aws:iam::<Account-Id>:role/<RoleB>"
		}
	]
}

14 Select the Trust relationships tab to access the trust policy associated with \<RoleA\>. A trust policy defines which entities (users, roles, accounts, and services) are allowed to assume a role and under what conditions.

15 In the Trusted entities section, check the "Principal" element value to identify the entity authorized to assume the role. If the "Principal" matches the IAM user selected in step 4, as shown in the example below, your IAM user is authorized to assume \<RoleA\>:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"AWS": "arn:aws:iam::<Account-Id>:user/<Iam-User>"
			},
			"Action": "sts:AssumeRole"
		}
	]
}

16 In the left navigation panel, under Access management, choose Roles.

17 Click inside the Search box, paste the name of the IAM role copied in step 13, and press Enter to find the role assumed by \<RoleA\>.

18 Click on the name (link) of the IAM role returned as a search result, i.e., \<RoleB\>.

19 Select the Trust relationships tab to access the trust policy associated with \<RoleB\>.

20 In the Trusted entities section, check the "Principal" element value to identify the entity authorized to assume the role. If the "Principal" matches \<RoleA\>, as shown in the example below, your Amazon IAM user employs IAM Role Chaining to access AWS cloud resources with temporary credentials:

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

21 Repeat steps no. 4 – 21 for each Amazon IAM user available in your AWS cloud account.

Using AWS CLI

01 Run list-users command (OSX/Linux/UNIX) with custom query filters to list the name of each IAM user available within your AWS account:

aws iam list-users
	--output table
	--query 'Users[*].UserName'

02 The command output should return a table with the requested IAM user identifiers:

-------------------------
|       ListUsers       |
+-----------------------+
| cc-project5-developer |
| cc-ai-project-manager |
+-----------------------+

03 To view the IAM policies defined for your IAM user, perform the following actions:

  1. For managed IAM policies, run the following commands:
    1. Run list-attached-user-policies command (OSX/Linux/UNIX) with the name of the IAM user that you want to examine as the identifier parameter, to list the ARN of the each managed policy attached to the selected user:
      aws iam list-attached-user-policies
      	--user-name cc-project5-developer
      	--output table
      	--query 'AttachedPolicies[*].PolicyArn'
      
    2. The command output should return a table with the requested IAM policy ARN(s):
      ---------------------------------------------------------------
      |                 ListAttachedUserPolicies                    |
      +-------------------------------------------------------------+
      | arn:aws:iam::123456789012:policy/cc-project5-managed-policy |
      +-------------------------------------------------------------+
      
    3. Run get-policy-version command (OSX/Linux/UNIX) to describe the policy document defined for the managed policy attached to the selected IAM user:
      aws iam get-policy-version
      	--policy-arn arn:aws:iam::123456789012:policy/cc-project5-managed-policy
      	--version-id v1
      	--query 'PolicyVersion.Document'
      
    4. The command output should return the requested policy document:
      {
      	"Version": "2012-10-17",
      	"Statement": [
      		{
      			"Sid": "managed-policy",
      			"Effect": "Allow",
      			"Action": "sts:AssumeRole",
      			"Resource": "arn:aws:iam::<Account-Id>:role/<RoleA>"
      		}
      	]
      }
      
  2. For inline IAM policies, run the following commands:
    1. Run list-user-policies command (OSX/Linux/UNIX) with the name of the IAM user that you want to examine as the identifier parameter, to list the name of the each inline policy associated with the selected user:
      aws iam list-user-policies
      	--user-name cc-project5-developer
      	--output table
      	--query 'PolicyNames[*]'
      
    2. The command output should return a table with the requested IAM policy name(s):
      -----------------------------
      |     ListUserPolicies      |
      +---------------------------+
      | cc-project5-inline-policy |
      +---------------------------+
      
    3. Run get-user-policy command (OSX/Linux/UNIX) to describe the policy document defined for the inline policy associated with the selected IAM user:
      aws iam get-user-policy
      	--user-name cc-project5-developer
      	--policy-name cc-project5-inline-policy
      	--query 'PolicyDocument'
      
    4. The command output should return the requested policy document:
      {
      	"Version": "2012-10-17",
      	"Statement": [
      		{
      			"Sid": "inline-policy",
      			"Effect": "Allow",
      			"Action": "sts:AssumeRole",
      			"Resource": "arn:aws:iam::<Account-Id>:role/<RoleA>"
      		}
      	]
      }
      

04 Examine each managed/inline IAM policy defined for your IAM user to determine whether the selected user assumes an IAM role using long-term credentials. To allow role assumption, the policy must use an IAM role for the "Resource" element, with "Effect" set to "Allow", and "Action" set to "sts:AssumeRole". If the user assumes an IAM role, as shown in the policy examples above, note the name of the assumed IAM role, i.e., \<RoleA\>.

05 Run get-role command (OSX/Linux/UNIX) to describe the trust policy associated with \<RoleA\>. A trust policy defines which entities are allowed to assume a role and under what conditions:

aws iam get-role
	--role-name <RoleA>
	--query 'Role.AssumeRolePolicyDocument'

06 The command output should return the trust policy associated with \<RoleA\>. Check the "Principal" element value to identify the entity authorized to assume the role. If the "Principal" matches your IAM user, as shown in the example below, your IAM user is authorized to assume \<RoleA\>:

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

07 To view the IAM policies defined for **\<RoleA\>**, perform the following actions:

  1. For managed IAM policies, run the following commands:
    1. Run list-attached-role-policies command (OSX/Linux/UNIX) to list the Amazon Resource Name (ARN) of each managed policy attached to \<RoleA\>:
      aws iam list-attached-role-policies
      	--role-name <RoleA>
      	--query 'AttachedPolicies[*].PolicyArn'
      
    2. The command output should return the ARN of each managed policy attached to the selected role:
      [
      	"arn:aws:iam::123456789012:policy/cc-role-managed-policy"
      ]
      
    3. Run get-policy-version command (OSX/Linux/UNIX) with the ARN of the IAM managed policy that you want to examine as the identifier parameter and custom filtering to describe the policy document (JSON format) defined for the selected managed policy:
      aws iam get-policy-version
      	--policy-arn arn:aws:iam::123456789012:policy/cc-role-managed-policy
      	--version-id v1
      	--query 'PolicyVersion.Document'
      
    4. The command output should return the requested IAM policy document:
      {
      	"Version": "2012-10-17",
      	"Statement": [
      		{
      			"Effect": "Allow",
      			"Action": "sts:AssumeRole",
      			"Resource": "arn:aws:iam::<Account-Id>:role/<RoleB>"
      		}
      	]
      }
      
  2. For inline IAM policies, run the following commands:
    1. Run list-role-policies command (OSX/Linux/UNIX) to list the name of each inline policy associated with \<RoleA\>:
      aws iam list-role-policies
      	--role-name <RoleA>
      	--query 'PolicyNames'
      
    2. The command output should return the name of each inline policy associated with the selected role:
      [
      	"cc-role-inline-policy"
      ]
      
    3. Run get-role-policy command (OSX/Linux/UNIX) with the name of the IAM inline policy that you want to examine as the identifier parameter and custom query filters to describe the policy document (JSON format) defined for the selected inline policy:
      aws iam get-role-policy
      	--role-name <RoleA>
      	--policy-name cc-role-inline-policy
      	--query 'PolicyDocument'
      
    4. The command output should return the requested inline policy document:
      {
      	"Version": "2012-10-17",
      	"Statement": [
      		{
      			"Effect": "Allow",
      			"Action": "sts:AssumeRole",
      			"Resource": "arn:aws:iam::<Account-Id>:role/<RoleB>"
      		}
      	]
      }
      

08 Examine each managed/inline IAM policy to determine whether the selected role assumes another IAM role. To allow role assumption, the policy must use another IAM role for the "Resource" element, with "Effect" set to "Allow", and "Action" set to "sts:AssumeRole". If the role assumes another IAM role, as shown in the policy examples above, note the name of the assumed IAM role, i.e., \<RoleB\>.

09 Run get-role command (OSX/Linux/UNIX) to describe the trust policy associated with \<RoleB\>. A trust policy defines which entities are allowed to assume a role and under what conditions:

aws iam get-role
	--role-name <RoleB>
	--query 'Role.AssumeRolePolicyDocument'

10 The command output should return the trust policy associated with \<RoleB\>. Check the "Principal" element value to identify the entity authorized to assume the role. If the "Principal" matches \<RoleA\>, as shown in the example below, your Amazon IAM user employs IAM Role Chaining to access AWS cloud resources with temporary credentials:

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

11 Repeat steps no. 3 – 10 for each Amazon IAM user available in your AWS cloud account.

Remediation / Resolution

To simplify role management and reduce the complexity of IAM Role Chaining within your AWS cloud environment, you can consolidate multiple chained roles into a single role. This reduces complexity but requires careful consideration to avoid granting excessive privileges. To consolidate multiple chained roles into a single role with fine-grained permissions, perform the following operations:

As an example, the following steps detail the process of consolidating two chained IAM roles, \<RoleA\> and \<RoleB\>, to mitigate the risks associated with IAM Role Chaining.

Using AWS Console

01 Sign in to the AWS Management Console.

02 Navigate to Identity and Access Management (IAM) console available at https://console.aws.amazon.com/iam/.

03 In the left navigation panel, under Access management, choose Roles.

04 Click on the name (link) of the IAM role assumed by your IAM user, i.e., \<RoleA\>.

05 Select the Permissions tab to access the IAM policies attached to the selected role.

06 In the Permissions policies section, perform the following actions based on the policy type used:

  1. For managed IAM policies:
    1. Select Add permissions, choose Attach policies, select the managed IAM policy defined for \<RoleB\>, and choose Add permissions to attach the policy. Follow the Principle of Least Privilege (the security concept of providing every identity the minimal set of permissions required to successfully perform its tasks) when selecting the managed policies to attach to your IAM role.
    2. Select the managed policy configured to assume \<RoleB\>, used for IAM Role Chaining, and choose Remove. Inside the confirmation box, choose Remove to detach the policy.
  2. For inline IAM policies:
    1. Select Add permissions and choose Create inline policy to create a new inline policy for \<RoleA\>. Select the JSON tab, paste the inline policy document defined for \<RoleB\> into the Policy editor box, select Next, provide a policy name, and choose Create policy to attach the new policy. Follow the Principle of Least Privilege (POLP) when creating the new policy.
    2. Select the inline policy configured to assume \<RoleB\>, utilized for IAM Role Chaining, and choose Remove. Inside the confirmation box, enter the policy name in the required text box, and choose Delete to remove the policy.

07 Repeat steps no. 4 - 6 for each Amazon IAM user leveraging IAM Role Chaining, available in your AWS cloud account.

Using AWS CLI

01 Depending on the policy type used by the IAM role assumed by your IAM user, i.e., \<RoleA\>, execute one of the following sets of commands:

  1. For managed IAM policies:
    1. Run attach-role-policy command (OSX/Linux/UNIX) to attach the specified managed IAM policy to \<RoleA\>. For the --policy-arn parameter, provide the ARN of the managed IAM policy designated for \<RoleB\>. Ensure that the policy adheres to the Principle of Least Privilege (POLP), granting only the minimal permissions necessary to accomplish the required tasks effectively (the command does not produce an output):
      aws iam attach-role-policy
      	--role-name <RoleA>
      	--policy-arn arn:aws:iam::123456789012:policy/cc-role-b-managed-policy
      
    2. Run detach-role-policy command (OSX/Linux/UNIX) to detach the managed IAM policy configured to assume \<RoleB\>, used for IAM Role Chaining, from \<RoleA\> (the command does not return an output):
      aws iam detach-role-policy
      	--role-name <RoleA>
      	--policy-arn arn:aws:iam::123456789012:policy/cc-project5-managed-policy
      
  2. For inline IAM policies:
    1. Run put-role-policy command (OSX/Linux/UNIX) to create a new inline IAM policy for \<RoleA\>. For the --policy-document parameter, use the inline policy document defined for \<RoleB\> in JSON format (i.e., cc-iam-role-policy.json). Ensure that the policy adheres to the Principle of Least Privilege (POLP), granting only the minimal permissions necessary to accomplish the required tasks effectively (the command does not produce an output):
      aws iam put-role-policy
      	--role-name <RoleA>
      	--policy-name cc-role-b-inline-policy
      	--policy-document file://cc-iam-role-policy.json
      
    2. Run delete-role-policy command (OSX/Linux/UNIX) to remove the inline IAM policy configured to assume \<RoleB\>, utilized for IAM Role Chaining, from \<RoleA\> (the command does not return an output):
      aws iam delete-role-policy
      	--role-name <RoleA>
      	--policy-name cc-project5-inline-policy
      

02 Repeat step no. 1 for each Amazon IAM user leveraging IAM Role Chaining, available within your AWS cloud account.

References