How to Fix: AWS S3 AccessDenied 403

Framework: AWSError Code: 403Severity: High

Symptoms

Root Cause

The request lacks the necessary permissions. This is typically due to one of the following:

Resolution (Step-by-Step)

  1. Identify the caller and action. Check CloudTrail or the error message for the exact userArn and action (e.g., s3:GetObject).

    aws sts get-caller-identity
  2. Verify IAM permissions. Ensure the IAM user/role has the required actions.

    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::your-bucket", "arn:aws:s3:::your-bucket/*"]
    }
  3. Check S3 bucket policy. Use the AWS CLI to retrieve and inspect the policy.

    aws s3api get-bucket-policy --bucket your-bucket --query Policy --output text | jq .

    Look for explicit Deny statements or missing Allow for the principal.

  4. Review S3 Block Public Access settings. If the bucket policy allows public access, these settings can override it.

    aws s3api get-public-access-block --bucket your-bucket

    If BlockPublicPolicy is true, you cannot set a public bucket policy. Set it to false if needed:

    aws s3api put-public-access-block --bucket your-bucket --public-access-block-configuration BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
  5. Validate pre-signed URLs. If using pre-signed URLs, ensure they are generated with the correct IAM user and within the expiration window.

    aws s3 presign s3://your-bucket/object.txt --expires-in 3600

Verification

Attempt the original operation again. Use the AWS CLI with debug output to confirm the request is allowed:

aws s3 ls s3://your-bucket/ --debug 2>&1 | grep -i "accessdenied\|allow\|deny"

A successful response will show the object list or a 200 OK status.