Solve: AccessDeniedException or UnauthorizedOperation—Fixing IAM Errors in EC2 and Lambda
Problem
You launch an EC2 instance, call an AWS API from inside Lambda, or spin up automation with the CLI — and suddenly hit a wall: UnauthorizedOperation, AccessDeniedException, or a plain An error occurred (AccessDenied). It’s unclear which policy blocked the action or even which part of the system is to blame.
This lack of clarity halts builds, baffles even senior engineers, and causes support tickets to pile up. IAM debugging outside of S3 can be even more obscure because the error messages tend to be generic, and the services involved often rely on multiple assumed roles and service-linked resources.
You launch an EC2 instance, call an AWS API from inside Lambda, or spin up automation with the CLI — and suddenly hit a wall: UnauthorizedOperation, AccessDeniedException, or a plain An error occurred (AccessDenied). It’s unclear which policy blocked the action or even which part of the system is to blame.
This lack of clarity halts builds, baffles even senior engineers, and causes support tickets to pile up. IAM debugging outside of S3 can be even more obscure because the error messages tend to be generic, and the services involved often rely on multiple assumed roles and service-linked resources.
Clarifying the Issue
At the heart of most EC2 and Lambda access problems is a misunderstanding of who’s performing the action, what policy applies, and how it’s being constrained. You might grant a policy to a role, but if that role is assumed by a service, or if the user context involves a boundary or SCP, then your permissions are filtered through layers you didn’t account for.
A few common examples:
- EC2 user tries to start instances and gets UnauthorizedOperation despite having ec2:StartInstances.
- A Lambda function can't call DynamoDB, throwing AccessDeniedException, even though the role appears to have dynamodb:PutItem.
- CLI calls fail under assumed roles because a session policy overrides the inline permissions.
- IAM’s web of policies doesn't make debugging easy. But there is a structured way through it.
Why It Matters
IAM is the backbone of AWS security and automation. When it misbehaves, engineers lose confidence, business logic fails, and timelines slip. In regulated industries or enterprise environments, one misconfigured permission can cause compliance failures or outages.
It’s not enough to know how to grant access — you need to know how to trace access. Without a strong debugging practice, even small teams can end up with bloated, over-permissive roles just to "make things work." That’s dangerous, expensive, and hard to reverse.
Key Terms
- AccessDeniedException – A general-purpose denial response, used by services like Lambda, DynamoDB, and STS.
- UnauthorizedOperation – A more specific error from EC2 and similar services indicating a disallowed action.
- Instance Profile – A container for an IAM role that EC2 instances assume when calling AWS services.
- AssumeRoleWithSessionPolicy – An STS call that temporarily attaches a policy to a session, potentially limiting access beyond the base role.
- Service-Linked Role – An AWS-managed IAM role preconfigured to support a specific service (e.g., AWSServiceRoleForEC2Spot).
- STS Credentials – Temporary credentials generated for roles assumed by users, services, or applications.
Steps at a Glance
- Identify the exact user, role, or session that made the failing request.
- Simulate the IAM policy for that principal.
- Check for SCPs, permission boundaries, or session policies.
- Confirm that the correct service-linked role or instance profile is in use.
- Test access manually by assuming the role and calling the API.
- Review CloudTrail logs to see the evaluated policy context.
Detailed Steps
1. Identify Who Made the Request
Use CloudTrail or diagnostic logs to determine which user or role triggered the action. Often, EC2 uses an instance profile, and Lambda uses an execution role:
Run this to simulate the role’s effective permissions:
3. Inspect SCPs, Boundaries, and Sessions
First check SCPs:
4. Confirm Role Is Attached Properly
For EC2:
For Lambda:
5. Test Access by Assuming the Role
Assume the role and call the API:
If this fails, you’ve confirmed the role is the problem. If it works, the issue might be with how the role is being assumed or passed during automation.
6. Review CloudTrail Logs for Final Clarity
Use CloudTrail logs to inspect the failing call:
Conclusion
AccessDeniedException and UnauthorizedOperation aren’t bugs — they’re messages from AWS that your access model has a logic error. IAM’s layered structure means that even a perfectly written policy might be overridden or misapplied by another layer.
Instead of guessing, follow a disciplined checklist: simulate policies, confirm roles and trust relationships, check for session and org-wide limits, and always test with assumed credentials. IAM is complex because it’s powerful — but it becomes manageable when you know how to trace its logic.
Need AWS Expertise?
We'd love to help you with your AWS projects. Feel free to reach out to us at info@pacificw.com.
Written by Aaron Rose, software engineer and technology writer at Tech-Reader.blog.
Comments
Post a Comment