AccessDenied
S3 PutObject AccessDenied with a valid IAM policy
- Product
- AWS S3
- Severity
- Severity: medium
- Updated
- Read
- 5 min
The identity policy allows s3:PutObject, but another layer — bucket policy, KMS key policy, or an SCP — denies it. Explicit denies always win.
An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
Symptoms
- Uploads fail while ListBucket and GetObject succeed.
- The IAM policy simulator reports "allowed" for the action.
- Failures only occur on buckets with default SSE-KMS encryption.
Cause
- The role lacks kms:GenerateDataKey on the bucket’s KMS key.
- A bucket policy requires a header, such as x-amz-server-side-encryption, that the client omits.
- An Organizations SCP denies writes outside approved regions.
Resolution
Step 1: Confirm the calling identity
Make sure the request is signed by the role you think it is.
bashaws sts get-caller-identityStep 2: Grant KMS permissions
Add the key actions to the role, and confirm the key policy trusts the account.
json{ "Effect": "Allow", "Action": ["kms:GenerateDataKey", "kms:Decrypt"], "Resource": "arn:aws:kms:us-east-1:123456789012:key/<key-id>" }Step 3: Search CloudTrail for the deny source
Filter by errorCode AccessDenied and read the errorMessage — it often names the policy type that denied the request.
bashaws cloudtrail lookup-events \ --lookup-attributes AttributeKey=EventName,AttributeValue=PutObject \ --max-results 5