AWS Hands-On | S3 Security | S3 CORS
📌 Notice
This is a hands-on tutorial accompanying the blog post:
“Pass the AWS Certified Solutions Architect Associate Certification SAA-C03-(Episode 12: S3 Security)”
🔹 Focus: Practical implementation of Amazon S3.
🔹 For theoretical concepts and exam-style questions, please refer to the main blog post (link to parent blog).
Here’s a step-by-step guide to practicing CORS (Cross-Origin Resource Sharing) with Amazon S3, based on the provided content:
Objective: Understand how CORS prevents cross-origin requests by default in web browsers and how to configure S3 bucket CORS policies to allow such requests.
Prerequisites:
✔ An AWS account with access to Amazon S3.
✔ Two HTML files:
index.html
: Contains a script to fetch another HTML file. (You'll need to modify it as described in Step 1).extra-page.html
: A simple HTML file with content like "This extra page has been successfully loaded."
Step 1: Prepare Your index.html
File for CORS Demo
- Open
index.html
: Open yourindex.html
file in a text editor. - Uncomment CORS Demo Section:
<!DOCTYPE html>
<html>
<body>
<h1>I Really love coffee!</h1>
<p>Hello world!</p>
<img src="coffee.jpg" width="300">
</body>
<!-- CORS DEMO -->
<div id="tofetch">
<script>
var tofetch = document.getElementById("tofetch");
fetch('extra-page.html')
.then((response) => {
return response.text();
})
.then((html) => {
tofetch.innerHTML = html
});
</script>
</html>
3. Save index.html
: Save the modified file.
Step 2: Create Your “Origin” S3 Bucket and Host index.html
- Create S3 Bucket: In the AWS S3 console, click “Create bucket”.
- Configure Bucket Details (Origin):
- Bucket name: Choose a unique name (e.g.,
demo-cors-mino-v2
). - AWS Region: Choose a region (e.g.,
ap-southeast-1
- Singapore, as the example used Canada for the "other origin," and I'm in Sri Lanka, making a region like Singapore a good alternative to demonstrate cross-region). - Block Public Access settings: Uncheck “Block all public access” (you’ll make this bucket public). Acknowledge the warning.
- Leave other settings as default.
3. Create Bucket: Click “Create bucket”.
4. Enable Static Website Hosting:
- Go into your newly created “Origin” bucket.
- Click the “Properties” tab.
- Scroll down to “Static website hosting” and click “Edit”.
- Select “Enable”.
- Hosting type: “Host a static website”.
- Index document:
index.html
. - Click “Save changes”.
5. Set Bucket Policy for Public Access:
- Click the “Permissions” tab.
- Under “Bucket policy”, click “Edit”.
- Paste the following policy, replacing
YOUR_ORIGIN_BUCKET_NAME
with the actual name of your origin bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_ORIGIN_BUCKET_NAME/*"
}
]
}
- Click “Save changes”.
6. Upload Files to Origin Bucket:
- Go to the “Objects” tab. * Click “Upload”, then “Add files”.
- Select both your modified
index.html
andextra-page.html
files. - Click "Upload".
7. Test Initial Setup (Same Origin):
- Go to the "Properties" tab of your origin bucket.
- Copy the "Bucket website endpoint" URL.
- Paste it into your browser.
Observation: You should see "I love coffee, Hello world! The coffee image." followed by "This extra page has been successfully loaded." This confirms the
fetch
request worked within the same origin.
Step 3: Create Your “Other Origin” S3 Bucket and Host extra-page.html
- Create S3 Bucket: In the AWS S3 console, click “Create bucket”.
- Configure Bucket Details (Other Origin):
- Bucket name:
demo-other-origin-mino
(or a unique name). - AWS Region: Choose a different region from your origin bucket (e.g.,
us-east-1
- N. Virginia). - Block Public Access settings: Uncheck “Block all public access”. Acknowledge the warning.
- Leave other settings as default.
3. Create Bucket: Click “Create bucket”.
4. Enable Static Website Hosting:
- Go into your new “Other Origin” bucket.
- Click the “Properties” tab.
- Scroll down to “Static website hosting” and click “Edit”.
- Select “Enable”.
- Hosting type: “Host a static website”.
- Index document:
index.html
(even though we're only puttingextra-page.html
). - Click “Save changes”.
5. Set Bucket Policy for Public Access:
- Click the “Permissions” tab.
- Under “Bucket policy”, click “Edit”.
- Paste the following policy, replacing
YOUR_OTHER_ORIGIN_BUCKET_NAME
with the actual name of this other origin bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_OTHER_ORIGIN_BUCKET_NAME/*"
}
]
}
- Click “Save changes”.
6. Upload extra-page.html
to Other Origin:
- Go to the "Objects" tab.
- Click "Upload", then "Add files".
- Select only your
extra-page.html
file. - Click "Upload".
7. Verify extra-page.html
is Public:
- Click on the
extra-page.html
object in the "Other Origin" bucket. - Copy its "Object URL".
- Paste it into your browser.
- You should see "This extra page has been successfully loaded."
Step 4: Modify index.html
to Fetch from the "Other Origin"
- Remove
extra-page.html
from Origin Bucket:
- Go back to your first (“Origin”) bucket.
- Select
extra-page.html
and delete it.
Reason: This ensures the
fetch
request must go to the other bucket, demonstrating the cross-origin scenario.
- Go back to your webpage (the one using the origin bucket’s endpoint) and refresh. You should now see a “404 Not Found” for the
extra-page.html
in the browser's console, as it can't find it locally.
2. Get the “Other Origin” extra-page.html
URL:
- Go to your
demo-other-origin-mino
bucket. - Go to the “Properties” tab.
- Copy the “Bucket website endpoint” URL.
- Append
/extra-page.html
to it (e.g.,http://demo-other-origin-mino.s3-website.us-east-1.amazonaws.com/extra-page.html
). This is the full URL to theextra-page.html
in the other bucket.
<!DOCTYPE html>
<html>
<body>
<h1>I Really love coffee!</h1>
<p>Hello world!</p>
<img src="coffee.jpg" width="300">
</body>
<!-- CORS DEMO -->
<div id="tofetch">
<script>
var tofetch = document.getElementById("tofetch");
fetch('http://demo-other-origin-mino.s3-website.us-east-1.amazonaws.com/extra-page.html')
.then((response) => {
return response.text();
})
.then((html) => {
tofetch.innerHTML = html
});
</script>
</html>
3. Edit index.html
to Point to Other Origin:
- Open your
index.html
file in a text editor again. - Find the
fetch('extra-page.html')
line. - Replace
'extra-page.html'
with the full URL you just copied for theextra-page.html
in the "Other Origin" bucket. - Example:
fetch('http://demo-other-origin-stephane.s3-website.ca-central-1.amazonaws.com/extra-page.html')
- Save the modified
index.html
.
4. Upload Updated index.html
to Origin Bucket:
- Go back to your first (“Origin”) bucket.
- Click “Upload”, then “Add files”, and select your newly modified
index.html
. - Click “Upload”. (It will overwrite the existing
index.html
.)
Step 5: Observe CORS Blockage (Before CORS Policy)
- Open Developer Tools: Go to your browser (Chrome recommended). Navigate to the webpage hosted on your origin bucket’s endpoint. Right-click anywhere on the page, select “Inspect” (or “More tools” > “Developer tools”).
- Go to “Console” Tab: In the Developer Tools, click on the “Console” tab.
- Refresh Page: Refresh the webpage.
Observation: You will see “Hello world! I love coffee” and the image. However, the “This extra page has been successfully loaded.” text will not appear. More importantly, in the Console tab of your developer tools, you will see an error message similar to:
Access to fetch at 'http://demo-other-origin-stephane.s3-website.ca-central-1.amazonaws.com/extra-page.html' from origin 'http://YOUR_ORIGIN_BUCKET_ENDPOINT' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Explanation: The browser is preventing your
index.html
(from Origin A) from fetchingextra-page.html
(from Origin B) because Origin B has not explicitly allowed requests from Origin A.
Step 6: Add CORS Policy to the “Other Origin” Bucket
- Navigate to “Other Origin” Bucket Permissions: Go to your
demo-other-origin-mino
bucket. - Go to “Permissions” Tab: Click on the “Permissions” tab.
- Edit CORS Policy: Scroll down to “Cross-origin resource sharing (CORS)” and click “Edit”.
- Paste CORS Configuration: Paste the following JSON configuration into the editor.
- Crucially, replace
YOUR_ORIGIN_BUCKET_ENDPOINT
with the exact bucket website endpoint of your first ("Origin") bucket, without a trailing slash. (e.g.,http://demo-cors-mino-v2.s3-website.ap-southeast-1.amazonaws.com
)
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"http://YOUR_ORIGIN_BUCKET_ENDPOINT"
],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
5. Save Changes: Click “Save changes”.
Explanation: This CORS policy tells the “Other Origin” bucket that it’s allowed to receive GET requests from your “Origin” bucket’s domain.
Step 7: Verify CORS Success
- Refresh Webpage: Go back to your webpage (the one hosted on your origin bucket’s endpoint) in the browser with Developer Tools open.
- Refresh the page again.
Observation: The “This extra page has been successfully loaded.” text should now appear on your webpage!
- Verify in Developer Tools:
- In the “Network” tab, find the request for
extra-page.html
. - Click on it, then go to the “Headers” tab.
- Under “Response Headers”, you should now see
Access-Control-Allow-Origin: http://YOUR_ORIGIN_BUCKET_ENDPOINT
(or similar) andAccess-Control-Allow-Methods: GET
.
Conclusion:
You have successfully demonstrated CORS in Amazon S3. You’ve learned that:
- Web browsers enforce a Same-Origin Policy for security.
- By default, cross-origin requests are blocked.
- You must configure a CORS policy on the receiving S3 bucket (the one serving the resource) to explicitly allow requests from specified origins.
- The
Access-Control-Allow-Origin
header is key to enabling these requests.