04 · S3 Storage¶
S3 (Simple Storage Service) is object storage: you store arbitrary files ("objects") inside named containers ("buckets"), addressed by key, with effectively unlimited capacity and 11-nines durability. It's the backbone of an enormous number of AWS architectures — static websites, data lakes, backups, Lambda deployment packages, and the frontend of the capstone project at the end of this level. This module covers buckets, objects, versioning, bucket policies, and hosting a static website.
Buckets and objects¶
A bucket is a globally-unique-named container; an object is a file
plus metadata, stored under a key (its full path-like name within the
bucket, e.g. images/logo.png).
# Bucket names must be globally unique across ALL of AWS, not just your account
aws s3 mb s3://yourname-training-bucket-2026 --region us-east-1
# Upload a file
echo "hello from s3" > hello.txt
aws s3 cp hello.txt s3://yourname-training-bucket-2026/hello.txt
# List objects in a bucket
aws s3 ls s3://yourname-training-bucket-2026/
# Download an object
aws s3 cp s3://yourname-training-bucket-2026/hello.txt downloaded.txt
# Sync a whole local directory to S3 (only uploads changed/new files)
aws s3 sync ./site/ s3://yourname-training-bucket-2026/site/
# Delete an object
aws s3 rm s3://yourname-training-bucket-2026/hello.txt
aws s3 is a high-level, S3-specific command set (cp, sync, mb, rb,
ls, rm). There's also a lower-level aws s3api for operations like bucket
policies and versioning configuration that don't have a friendly aws s3
equivalent.
Object versioning¶
Versioning keeps every version of an object instead of overwriting it — protects against accidental deletes/overwrites, at the cost of storing every version (which counts toward billing).
aws s3api put-bucket-versioning \
--bucket yourname-training-bucket-2026 \
--versioning-configuration Status=Enabled
# Overwrite the same key twice
echo "version 1" | aws s3 cp - s3://yourname-training-bucket-2026/notes.txt
echo "version 2" | aws s3 cp - s3://yourname-training-bucket-2026/notes.txt
# List every version that now exists for that key
aws s3api list-object-versions \
--bucket yourname-training-bucket-2026 \
--prefix notes.txt \
--query "Versions[].[Key,VersionId,IsLatest]" --output table
# Fetch a specific (non-latest) version
aws s3api get-object \
--bucket yourname-training-bucket-2026 \
--key notes.txt \
--version-id "<VersionId from above>" \
restored-notes.txt
A "deleted" object in a versioned bucket isn't gone — S3 just adds a delete marker on top; the prior versions are still retrievable until you explicitly delete them by version ID.
Bucket policies¶
A bucket policy is a resource-based policy (JSON, same shape as IAM policies) attached directly to the bucket, controlling who can access it — useful when you want to grant access without touching IAM at all (e.g. public read for a static website).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForWebsite",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::yourname-training-bucket-2026/*"
}
]
}
# S3 blocks public bucket policies by default (a safety net) — you must
# explicitly opt out of the relevant block before a public policy takes effect
aws s3api put-public-access-block \
--bucket yourname-training-bucket-2026 \
--public-access-block-configuration \
BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false
aws s3api put-bucket-policy \
--bucket yourname-training-bucket-2026 \
--policy file://public-read-policy.json
Only make a bucket public on purpose
RestrictPublicBuckets/BlockPublicPolicy exist because accidentally
public buckets are one of the most common real-world data leaks. Only
disable the block for buckets that are genuinely meant to serve public
content, like a static website's assets — never for buckets holding
anything sensitive.
Static website hosting¶
S3 can serve a bucket's contents directly as a website (no server needed) — this is exactly the frontend pattern used in this level's capstone project.
aws s3api put-bucket-website \
--bucket yourname-training-bucket-2026 \
--website-configuration '{
"IndexDocument": {"Suffix": "index.html"},
"ErrorDocument": {"Key": "error.html"}
}'
echo "<h1>Hello from S3 static hosting</h1>" > index.html
echo "<h1>404 - Not Found</h1>" > error.html
aws s3 cp index.html s3://yourname-training-bucket-2026/
aws s3 cp error.html s3://yourname-training-bucket-2026/
# The website endpoint URL follows a fixed pattern per region:
echo "http://yourname-training-bucket-2026.s3-website-us-east-1.amazonaws.com"
Visit that URL — with the public-read bucket policy from above in place, your page loads with no web server, no EC2 instance, and no ongoing compute cost.
Storage classes (brief overview)¶
| Class | Use case | Relative cost |
|---|---|---|
STANDARD |
Frequently accessed data (default) | Baseline |
STANDARD_IA |
Infrequent access, still needs millisecond retrieval | Lower storage, retrieval fee |
GLACIER |
Long-term archive, retrieval takes minutes–hours | Much lower storage cost |
For this course, STANDARD (the default) is fine — storage classes matter
more once you're optimizing costs at scale (Level 4 covers this).
Cheat sheet¶
| Command | Purpose |
|---|---|
aws s3 mb s3://NAME |
Create a bucket. |
aws s3 cp FILE s3://BUCKET/KEY |
Upload/download an object. |
aws s3 sync DIR s3://BUCKET/PREFIX |
Sync a local directory to/from S3. |
aws s3 ls s3://BUCKET/ |
List objects. |
aws s3 rm s3://BUCKET/KEY |
Delete an object. |
aws s3api put-bucket-versioning --bucket B --versioning-configuration Status=Enabled |
Turn on versioning. |
aws s3api list-object-versions --bucket B |
List all versions of all objects. |
aws s3api put-bucket-policy --bucket B --policy file://p.json |
Attach a bucket policy. |
aws s3api put-public-access-block ... |
Opt in/out of S3's public-access safety blocks. |
aws s3api put-bucket-website --bucket B --website-configuration '{...}' |
Enable static website hosting. |
How It Actually Works¶
S3 buckets aren't a filesystem — there is no directory tree on disk anywhere.
Every object is stored as an opaque blob in a massive, sharded key-value
index, addressed by the full key string (images/logo.png is one flat key,
not a traversal through folders); the Console's "folder" view is purely a
UI illusion built by splitting keys on /. This is why S3 can list a
million-object "folder" instantly regardless of nesting depth, and why
renaming a folder is actually a full copy-then-delete of every object under
that prefix, not a cheap metadata rename.
Historically S3 was the textbook example of eventual consistency: a
PUT followed immediately by a GET of the same key could, in the old
model, return stale data because the object had to propagate across multiple
storage nodes for durability before being uniformly visible. Since December
2020, S3 provides strong read-after-write consistency for all operations
(including overwrites and deletes) — but the underlying mechanism didn't
change from "eventually replicate to 11-nines durability across at least
three Availability Zones"; what changed is that reads are now routed through
a consistency-checking layer that won't serve a response until it can
guarantee it reflects the latest committed write, even while replication to
all copies is still catching up in the background.
Versioning works by never overwriting a key's data at all: internally, each
key maps to a chain of immutable version objects plus a pointer to "current."
A PUT to an existing key allocates a brand-new object and version ID and
moves the pointer; a "delete" on a versioned bucket just writes a
zero-byte delete-marker version on top of the chain — the storage bytes for
every prior version remain fully allocated (and billed) until you issue a
version-specific delete.
Exercise¶
- Create a bucket with a globally-unique name of your choosing.
- Enable versioning, upload the same key three times with different
content, and use
list-object-versionsto view the history. - Enable static website hosting with a simple
index.html, disable the relevant public-access blocks, and attach a bucket policy granting publics3:GetObject. - Visit the website endpoint URL in a browser and confirm your page loads.
- Clean up: delete all object versions (not just the latest) and the bucket
itself —
aws s3 rb s3://BUCKET --forceonly removes current versions, so for a versioned bucket you may need to delete each version ID explicitly first viaaws s3api delete-object --version-id.