AWS Builder Center
Troubleshooting AWS IAM Access Issues: Understanding Permissions, Trust Policies, and Least Privilege

Troubleshooting AWS IAM Access Issues: Understanding Permissions, Trust Policies, and Least Privilege

One of the things I have learned while working with AWS is that access problems are not always caused by a missing permission in the obvious place. Sometimes a user has the right permissions attached to their identity, but the operation still fails. In other cases, the role has the correct permissions, but its trust policy does not allow the intended principal to assume it.

One of the things I have learned while working with AWS is that access problems are not always caused by a missing permission in the obvious place.
Sometimes a user has the right permissions attached to their identity, but the operation still fails. In other cases, the role has the correct permissions, but its trust policy does not allow the intended principal to assume it.
This is because AWS Identity and Access Management (IAM) evaluates access from different perspectives.
I explored this in an AWS Builder Lab titled “Troubleshooting - IAM Access Issues.” The lab presented a break/fix scenario where an IAM user could log in to the AWS Management Console but could not assume an IAM role that they were supposed to use.
The objective was not simply to make the role switch work. The solution also had to follow the principle of least privilege.
That made the exercise particularly useful from a cloud security perspective.

The Scenario

The lab simulated a typical situation in a cloud environment.
AnyCompany had a policy that users should not have the permissions required for their day-to-day AWS tasks attached directly to their IAM identities.
Instead, users should be able to assume an IAM role containing the permissions required for their work.
The environment contained:
  • An IAM user named Operator-User
  • An IAM role named Operator-Role
  • An EC2 instance named CommandHost
  • AWS Systems Manager Session Manager
  • An administrative AWSLabUser used to troubleshoot the problem
The intended workflow was:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Operator-User
│
│ AssumeRole
▼
Operator-Role
│
▼
Session Manager
│
▼
CommandHost
│
▼
Required scripts
The problem was that Operator-User could successfully log into the AWS Management Console but could not switch to Operator-Role.
The lab therefore became a troubleshooting exercise rather than simply a configuration exercise.
The scenario also imposed two important least-privilege requirements:
  1. Operator-User should only be allowed to assume Operator-Role.
  2. Operator-Role should only be assumable by Operator-User.

Why IAM Role Assumption Can Fail

One of the most important concepts from this lab is that assuming a role requires the correct configuration on both sides of the relationship.
There is a permission side and a trust side.
The user's identity-based policy needs to allow the sts:AssumeRole action against the intended role.
At the same time, the role's trust policy must trust the principal that is attempting to assume it.
Conceptually:
1
2
3
4
5
6
7
8
9
10
11
12
Operator-User
│
│ Identity-based policy
│
│ sts:AssumeRole
▼
Operator-Role
│
│ Trust policy
│
▼
Allows Operator-User
If either side is incorrectly configured, the role assumption can fail.
This is one of those IAM concepts that becomes much clearer when troubleshooting an actual access failure.

Reproducing the Problem

The first step was to reproduce the issue instead of immediately changing configuration.
I accessed the AWS Management Console using the Operator-User credentials and attempted to switch to Operator-Role.
From the user menu, I selected Switch role and provided the AWS account ID and the role name.
The attempt failed with the message:
“Invalid information in one or more fields. Check your information or contact your administrator.”
This confirmed that the problem was real.
The lab specifically designed this as a break/fix scenario, so reproducing the failure first was important. It established a baseline against which the eventual fix could be verified.

Looking at IAM from Both Sides

After reproducing the problem, I switched back to the administrative console.
This is where the troubleshooting process became more interesting.
When debugging IAM access, it is easy to focus on the user and assume that the problem must be in the user's permissions.
But role assumption involves two separate authorization relationships.

Identity-based policy

The IAM user's permissions determine what actions the user is allowed to request.
In this case, the user needs permission to call:
sts:AssumeRole
against the specific Operator-Role.

Trust policy

The IAM role has a trust policy that determines which principals are allowed to assume it.
So even if the user has permission to call sts:AssumeRole, the role must also trust that user.
This distinction is fundamental:
The identity policy says what the principal is allowed to do.
The trust policy says who is allowed to assume the role.

Applying Least Privilege

The lab did not simply ask for the quickest possible fix.
It required the solution to follow least privilege.
The Operator-User should not receive broad permissions such as:
1
sts:AssumeRole on *
when the user only needs to assume one specific role.
Instead, the permission should be limited to the intended role.
Conceptually, the permission should look like:
1
2
3
4
5
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<account-id>:role/Operator-Role"
}
The important part is the Resource.
Rather than allowing the user to assume arbitrary roles, the permission is scoped to Operator-Role.
This significantly reduces the potential impact if the user's credentials are compromised.
The lab also restricted the solution to preconfigured customer-managed policies whose names began with IAM-User-Policy; creating a new identity-based policy was not permitted.

Configuring the Role Trust Policy

The second half of the solution involved the Operator-Role trust policy.
The trust relationship needed to allow Operator-User to assume the role.
This is different from the permissions attached to the role.
The role's permission policies determine what the role can do after it has been assumed.
The trust policy determines who can assume it in the first place.
This gives us another useful distinction:
1
2
3
4
5
6
7
Trust Policy
│
└── Who can assume this role?

Permission Policy
│
└── What can the role do after assumption?
For this scenario, the trust relationship needed to be restricted to Operator-User.
That satisfies the second least-privilege requirement: the role should only be assumable by the intended user.
The lab's stated objective specifically required viewing and updating both the user's identity-based policy and the IAM role's trust policy.

The Two Policies Must Work Together

