Problem: S3 File Upload is Successful but Returns 403 Forbidden on Access


Problem: S3 File Upload is Successful but Returns 403 Forbidden on Access

Bash
$ aws s3 cp myfile.txt s3://my-private-bucket/
upload: ./myfile.txt to s3://my-private-bucket/myfile.txt

$ aws s3 ls s3://my-private-bucket/
2025-02-09 10:05:32   102400  myfile.txt

# Try to access the file via URL
$ curl -I https://my-private-bucket.s3.amazonaws.com/myfile.txt
HTTP/1.1 403 Forbidden
x-amz-request-id: 123456789ABCDEF
x-amz-id-2: abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Content-Type: application/xml

Issue:

Even though the file was successfully uploaded, trying to access it via a web browser or curl returns 403 Forbidden. This usually happens because:

  • Bucket Public Access Block settings – The bucket has public access completely disabled.
  • Object ACL is private – The file is uploaded without public-read permissions.
  • Missing or restrictive bucket policy – The bucket policy does not allow public access.

Fix: Adjust ACLs and Bucket Policy to Allow Public Access

Bash
# Step 1: Check if public access is blocked at the bucket level
$ aws s3api get-public-access-block --bucket my-private-bucket
{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": true,       # TRUE = Blocks public access via ACLs
        "IgnorePublicAcls": true,      # TRUE = Ignores any existing public ACLs
        "BlockPublicPolicy": true,     # TRUE = Prevents public bucket policies
        "RestrictPublicBuckets": true  # TRUE = Completely blocks all public access
    }
}

# Explanation: 
# If ANY of these values are "true," then the bucket will ignore ACLs and 
# policies that allow public access. This is why even correctly 
# configured permissions might still result in "403 Forbidden" errors.
# Step 2: Remove public access block settings if public access is needed
$ aws s3api delete-public-access-block --bucket my-private-bucket

# Step 3: Set the object ACL to allow public read
$ aws s3api put-object-acl --bucket my-private-bucket --key myfile.txt --acl public-read

# Step 4: Verify the ACL is now set to public-read
$ aws s3api get-object-acl --bucket my-private-bucket --key myfile.txt
{
    "Owner": { "DisplayName": "aws-user", "ID": "abcdef1234567890" },
    "Grants": [
        {
            "Grantee": {
                "Type": "CanonicalUser",
                "ID": "abcdef1234567890"
            },
            "Permission": "FULL_CONTROL"
        },
        {
            "Grantee": {
                "Type": "Group",
                "URI": "http://acs.amazonaws.com/groups/global/AllUsers"
            },
            "Permission": "READ"
        }
    ]
}

# Step 5: Add a bucket policy to allow public reads (optional)
$ aws s3api put-bucket-policy --bucket my-private-bucket --policy '{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-private-bucket/*"
        }
    ]
}'

# Step 6: Verify public access with curl
$ curl -I https://my-private-bucket.s3.amazonaws.com/myfile.txt
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 102400

Need AWS Expertise?

If you're looking for guidance on AWS challenges or want to collaborate, feel free to reach out! We'd love to help you tackle your AWS projects. 🚀

Email us at: info@pacificw.com


Image: Gemini

Comments

Popular posts from this blog

The New ChatGPT Reason Feature: What It Is and Why You Should Use It

Raspberry Pi Connect vs. RealVNC: A Comprehensive Comparison

The Reasoning Chain in DeepSeek R1: A Glimpse into AI’s Thought Process