๐๏ธ AWS S3 โ Extended Concepts
Versioning Deep Dive ยท Bucket Types ยท Static Hosting ยท CORS ยท Object Lock ยท Data Concepts
Part of my AWS learning journey โ transitioning from Systems Engineer to Cloud/DevOps. This session goes deeper into S3 โ versioning behaviour, static website hosting, CORS, Object Lock, and important data concepts every cloud engineer should know.
๐ Topics Covered
| # | Topic | Type |
|---|---|---|
| 1 | Bucket Versioning โ Deep Dive | Concept + Cert |
| 2 | Does S3 Store Only Changed Bytes? | Concept + Interview |
| 3 | Suspend Versioning โ What Actually Happens | Concept + Cert |
| 4 | General Purpose vs Directory Bucket | Concept + Cert |
| 5 | Storage Classes โ Context Recap | Concept |
| 6 | OLTP vs OLAP โ Data Concepts for Cloud Engineers | Concept + Interview |
| 7 | Static Website Hosting on S3 | Concept + Lab |
| 8 | CORS โ What It Is and Why S3 Needs It | Concept + Interview |
| 9 | S3 Object Lock โ WORM Model | Concept + Cert |
| 10 | Interview Questions | Interview |
| 11 | Practice Tasks | Practice |
Bucket Versioning โ Deep Dive
You know what versioning does at a surface level โ it keeps multiple versions of an object. But the behaviour in two specific scenarios is what most people get wrong, and both come up in exams and interviews.
Normal Upload Flow (Versioning Enabled)
Upload report.pdf โ Version ID: v1 (current)
Upload report.pdf again โ Version ID: v2 (current), v1 preserved
Upload report.pdf again โ Version ID: v3 (current), v1 + v2 preserved
GET report.pdf โ returns v3 (always returns current)
GET report.pdf?versionId=v1 โ returns v1 specifically
Every upload with the same key creates a new version. The previous ones are never touched.
Delete Flow (The Tricky Part)
This is where most people get confused โ and where interviewers test.
State: report.pdf has v1, v2, v3
DELETE report.pdf (standard delete, no versionId specified)
โ S3 does NOT delete anything
โ S3 adds a Delete Marker (a special object with its own Version ID)
โ GET report.pdf now returns 404 (marker hides the object)
โ But v1, v2, v3 still exist underneath
โ You're still paying storage for all three versions
Restoring a "deleted" object:
Delete the Delete Marker
โ Object reappears, GET report.pdf returns v3 again โ
Permanently deleting an object and all versions:
Must explicitly delete each version by its Version ID:
DELETE report.pdf?versionId=v1
DELETE report.pdf?versionId=v2
DELETE report.pdf?versionId=v3
DELETE <delete-marker>?versionId=dm-id
โ Now the object is truly gone, zero storage consumed
โ ๏ธ Cost trap: People enable versioning, never clean up old versions, and then wonder why their S3 bill is growing. Every version consumes storage. Fix: add a Lifecycle rule to expire non-current versions after X days.
Lifecycle rule โ Expire non-current versions after 30 days
โ Old versions auto-deleted after 30 days
โ Current version always kept
Does S3 Store Only Changed Bytes?
A natural question โ modern tools like git and incremental backups only store the difference (delta) between versions. Does S3 do the same?
No. S3 stores each version as a complete, separate object.
report.pdf v1 = 10 MB โ stored in full (10 MB)
report.pdf v2 = 10.2 MB โ stored in full (10.2 MB) โ NOT just the 0.2 MB diff
report.pdf v3 = 10.1 MB โ stored in full (10.1 MB)
Total storage consumed: 30.3 MB (not 10.2 MB)
Each version gets its own Version ID and is managed independently โ you can access, copy, restore, or delete any version directly.
Implication for cost planning:
- Frequently updated large files + versioning = storage costs multiply fast
- For 100 uploads/day of a 50 MB file: 100 ร 50 MB = 5 GB/day extra storage
- Always pair versioning with Lifecycle rules that expire old versions
๐ฏ Interview tip: "Does S3 versioning use delta storage like git?" โ No. Every version is a full copy. This is why Lifecycle policies to expire non-current versions are essential in production.
Suspend Versioning โ What Actually Happens
Once you enable versioning on a bucket, you cannot fully turn it off โ you can only suspend it. This is by design: AWS won't let you accidentally lose version history.
Behaviour After Suspension
Before suspension: v1, v2, v3 exist for report.pdf
Versioning suspended.
New upload: report.pdf v4
โ Gets Version ID: null (not a real UUID)
โ If another null version existed, it gets overwritten
โ v1, v2, v3 still safely preserved
State now:
report.pdf โ null version (v4 upload)
v3 (preserved)
v2 (preserved)
v1 (preserved)
Three states a bucket can be in:
| State | New uploads | Existing versions |
|---|---|---|
| Unversioned (never enabled) | No Version ID | N/A |
| Enabled | Full Version ID (UUID) | All preserved |
| Suspended | Version ID: null
|
All preserved |
Key rules to remember:
- Versioning: once enabled, can never go back to "Unversioned"
- Suspended โ Enabled: you can re-enable. All existing versions preserved, new uploads get UUIDs again
- Null version uploads: if you upload again while suspended, the previous null version is overwritten (but all UUID versions stay untouched)
๐ฏ Cert scenario: "A bucket has versioning enabled. The team wants to stop creating new versions to save costs but keep existing ones. What should they do?" โ Suspend versioning. New uploads will use null version ID and won't accumulate new versions, but all existing versions are retained.
General Purpose Bucket vs Directory Bucket
Historically S3 had one type of bucket. AWS introduced Directory Buckets for a specific high-performance use case. Knowing the difference matters for both certs and architecture decisions.
General Purpose Bucket
The standard S3 bucket you've been using in all labs. Think of it as a general warehouse โ stores anything, supports all features, multi-AZ redundancy by default.
Features: ALL S3 features supported
AZs: Multi-AZ (data replicated across 3+ AZs in a Region)
Storage classes: All classes (Standard, IA, Glacier, etc.)
Versioning: โ
Supported
Lifecycle rules: โ
Supported
Object Lock: โ
Supported
Replication: โ
Supported
Use for: Everything โ backups, web assets, data lakes, logs
Directory Bucket
Purpose-built for high-performance, latency-sensitive workloads โ think machine learning training data, real-time analytics, high-frequency log ingestion.
Think of it as an express warehouse inside one building โ extremely fast, but only within a single AZ and stripped of most management features.
Features: Limited to core operations
AZs: Single AZ only (Express One Zone storage class)
Storage classes: Only Express One Zone
Versioning: โ Not supported
Lifecycle rules: โ Not supported
Object Lock: โ Not supported
Performance: 10x faster than General Purpose for small objects
Use for: ML training, real-time data processing, low-latency apps
Decision guide:
Need all S3 features (versioning, lifecycle, replication)? โ General Purpose
Need maximum speed for ML/analytics inside one AZ? โ Directory Bucket
Need durability across multiple AZs? โ General Purpose
Need sub-10ms consistent latency at massive scale? โ Directory Bucket
โ ๏ธ Directory Buckets are in a single AZ โ if that AZ has an outage, your data is temporarily unavailable. Only use them for workloads where performance beats durability requirements.
Storage Classes โ Context Recap
Covered in depth last session. Quick mental model for reference:
How often will this data be accessed?
Daily/Active โ Standard
Unknown pattern โ Intelligent-Tiering (auto-manages itself)
Once a month โ Standard-IA (retrieval fee applies)
Once a quarter โ Glacier Instant Retrieval
Once a year โ Glacier Flexible (minutes-to-hours retrieval)
Almost never โ Glacier Deep Archive (cheapest, up to 12hr retrieval)
One AZ is fine + fast? โ Express One Zone (Directory Bucket only)
Lifecycle rules automate the transitions โ set it once, S3 moves objects down the chain automatically as they age. Always pair versioning with lifecycle rules that expire old versions.
OLTP vs OLAP โ Data Concepts Every Cloud Engineer Should Know
This pair of concepts comes up when you're designing cloud architectures involving databases and data pipelines โ which is constantly in DevOps and cloud roles.
OLTP โ Online Transaction Processing
What it does: Handles day-to-day, real-time business operations โ individual transactions, fast reads and writes, high concurrency.
Characteristics:
- Short, fast queries (milliseconds)
- Many concurrent users
- Writes and reads constantly
- Data is current and operational
- Optimized for INSERT, UPDATE, DELETE
Examples in real life: A customer places an order, a payment is processed, a hotel room is booked โ each of these is one OLTP transaction.
AWS services: RDS (MySQL, PostgreSQL), Aurora, DynamoDB
User clicks "Buy Now" on your site
โ
OLTP (RDS/Aurora)
โ
INSERT INTO orders VALUES (user_id, item_id, price, timestamp)
UPDATE inventory SET stock = stock - 1 WHERE item_id = 123
โ
Completed in milliseconds โ
OLAP โ Online Analytical Processing
What it does: Analyses large historical datasets to generate reports, trends, and business insights. Not for real-time transactions โ for answering questions like "what were our top-selling products last quarter across all regions?"
Characteristics:
- Complex queries across massive datasets (millions/billions of rows)
- Read-heavy (rarely writes)
- Aggregations, joins, GROUP BY across large tables
- Historical data, not real-time
- Optimized for fast analytical reads (columnar storage)
Examples in real life: Monthly sales report, customer churn analysis, inventory trend forecast.
AWS services: Amazon Redshift (data warehouse), Amazon Athena (query S3 directly with SQL)
Business analyst asks: "Show me total revenue by product category for 2025"
โ
OLAP (Redshift/Athena)
โ
SELECT category, SUM(revenue)
FROM sales_fact
WHERE year = 2025
GROUP BY category
โ
Scans billions of rows, returns in seconds โ
(would kill an OLTP database)
Why Both Matter Together
In real architectures, you use both โ OLTP for operations, OLAP for analysis:
Customer transactions โ RDS (OLTP) โ ETL pipeline โ Redshift (OLAP)
โ
Runs nightly, loads transformed data
Business reports run against Redshift
RDS never touched by analytical queries
Why separate them? Running a heavy analytical query against your OLTP database would lock tables, slow down real user transactions, and potentially take the site down. OLAP databases are architecturally different โ columnar storage, massively parallel processing โ built specifically for large scans.
Quick Comparison
| OLTP | OLAP | |
|---|---|---|
| Purpose | Real-time transactions | Historical analysis |
| Query type | Short, simple | Long, complex aggregations |
| Data volume | Thousands of rows | Billions of rows |
| Users | Many concurrent end users | Analysts, BI tools |
| Writes | Frequent | Rare (batch loads) |
| AWS services | RDS, Aurora, DynamoDB | Redshift, Athena |
| Storage | Row-oriented | Columnar (faster scans) |
๐ฏ Interview context: If asked "how would you design a reporting system that doesn't slow down production?" โ separate OLTP (RDS for transactions) from OLAP (Redshift/Athena for analytics), connected by an ETL pipeline. This pattern shows architectural thinking, not just tool knowledge.
Static Website Hosting on S3
S3 can serve a complete website โ HTML, CSS, JavaScript, images โ directly from a bucket, without any server.
Analogy: Normally a website needs a server running 24/7 waiting for visitors. Static hosting on S3 is like pinning your brochure to a public notice board โ it's always there, no one needs to "run" it, and millions of people can read it simultaneously.
What "Static" Means
Static = files that are the same for every visitor. The server doesn't generate content dynamically per user.
โ
Static (S3 can serve): โ Not static (S3 cannot serve):
HTML files Node.js / Express apps
CSS stylesheets PHP backend
JavaScript (React, Vue) Python Flask/Django
Images, fonts, PDFs Database queries
Pre-built React apps Server-side rendering
A React or Vue app that calls an API is fine โ the frontend is static files, the API runs on EC2/Lambda elsewhere.
Step-by-Step Setup
Step 1: Create bucket
Name: your-site-name.com (can match your domain)
Region: us-east-1 (or closest to users)
Block Public Access: DISABLE all 4 settings for public site
Step 2: Enable Static Website Hosting
Bucket โ Properties โ Static website hosting โ Enable
Index document: index.html
Error document: error.html (optional)
Save โ note the Website Endpoint URL
Step 3: Upload your files
Upload index.html, styles.css, app.js, images/
Make sure all files are present
Step 4: Add Bucket Policy (allow public read)
Bucket โ Permissions โ Bucket Policy โ Edit โ paste:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}]
}
Step 5: Test
Open the S3 Website Endpoint in browser
http://your-bucket-name.s3-website-ap-south-1.amazonaws.com
โ Your site loads โ
S3 Website URL vs S3 Object URL
These look similar but behave differently:
| S3 Object URL | S3 Website Endpoint | |
|---|---|---|
| Format | bucket.s3.region.amazonaws.com/key |
bucket.s3-website-region.amazonaws.com |
| Returns | The raw file | Serves index.html for /, error.html for 404 |
| HTTPS | โ | โ HTTP only |
| CloudFront compatible | โ | โ |
โ Production setup: Use CloudFront in front of S3 static hosting to get HTTPS, custom domain, and CDN caching. S3 alone gives you HTTP only with an ugly URL.
Best for: Personal portfolio, documentation site, React/Vue/Angular SPA, company landing page โ anything without server-side logic.
CORS โ Cross-Origin Resource Sharing
The Problem CORS Solves
Browsers enforce a security rule called the Same-Origin Policy โ a page loaded from domain-a.com cannot make JavaScript requests to domain-b.com unless explicitly permitted.
Analogy: You work at Company A and want to access files in Company B's building. Company B's security guard (the browser's CORS check) checks whether Company A employees are on the approved visitor list before letting you in.
Where This Appears with S3
Your frontend: https://myapp.com (served from EC2 or elsewhere)
Your S3 bucket: https://my-assets.s3.amazonaws.com
User visits myapp.com, JavaScript runs:
fetch('https://my-assets.s3.amazonaws.com/data.json')
โ Browser BLOCKS this request โ
โ "Cross-origin request blocked"
The browser blocked it because myapp.com โ my-assets.s3.amazonaws.com โ different origins.
Fixing It โ CORS Configuration on S3
You add a CORS rule to the S3 bucket that tells browsers: "Requests from myapp.com are approved."
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedOrigins": ["https://myapp.com"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]
Breaking it down:
| Field | Meaning |
|---|---|
AllowedOrigins |
Which domains can make requests โ ["https://myapp.com"] or ["*"] for all |
AllowedMethods |
Which HTTP methods are allowed โ GET, PUT, POST, DELETE, HEAD |
AllowedHeaders |
Which request headers are allowed โ ["*"] means all |
ExposeHeaders |
Which response headers the browser can read |
MaxAgeSeconds |
How long the browser can cache the CORS preflight response |
Bucket Policy vs CORS โ Key Distinction
This trips people up:
Bucket Policy: answers "WHO can access this bucket?"
โ Applies to: all clients (CLI, SDK, browser, curl)
โ Example: "Only my EC2 role can GetObject"
CORS: answers "Which BROWSER ORIGINS can use that access?"
โ Applies to: only browser-based JavaScript requests
โ Example: "myapp.com's JavaScript is allowed to fetch from this bucket"
Both must allow the request for a browser to successfully access S3:
- Bucket Policy says the user/origin is allowed
- CORS says the browser origin is allowed
๐ฏ Interview tip: "What's the difference between a bucket policy and CORS in S3?" โ Bucket policy controls who can access (any client). CORS controls which browser origins can access (browser JS only). They're complementary, not interchangeable.
S3 Object Lock โ WORM Model
What is WORM?
WORM = Write Once, Read Many โ once data is written, it cannot be modified or deleted for a defined period. This is a compliance requirement in industries like finance, healthcare, and legal.
Analogy: Object Lock is like writing in permanent marker on a whiteboard that's been laminated โ it can be read by anyone, but nobody can erase or change what's written during the protection period.
Two Retention Modes
Governance Mode
- Objects cannot be modified or deleted by regular users
- Authorized IAM users with
s3:BypassGovernanceRetentionpermission can bypass the lock - Use for: internal policies where administrators may occasionally need override ability
Regular user: DELETE object โ โ Blocked
Admin with bypass permission: DELETE object โ โ
Allowed (with override header)
Compliance Mode
- Objects cannot be modified or deleted by anyone โ including root user and AWS Support
- Once set, the retention period cannot be shortened
- Use for: regulated industries (SEC Rule 17a-4, HIPAA, FINRA) where even admins cannot bypass
Regular user: DELETE object โ โ Blocked
Admin: DELETE object โ โ Blocked
Root user: DELETE object โ โ Blocked
AWS Support: Cannot help delete โ โ Blocked
โ ๏ธ Compliance Mode is irreversible for the retention period. Think carefully before setting it โ if you set a 10-year retention in Compliance Mode, that data cannot be deleted for 10 years by anyone.
Two Lock Mechanisms
Retention Period โ protects the object version until a specific date
Object uploaded with retention: 2026-01-01 to 2036-01-01 (10 years)
โ Cannot be deleted or modified until 2036-01-01
โ After that date, normal rules apply
Legal Hold โ protects indefinitely until explicitly removed (no date)
Object placed under Legal Hold
โ Cannot be deleted until Legal Hold is removed
โ No expiry date โ remains until someone with s3:PutObjectLegalHold removes it
โ Used during litigation: "preserve everything related to this case"
Requirements & Use Cases
Requirements to enable Object Lock:
โ
Must enable at bucket creation (cannot enable on existing bucket)
โ
Versioning is automatically enabled and required
โ
Cannot disable versioning once Object Lock is active
Common use cases:
| Industry | Requirement | Mode |
|---|---|---|
| Finance | SEC 17a-4: emails and records for 7 years | Compliance |
| Healthcare | HIPAA: patient records retention | Compliance |
| Legal | Litigation hold on documents | Legal Hold |
| Backup | Ransomware-proof backups | Governance |
| Government | Regulatory audit records | Compliance |
๐ฏ Cert scenario: "A financial company needs to store trade records for 7 years and ensure not even admins can delete them." โ S3 Object Lock in Compliance Mode with a 7-year retention period. Governance Mode would be wrong here because admins could bypass it.
Object Lock vs Versioning vs Delete Marker
Versioning alone:
DELETE โ adds delete marker, data still recoverable
Versioning + Object Lock (Governance):
DELETE โ blocked for regular users, admins can bypass
Object still exists until retention period ends
Versioning + Object Lock (Compliance):
DELETE โ blocked for everyone, no bypass possible
Object guaranteed to exist until retention date
โก Quick Revision
VERSIONING
Upload same key โ new version created (old preserved)
Standard delete โ adds Delete Marker (data not gone)
Permanent delete โ must delete each version by Version ID
Each version = full copy, not delta โ watch storage costs
Fix: Lifecycle rule to expire non-current versions
SUSPEND VERSIONING
Cannot fully disable once enabled โ only suspend
New uploads after suspension โ null Version ID
Existing versions โ all preserved, untouched
Re-enable โ new uploads get UUIDs again
BUCKET TYPES
General Purpose = all features, multi-AZ, everyday use
Directory Bucket = single AZ, 10x faster, no versioning/lifecycle/lock
OLTP vs OLAP
OLTP โ transactions, fast R/W, RDS/Aurora/DynamoDB
OLAP โ analytics, large scans, Redshift/Athena
Separate them in architecture โ never run analytics on OLTP DB
STATIC HOSTING
S3 serves HTML/CSS/JS/images directly
Cannot run server-side code (Node, PHP, Python)
Must disable Block Public Access + add public read policy
Add CloudFront for HTTPS + custom domain in production
CORS
Bucket Policy = WHO can access (all clients)
CORS = WHICH BROWSER ORIGINS can access (browsers only)
Both must allow request for browser JS to work
Configure in bucket's Permissions โ Cross-origin resource sharing
OBJECT LOCK (WORM)
Must enable at bucket creation
Requires versioning (auto-enabled)
Governance = lock with admin bypass
Compliance = lock with NO bypass (not even root)
Retention Period = until specific date
Legal Hold = indefinite until removed
๐ผ Interview Questions
Q1: What happens when you delete an object in a versioned S3 bucket?
S3 does not delete the actual data. Instead, it adds a Delete Marker โ a special placeholder with its own Version ID. The object appears gone (GET returns 404), but all versions still exist and are still billed. To permanently delete, you must explicitly delete each version by its Version ID and remove the delete marker.
Q2: Does S3 versioning use delta/incremental storage like git?
No. Each version is stored as a complete, independent object with its own Version ID. Uploading a 10 MB file 10 times creates 100 MB of stored data, not 10 MB plus incremental diffs. This makes Lifecycle rules to expire non-current versions essential for cost control.
Q3: What is the difference between Governance Mode and Compliance Mode in S3 Object Lock?
Both prevent object modification and deletion. Governance Mode allows authorized IAM users with the bypass permission to override the lock โ useful for internal policies where administrators need flexibility. Compliance Mode cannot be bypassed by anyone, including root user and AWS โ used for strict regulatory requirements where data immutability must be guaranteed.
Q4: When does S3 CORS apply and when does the bucket policy apply?
The bucket policy applies to all access โ CLI, SDK, curl, and browser โ and controls who is allowed to make requests. CORS applies only to browser-based JavaScript requests and controls which origins (domains) browsers are allowed to make requests from. Both must permit the request for a browser to successfully access S3.
Q5: What is the difference between a General Purpose and Directory Bucket?
General Purpose is the standard S3 bucket โ supports all features (versioning, lifecycle, object lock, all storage classes), data is replicated across multiple AZs, suitable for all workloads. Directory Bucket is purpose-built for high-performance single-AZ workloads โ up to 10x faster for small objects, but supports only Express One Zone storage class, no versioning, no lifecycle rules, no object lock.
Q6: Can you disable versioning after enabling it on a bucket?
No. Once versioning is enabled, it can only be suspended โ never fully disabled. Suspension stops new versions from being created (new uploads get null version ID) but all existing versions are permanently preserved. You can re-enable versioning at any time.
Q7: What is the difference between OLTP and OLAP? Give AWS examples.
OLTP handles real-time operational transactions โ short, fast read/write queries, high concurrency, current data. AWS: RDS, Aurora, DynamoDB. OLAP handles large-scale analytical queries across historical data โ complex aggregations, columnar storage, read-heavy. AWS: Redshift, Athena. They're always kept separate in architecture because analytical queries would overwhelm and destabilize a transactional database.
๐ฌ Practice Tasks
Versioning lab: Enable versioning on a bucket. Upload
test.txt. Upload a modified version with the same name. List all versions via CLI (aws s3api list-object-versions). Delete the object via Console. Confirm the delete marker was created. Restore the object by deleting the delete marker. Then permanently delete all versions.Lifecycle + Versioning: Create a bucket with versioning enabled. Add a Lifecycle rule to expire non-current versions after 7 days. Upload the same file 5 times. Verify all 5 versions appear. Wait (or check back after 7 days) to confirm old versions are auto-expired.
Static website: Create a bucket, disable Block Public Access, enable static website hosting, upload a simple
index.htmlanderror.html, add the public read bucket policy, and access the S3 website endpoint in your browser.CORS lab: Create a bucket with an image. Try to fetch it via JavaScript in your browser's console from a different origin โ observe the CORS error. Add a CORS rule allowing
*as origin. Retry and confirm it succeeds.Object Lock: Create a new bucket with Object Lock enabled (Governance Mode). Upload a file with a 1-day retention period. Try to delete it โ confirm it's blocked. Check what happens when you try to overwrite it.
Write the policy: Without notes, write a bucket policy that: (a) allows public GET on all objects, (b) denies all HTTP (non-HTTPS) requests, and (c) allows a specific IAM role to PUT objects.
AWS S3 Extended Concepts | Cloud + DevOps learning journey โ Systems Engineer โ Cloud/DevOps Engineer
Top comments (0)