Amazon S3 for beginners: a private bucket, one file and a link that expires
S3 stores files as objects in buckets. Today: what it is, when to skip it, and a CloudShell lab that creates a bucket in your account's own namespace, checks its default locks and shares one file with a five-minute link.
Amazon S3, in plain words
Amazon Simple Storage Service (S3) is object storage. You put files, called objects, into containers called buckets, and you find each object again by its key, which looks like a path such as notes/hello.txt. There are no disks to size or servers to run: you pay for what you store and for the requests you make.
New buckets start locked down. Since April 2023, S3 turns on Block Public Access and turns off access control lists for every new bucket, and since January 2023 every new object is encrypted at rest with S3-managed keys (SSE-S3) at no extra cost. Being private is the default; making something public takes deliberate work.
Bucket names used to be first come, first served across all of AWS. Since March 2026 you can create general purpose buckets in your account regional namespace instead: the name ends with your account ID, the Region and -an, and no other account can ever claim it. That is what today's lab uses.
Reach for it when
- You need somewhere durable to keep files your app or team reads and writes over HTTPS: uploads, exports, backups, logs or build outputs.
- You want a landing zone for a data lake or for documents that Athena, Glue or Amazon Bedrock Knowledge Bases will read later.
- You need to hand someone a single file for a short time without creating a user for them. A presigned URL does that.
Skip it when
- Your program needs a normal file system with in-place edits, file locks or many machines mounting the same folder. Look at Amazon EFS or FSx instead.
- You need fast lookups and updates of small records by ID. That is a database job, for example DynamoDB.
- You need the boot or data disk for one EC2 instance. That is Amazon EBS, which attaches to the instance like a drive.
The AI angle
Most AI work on AWS starts with files in S3. Bedrock Knowledge Bases can use an S3 bucket as the source of the documents you want a model to answer from, SageMaker AI reads training data from S3 and writes model artifacts back to it, and S3 Vectors adds a bucket type for storing and querying vector embeddings, with Bedrock integration. Learning the bucket, key and permission basics today pays off in every one of those.
Hands-on lab: Create a private bucket, upload a file and share it for five minutes
Create a bucket in your account regional namespace from AWS CloudShell, confirm the default protections, upload one small file, prove a plain link is refused, share it with a presigned URL, then delete everything.
Before you start
- An AWS account that you own and are allowed to experiment in. Don't use a work account without permission.
- Sign-in as an IAM user or role that can create, read and delete S3 buckets and objects (an administrator role in a personal sandbox account covers this).
- The AWS Management Console set to US East (N. Virginia),
us-east-1. The commands below use that Region.
Open CloudShell and set your variables
Choose the CloudShell icon in the console's top bar. These lines read your account ID from your current sign-in and build a bucket name in your account regional namespace: a prefix, then the account ID, the Region and
-an. Nothing is created yet. If CloudShell restarts during the lab, run this step again.REGION=us-east-1 ACCOUNT=$(aws sts get-caller-identity --query Account --output text) BUCKET="sandbox-lab-${ACCOUNT}-${REGION}-an" echo "$BUCKET"Create the bucket
The
--bucket-namespace account-regionaloption tells S3 to put the bucket in the part of the name space reserved for your account. Inus-east-1you don't pass aLocationConstraint; in any other Region you would add--create-bucket-configuration LocationConstraint=$REGION.aws s3api create-bucket --bucket "$BUCKET" \ --bucket-namespace account-regional --region "$REGION"Check the locks you got for free
Read the bucket's Block Public Access settings and its default encryption. You should see four
truevalues andAES256, which is SSE-S3. You didn't configure either of these.aws s3api get-public-access-block --bucket "$BUCKET" aws s3api get-bucket-encryption --bucket "$BUCKET" \ --query 'ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault.SSEAlgorithm' \ --output textUpload a file and look at it
Create a tiny text file, copy it into the bucket under the key
notes/hello.txt, list the bucket, and read the object's size and encryption from its metadata.echo "hello from my sandbox" > hello.txt aws s3 cp hello.txt "s3://$BUCKET/notes/hello.txt" aws s3 ls "s3://$BUCKET" --recursive aws s3api head-object --bucket "$BUCKET" --key notes/hello.txt \ --query '{Size:ContentLength,Encryption:ServerSideEncryption}'Prove it's private, then share it for five minutes
The first
curlasks for the object with no credentials and should print403. The presigned URL carries a signature made with your own credentials, so it works without any sign-in, but only for 300 seconds and only for this one object. Anyone holding the link during that window can download the file, which is why it is short. Nothing about the bucket becomes public.curl -s -o /dev/null -w '%{http_code}\n' "https://$BUCKET.s3.$REGION.amazonaws.com/notes/hello.txt" URL=$(aws s3 presign "s3://$BUCKET/notes/hello.txt" --expires-in 300 --region "$REGION") curl -s "$URL"
Check that it worked
Step 3 prints four true values and AES256. In step 5 the plain request prints 403 and the presigned request prints hello from my sandbox. Run the same curl -s "$URL" again after five minutes and S3 refuses it.
Clean up
Delete the object and the bucket in one command (--force empties the bucket first; it works here because versioning was never turned on), then remove the local file. The head-bucket check should end with an error mentioning 404 or Not Found, and the final listing should print nothing.
aws s3 rb "s3://$BUCKET" --force
rm -f hello.txt
aws s3api head-bucket --bucket "$BUCKET"
aws s3 ls | grep sandbox-labGotchas
- A bucket's name and Region can't be changed after you create it. Pick them with care, and note that the console adds the account regional suffix for you while the API and CLI expect the full name.
- A presigned URL can't outlive the credentials that signed it. Links made from CloudShell or any other role session stop working when that session's credentials expire, even if you asked for up to seven days.
aws s3 rb --forcedoes not delete old object versions. If you turn on versioning, delete every version and delete marker before the bucket will go away.- S3 checks Block Public Access at the account and bucket levels together and applies the stricter one, so a bucket-level change alone may not open anything. Leave it on unless you have a specific reason.
- News: since October 21, 2026, S3 server access logs can be delivered to Amazon CloudWatch Logs in every AWS Region, in addition to delivery into a bucket. CloudWatch Logs charges apply.