← All posts
2 min read

Configure S3 CORS for one web origin

#aws#cli#s3#storage#web
📑 On this page

Part 33 of AWS from Zero. This lesson keeps the scope to one S3 behavior you can verify from the terminal.

What we are learning

CORS tells browsers which cross-origin requests may be made. It does not grant S3 permission; IAM, bucket policy, and presigned authorization still apply.

Before you run it

aws sts get-caller-identity
REGION="ap-south-1"
BUCKET="replace-with-your-private-demo-bucket"

Use a private general purpose bucket that you own. Replace every placeholder before running a write or delete command.

The command

cat > cors.json <<'EOF'
{
  "CORSRules": [{
    "AllowedOrigins": ["https://app.example.com"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }]
}
EOF
 
aws s3api put-bucket-cors \
  --bucket "$BUCKET" \
  --cors-configuration file://cors.json

A successful configuration command may return no output. Treat inspection as a separate required step.

Inspect the result

aws s3api get-bucket-cors \
  --bucket "$BUCKET" \
  --output json

S3 evaluates CORS rules in order and uses the first matching rule.

One tiny variation

aws s3api delete-bucket-cors --bucket "$BUCKET"
aws s3api get-bucket-cors --bucket "$BUCKET"

Deleting the configuration should make the second command return NoSuchCORSConfiguration.

Common mistake

Do not use AllowedOrigins: ["*"] with broad write methods merely to silence a browser error. Match the real origin and only the methods your application needs.

Cleanup

aws s3api delete-bucket-cors --bucket "$BUCKET" 2>/dev/null || true
rm cors.json

The bucket remains private and the temporary CORS configuration is removed.

Next, we will learn Add tags to an S3 object.

Official AWS CLI reference