TT Lab
Get started
Learn Learning paths Courses

Object Storage and S3

Working With Buckets and Objects Using the AWS CLI

Continue in TT Lab

Goal

Get hands-on with the basic operations of S3-compatible storage — profile, bucket, object upload, prefix, listing, ETag, copy, metadata — using the aws CLI, and feel for yourself that there are no directories in object storage.

Why it matters

Understanding the S3 API is not learning a particular vendor. AWS S3, SeaweedFS, Garage, Ceph RGW and MinIO all speak the same API, so this API is in effect a portability layer. This is why the migration cost on the application side was small when the MinIO community edition stopped distribution in 2025–2026 — if you just changed the endpoint and credentials, the code stayed largely the same. This lab environment went through the same thing. The server changed from MinIO to SeaweedFS's S3 gateway, but the commands you type here run on AWS without changing a single character. What to remember especially in this lab is the ETag in step 6. For a single-part upload, the ETag is the md5 of the content, so the client can verify on its own whether the upload was intact. When the next lab covers how the ETag of a multipart upload differs from this, the rule you see here is the starting point.

Steps

  1. With aws configure set, put four values into the profile local — aws_access_key_id, aws_secret_access_key, region and endpoint_url (http://127.0.0.1:9000). The credentials are in /opt/fixtures/s3/creds.env. aws --profile local s3 ls must finish without an error.
  2. Create the bucket lab-media. It must appear in the aws --profile local s3 ls list.
  3. Upload /opt/fixtures/s3/logo.png to s3://lab-media/img/logo.png.
  4. From /opt/fixtures/s3/, upload banner.png as img/banner.png, readme.txt as doc/readme.txt and sales.csv as doc/sales.csv.
  5. Save the output of aws --profile local s3 ls --recursive s3://lab-media to /root/s3/list.txt. It must be exactly 4 lines.
  6. In /root/s3/etag.txt, write two lines, etag=<값> and md5=<값> (each with the actual value in place of the placeholder). The ETag of logo.png (with the quotes removed) and the md5 of the local file must be the same.
  7. Server-side copy doc/readme.txt to doc/README.txt and then delete the original. aws --profile local s3 ls s3://lab-media/doc/ must show only README.txt and not readme.txt.
  8. Upload sales.csv again with the Content-Type text/csv. In the output of aws --profile local s3api head-object --bucket lab-media --key doc/sales.csv, the ContentType must be text/csv.

Notes

Set up an S3 profile

With aws configure set, put four values into the profile local — aws_access_key_id, aws_secret_access_key, region and endpoint_url (http://127.0.0.1:9000). The credentials are in /opt/fixtures/s3/creds.env. aws --profile local s3 ls must finish without an error.

You bundle the endpoint and credentials into one profile. The credentials are in /opt/fixtures/s3/creds.env, and if you leave out endpoint_url, the CLI tries to go out to the real AWS.

Create a bucket

Create the bucket lab-media. It must appear in the aws --profile local s3 ls list.

Bucket names follow DNS rules — only lowercase letters, digits and hyphens are allowed.

Upload one object

Upload /opt/fixtures/s3/logo.png to s3://lab-media/img/logo.png.

Specify the local path and the destination key together. The slash in the destination key is part of the name, not a folder.

Organize with prefixes

From /opt/fixtures/s3/, upload banner.png as img/banner.png, readme.txt as doc/readme.txt and sales.csv as doc/sales.csv.

Upload them split under img/ and doc/. In reality no folders are created; the key names just come out that way.

Pull a recursive listing

Save the output of aws --profile local s3 ls --recursive s3://lab-media to /root/s3/list.txt. It must be exactly 4 lines.

The default listing shows things folded by prefix. There is an option that expands everything.

Compare the ETag with a local hash

In /root/s3/etag.txt, write two lines, etag=<값> and md5=<값> (each with the actual value in place of the placeholder). The ETag of logo.png (with the quotes removed) and the md5 of the local file must be the same.

The ETag of a single-part upload is the md5 of the content. Write the two values side by side and compare them.

Delete the original after a server-side copy

Server-side copy doc/readme.txt to doc/README.txt and then delete the original. aws --profile local s3 ls s3://lab-media/doc/ must show only README.txt and not readme.txt.

There is no rename. Copying and deleting is the rename. Make sure it is handled on the server without downloading.

Upload with a Content-Type and check it

Upload sales.csv again with the Content-Type text/csv. In the output of aws --profile local s3api head-object --bucket lab-media --key doc/sales.csv, the ContentType must be text/csv.

It is sometimes guessed from the extension, but it is safer to state it explicitly. Look up the object's metadata to confirm.