AWS IAM Role Assumtion Pecularity
Hi all. I am staring to write a series of posts about AWS. This article is the first one in the series. The goal is not to provide a deep dive into the AWS services, but to share some interesting and useful tips about AWS, which I have learned on my projects.
Today I will outline an interesting peculiarity of AWS IAM role assumption. I think it is important to understand for building better permission and trust policies for your IAM roles. I identified this interesting behavior while working on a project where I needed to restrict which roles can assume a particular role inside the same account.
The problem
Let’s say there is an IAM role in the account, the role name is a RoleA. This role has a permission to assume other roles, but only those which are placed in the specific ARN path, e.g. allowed-roles-path.
The RoleA ARN is the following: arn:aws:iam::123456789012:role/RoleA. Its permissions policy for assuming roles is the following:
1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Effect": "Allow",
6 "Action": "sts:AssumeRole",
7 "Resource": "arn:aws:iam::123456789012:role/allowed-roles-path/*"
8 }
9 ]
10}Question: What kind of behavior is expected here?
From the first glance it looks like that the RoleA can assume only roles which are placed in the allowed-roles-path. But this is NOT the case.
Behavior depends on the trust policy of the role which is being assumed.
Let’s create four more roles in the account: RoleB, RoleC, RoleD, and RoleE.
RoleBARN:arn:aws:iam::123456789012:role/RoleBand its trust policy allows to be assumed by any role in the account.
1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Effect": "Allow",
6 "Principal": {
7 "AWS": "arn:aws:iam::123456789012:root"
8 },
9 "Action": "sts:AssumeRole"
10 }
11 ]
12}RoleCARN:arn:aws:iam::123456789012:role/RoleCand its trust policy allows to be assumed only by theRoleA.
1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Effect": "Allow",
6 "Principal": {
7 "AWS": "arn:aws:iam::123456789012:role/RoleA"
8 },
9 "Action": "sts:AssumeRole"
10 }
11 ]
12}RoleDARN:arn:aws:iam::123456789012:role/allowed-roles-path/RoleDand its trust policy allows to be assumed by any role in the account.
1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Effect": "Allow",
6 "Principal": {
7 "AWS": "arn:aws:iam::123456789012:root"
8 },
9 "Action": "sts:AssumeRole"
10 }
11 ]
12}RoleEARN:arn:aws:iam::123456789012:role/allowed-roles-path/RoleEand its trust policy allows to be assumed only by theRoleA.
1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Effect": "Allow",
6 "Principal": {
7 "AWS": "arn:aws:iam::123456789012:role/RoleA"
8 },
9 "Action": "sts:AssumeRole"
10 }
11 ]
12}Expected behavior:
- The
RoleAcan assume theRoleDand theRoleEonly, because they are placed in theallowed-roles-path.
Actual behavior:
- The
RoleAcan assume the rolesRoleC,RoleDand theRoleE.
Surprised? I was surprised too when I found this out. I did not expect to see the RoleC in the list of assumable roles by the RoleA, because it is placed in the root path, not in the allowed-roles-path.
Let’s analyze case by case how evaluation of policies works.
RoleB:- The
RoleBtrust policy principalarn:aws:iam::123456789012:rootmatches all roles in the account, but it is not specific to theRoleAARN. - Because
arn:aws:iam::123456789012:rootdoes not match exactly theRoleAARN, the policy engine checks the permissions policy of theRoleA. - In the
RoleApermissions policy, theRoleBARN is not in theallowed-roles-path. - Rusult: the
RoleAcannot assume theRoleB.
- The
RoleC:- The
RoleCtrust policy principalarn:aws:iam::123456789012:role/RoleAmatches exactly theRoleAARN. The evaluation stops here. - Result: the
RoleAcan assume theRoleC.
- The
RoleD:- The
RoleDtrust policy principalarn:aws:iam::123456789012:rootmatches all roles in the account, but it is not specific to theRoleAARN. - Because
arn:aws:iam::123456789012:rootdoes not match exactly theRoleAARN, the policy engine checks the permissions policy of theRoleA. - In the
RoleApermissions policy, theRoleDARN is in theallowed-roles-path. - Result: the
RoleAcan assume theRoleD.
- The
RoleE:- The
RoleEtrust policy principalarn:aws:iam::123456789012:role/RoleAmatches exactly theRoleAARN. The evaluation stops here. - Result: the
RoleAcan assume theRoleE.
- The
The explanation
When you assume an IAM role, if the trust policy principal matches the ARN of the role that is assuming the role, the evaluation stops. The permissions policy of the role that is assuming the role is not checked.
Note: This behavior happends only if you are assuming a role in the same account. When you do cross-account role assumption, permissions policy of the role that is assuming the role is checked.
Summary
When configuring IAM role assumption in AWS inside the same account, be aware that the trust policy of the role that is being assumed is more important than the permissions policy of the role that is assuming the role. If the trust policy principal matches the ARN of the role that is assuming the role, the evaluation stops and the role can be assumed.