This was probably the most important lesson from the lab.
For the role assumption to succeed, the configuration needs to form a valid authorization relationship.
1
2
3
4
5
6
7
sts:AssumeRole
Operator-User ──────────────────────► Operator-Role
│ │
│ │
▼ ▼
Identity Policy Trust Policy
allows assumption trusts user
If the identity policy allows the action but the role does not trust the user, the request fails.
If the role trusts the user but the user's identity policy does not allow the operation, the request also fails.
Therefore, troubleshooting IAM access requires looking at the complete authorization path, not just one policy.

Verifying the Fix

After making the required IAM changes, I returned to the Operator-User console and attempted to switch roles again.
This time, the role switch succeeded.
The AWS Management Console redirected to the console with Operator-Role shown as the active identity.
That confirmed that the IAM configuration had been corrected.
The lab therefore followed a useful troubleshooting pattern:
1
2
3
4
5
6
7
8
9
10
11
12
13
Reproduce the failure
↓
Identify the intended access path
↓
Inspect identity permissions
↓
Inspect role trust policy
↓
Apply least privilege
↓
Retry the operation
↓
Verify successful role assumption

Why Role-Based Access Is Important

The scenario also demonstrates why organizations often prefer role-based access over attaching broad permissions directly to users.
Imagine an organization where employees are given powerful permissions directly on their IAM users.
Over time, permissions can accumulate.
A user might eventually have permissions for services they no longer need, increasing the organization's attack surface.
With role-based access, permissions can instead be associated with specific responsibilities.
For example:
1
2
3
4
5
6
7
8
9
10
11
Developer User
│
└── Assume Developer Role

Security Analyst
│
└── Assume Security Role

Operations User
│
└── Assume Operations Role
Each role can have a defined permission boundary based on the user's current responsibilities.
This makes access easier to reason about and can reduce excessive permissions.

Least Privilege in Practice

Least privilege is often described simply as:
Give users only the permissions they need.
But the lab showed that this principle needs to be applied at multiple levels.
For the Operator-User:
  • Allow only the required sts:AssumeRole action.
  • Restrict the resource to Operator-Role.
  • Do not allow the user to assume arbitrary roles.
For Operator-Role:
  • Restrict the trust relationship to Operator-User.
  • Give the role only the permissions required for its intended workload.
This creates a much tighter authorization model than simply allowing broad access.

Troubleshooting IAM Requires a Structured Approach

IAM errors can sometimes be frustrating because the visible error message does not always immediately tell you which policy is responsible.
A useful troubleshooting approach is to work through the authorization chain systematically.

1. Identify the principal

Who is making the request?
In this case:
Operator-User

2. Identify the requested action

What is the user trying to do?
In this case:
sts:AssumeRole

3. Identify the target resource

Which role is being assumed?
Operator-Role

4. Check the identity-based policy

Does the principal have permission to perform the action against that role?

5. Check the trust policy

Does the target role trust the principal?

6. Check for restrictions

Are there other policies or controls that could explicitly deny the request?

7. Retry and verify

After making the smallest necessary change, test the original operation again.
This method is much more reliable than randomly adding permissions until something works.

The Security Lesson

One of the biggest lessons I took from this exercise is that "fixing access" and "fixing access securely" are two different things.
A broad permission could potentially make the role assumption work, but it would not necessarily be a good security solution.
For example, allowing:
1
sts:AssumeRole → *
might solve a particular access problem, but it would also allow the user to attempt to assume other roles for which they were not intended to have access.
The better approach is to make the smallest change necessary to satisfy the business requirement.
In this case:
1
2
3
4
5
6
7
8
9
Operator-User
│
│ Can assume only
▼
Operator-Role
│
│ Trusts only
▼
Operator-User
This creates a tightly controlled relationship.

Connecting the Lab to Cloud Security

Although the lab was focused on IAM troubleshooting, the concepts extend directly into cloud security engineering.
IAM is one of the most important security boundaries in AWS.
A compromised credential with excessive permissions can potentially become a much larger security problem.
This is why several IAM principles matter:
  • Least privilege
  • Role-based access
  • Explicit trust relationships
  • Resource-level permission scoping
  • Avoiding unnecessary permissions
  • Regular permission review
The lab also reinforced an important operational principle:
When troubleshooting access, do not immediately grant more permissions.
Instead, determine exactly what action is required, identify the principal and resource involved, and inspect the policies governing that relationship.

What I Learned

This lab strengthened my understanding of several IAM concepts.

1. Identity policies and trust policies have different purposes

An identity-based policy determines what a principal can do.
A trust policy determines who can assume a role.

2. Role assumption requires the relationship to be correctly configured

The user needs permission to assume the role, and the role needs to trust the user.

3. Least privilege should be applied to role assumption itself

It is not enough to restrict the permissions inside the role. The ability to assume the role should also be restricted.

4. Reproducing the problem is part of troubleshooting

Rather than immediately changing configuration, I first confirmed the failure. This provided a clear baseline for verification.

5. IAM troubleshooting should be systematic

Instead of adding permissions randomly, trace the request from the principal to the action and then to the target resource.
This AWS Builder Lab was a good reminder that IAM is more than creating users and attaching policies.
Understanding how identity-based policies, trust policies, role assumption, and least privilege interact is essential when working with AWS security.
The most useful takeaway for me was the distinction between:
“Who is allowed to assume this role?”
and
“What is this role allowed to do?”
The first question is answered by the role's trust policy.
The second is answered by the permissions attached to the role.
When those two concepts are combined with least-privilege access, IAM becomes much easier to reason about and troubleshoot.
For cloud security, this is an important skill because access failures are inevitable in real environments. The goal is not simply to make the error disappear.
The goal is to understand why the request was denied, make the smallest appropriate change, and preserve the security boundaries while restoring access.
That is the difference between simply fixing an IAM problem and fixing it securely.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article