AWS Error: AccessDeniedException — IAM Permission Denied
An error occurred (AccessDeniedException) when calling the GetObject operation:
User: arn:aws:iam::123456789012:user/deploy-bot is not authorized to perform:
s3:GetObject on resource: "arn:aws:s3:::my-prod-bucket/config.json"
because no identity-based policy allows the s3:GetObject action
AccessDeniedException is AWS’s universal “your IAM principal cannot do this” response. It’s HTTP 403 with a structured message that almost always names the principal, the action, and the resource. The fix is rarely to grant *:* — it’s to read the message, find the gap, and add a tightly-scoped Allow for the exact action the caller needs.
The single most useful debugging habit is to log aws sts get-caller-identity at the start of every failing code path. It tells you the actual principal ARN AWS is evaluating, which is often different from what you expected — especially when running on EC2 (instance profile), Lambda (execution role), or after AssumeRole chains.
Why this happens
- No identity-based policy grants the action. The IAM user or role attached to the request has no policy that includes an `Allow` for the specific action (e.g., `s3:GetObject`) on the specific resource. AWS denies by default — silence is denial.
- Explicit Deny in an SCP, permission boundary, or session policy. Even if the identity policy says Allow, an Organizations SCP, a permission boundary, or an `AssumeRole` session policy can override with an explicit Deny. The error message will say `with an explicit deny in a service control policy` or similar — read it carefully.
- Resource policy blocks the principal. S3 bucket policies, KMS key policies, SNS topic policies, and Lambda resource policies can deny access independent of the caller's IAM. Cross-account calls require BOTH the caller's IAM AND the resource policy to allow the action.
- Wrong region or partition in the resource ARN. Policies that use `arn:aws:s3:::bucket/*` won't match `arn:aws-cn:s3:::bucket/*` (China) or `arn:aws-us-gov:...` (GovCloud). For regional services, an ARN with the wrong region in a `Resource` block silently fails to match.
- Condition keys not satisfied. Conditions like `aws:SourceVpc`, `aws:PrincipalTag`, `s3:RequestObjectTag`, or MFA requirements (`aws:MultiFactorAuthPresent`) can cause an Allow to evaluate to false. The denied request matched the action and resource but failed a condition.
How to fix it
Fixes are ordered by likelihood. Start with the first one that matches your context.
1. Read the error message — it names the missing permission
Modern AWS error messages include the principal ARN, the exact action, the resource ARN, and often the policy type that caused the deny (`identity-based policy`, `resource-based policy`, `permission boundary`, `service control policy`). Copy those three values straight into a new policy statement.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowConfigRead",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-prod-bucket/config.json"
}
]
}
2. Use IAM Access Analyzer or the policy simulator to confirm
Before redeploying, run the IAM Policy Simulator or `aws accessanalyzer` against your draft policy with the exact principal, action, and resource. It surfaces SCP and boundary denies that the console hides.
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/deploy-bot \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-prod-bucket/config.json
3. Check resource policies for cross-account or service-to-service calls
Cross-account S3, KMS, and SNS calls need both sides to allow. Add the calling principal to the resource's policy, and don't forget KMS — encrypted S3 objects require `kms:Decrypt` on the key as well as `s3:GetObject` on the bucket.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountRead",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789012:role/deploy-bot" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-prod-bucket/*"
}
]
}
4. Inspect the assumed role's session policy
`sts:AssumeRole` can attach a session policy that scopes down the role's permissions. If your role has `s3:*` but you assumed it with a session policy of `s3:ListBucket` only, GetObject will deny. Log the session policy at the call site to debug.
5. Turn on CloudTrail and search for the exact denied call
CloudTrail event `errorCode: AccessDenied` records the principal, action, resource, and the policy type that denied the call. Filter by `userIdentity.arn` and `eventName` to find the exact deny event and confirm whether it was identity-based, resource-based, or SCP-based.
Detection and monitoring in production
Alarm on `AccessDenied` events in CloudTrail at higher than baseline rates. A spike usually means a recent IAM change, a new SCP, or a rotated role that lost a policy attachment. Tag your CloudWatch alarm with the principal ARN so you know which service is degraded.
Related errors
- awsThrottlingExceptionYou exceeded the per-second or per-account API request limit for an AWS service. Most AWS APIs use a token bucket — sustained or bursty traffic above the bucket refill rate gets throttled.
- awsNoSuchBucketThe S3 bucket name in your request does not exist in the region your client is calling. Either the name is misspelled, the bucket was deleted, or your client is pointed at the wrong region for a bucket that exists elsewhere.
- github403_rate_limitYou exceeded GitHub's primary REST API rate limit — 60 requests/hour for unauthenticated calls, 5,000/hour for personal access tokens, or 15,000/hour for GitHub App installations. The response is HTTP 403 with `X-RateLimit-Remaining: 0`.
Frequently asked questions
What's the difference between AccessDenied and AccessDeniedException? +
Why does the AccessDeniedException message sometimes hide the reason? +
I added the policy but still get AccessDeniedException. What''s going on? +
Does `Effect: Deny` always win over `Effect: Allow`? +
Can `s3:*` in my policy still produce AccessDeniedException for s3:GetObject? +
How do I debug an SCP-based AccessDeniedException without org-admin access? +
Why do I get AccessDeniedException calling KMS even though my role has full S3 access? +
Are there tools that automatically suggest the missing IAM policy? +
When to escalate to AWS support
Escalate to your AWS account or org admin if (a) the error message points at an SCP you don't control, (b) a permission boundary you didn't create blocks the call, or (c) you've reproduced the deny with the IAM Policy Simulator and confirmed all your policies allow but CloudTrail still shows Deny — that's a service-side bug worth a support case with the request ID.