You can see the EC2 instance list, but clicking “Launch instance” reports insufficient permissions. The console shows both controls, yet IAM evaluates viewing resources and creating one as different API actions. Follow one user with a read-only policy, then see what changes when a group policy is added.
Why can you list instances but not create one?
Suppose IAM user reader has only AmazonEC2ReadOnlyAccess. The current managed policy permits EC2 Describe operations but does not allow ec2:RunInstances, the operation used to launch an instance. AWS publishes the policy's default-version document.
The diagram evaluates one RunInstances request. The read-only policy supplies no matching Allow; a group's EC2 full-access policy supplies one. A matching Allow does not guarantee that every real instance launch succeeds, because other limits and request requirements can still apply.
Policies applied to reader | ec2:DescribeInstances | ec2:RunInstances |
|---|---|---|
User has only AmazonEC2ReadOnlyAccess | Allowed | Implicitly denied: no matching Allow |
Read-only user policy plus group AmazonEC2FullAccess | Allowed | Group policy has a matching Allow |
The first denial does not require an explicit Deny statement. IAM generally denies a request by default when no applicable Allow exists. The action being requested matters more than which console button is visible.
What changes when a group policy is attached?
Now put reader in an ec2-operators group with AmazonEC2FullAccess. Its ec2:* Allow covers ec2:RunInstances. The user's read-only policy need not be removed: IAM evaluates the user's and group's applicable identity-based permissions together. AWS documents the full-access policy.
For this one request, the explanatory evaluation becomes:
Request: reader → ec2:RunInstances
Before group: User ReadOnly has no matching Allow → default deny
After group: User ReadOnly has no matching Allow
Group EC2 Full has ec2:* Allow → this action has an AllowThis comparison is based on published policy definitions, not a claim that an instance was launched in a live AWS account. A group Allow is not a promise of successful provisioning: resource conditions, permission boundaries, organization controls, explicit Deny statements, or a separate iam:PassRole requirement can still block the workflow.
What if AccessDenied remains after the group Allow?
First read the denied action name. Was it ec2:RunInstances or another action used during launch? Then verify the signed-in principal, group membership, attached policy, and default policy version. A similarly named user or group can lead you to inspect the wrong policy for a long time.
An applicable explicit Deny overrides an Allow. A permission boundary or AWS Organizations service control policy can further restrict what is permitted. The AWS IAM evaluation guide distinguishes default denial, explicit denial, and matching Allow. Narrow down the blocking boundary instead of attaching broader policies blindly.
AmazonEC2FullAccess makes the example easy to compare but is broad for day-to-day production access. Grant only the required actions, resources, and conditions, and prefer temporary role credentials over long-lived user keys where feasible.
Key takeaways
Being allowed to describe EC2 instances does not establish permission to launch one. Trace the denied action → user policy → group Allow → explicit Deny and other boundaries. A group policy can change the action's evaluation, but actual launch success still depends on the full request and applicable controls.

