Build a private S3 backup bucket from the CLI
📑 On this page
Part 80 of AWS from Zero. This S3 capstone assembles the small commands from Parts 11–79 into one private backup workflow.
What we are learning
A useful backup bucket needs more than an upload command: private access, ownership, encryption, version recovery, stale-upload cleanup, verification, and an explicit deletion plan.
Before you run it
REGION="ap-south-1"
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BUCKET="aws-zero-backup-$ACCOUNT_ID-$REGION"Review pricing and choose a unique bucket name. The example uses general purpose S3 and SSE-S3 to keep the first capstone focused.
Cost note: Versioning stores old copies, and backup growth must be monitored with lifecycle and cost controls.
The command
aws s3api create-bucket \
--bucket "$BUCKET" \
--region "$REGION" \
--create-bucket-configuration LocationConstraint="$REGION"
aws s3api put-bucket-ownership-controls \
--bucket "$BUCKET" \
--ownership-controls "Rules=[{ObjectOwnership=BucketOwnerEnforced}]"
aws s3api put-public-access-block \
--bucket "$BUCKET" \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-encryption \
--bucket "$BUCKET" \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
aws s3api put-bucket-versioning \
--bucket "$BUCKET" \
--versioning-configuration Status=Enabled
cat > backup-lifecycle.json <<'EOF'
{
"Rules": [{
"ID": "AbortStaleMultipartUploads",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7}
}]
}
EOF
aws s3api put-bucket-lifecycle-configuration \
--bucket "$BUCKET" \
--lifecycle-configuration file://backup-lifecycle.jsonThe bucket now has policy-based ownership, public-access guardrails, explicit encryption, version history, and stale multipart cleanup.
Inspect the result
aws s3api get-public-access-block --bucket "$BUCKET"
aws s3api get-bucket-versioning --bucket "$BUCKET"
aws s3api get-bucket-encryption --bucket "$BUCKET"
aws s3api get-bucket-ownership-controls --bucket "$BUCKET"
aws s3api get-bucket-lifecycle-configuration --bucket "$BUCKET"Treat every inspection as a deployment assertion. A backup is not ready merely because the bucket exists.
One tiny variation
aws s3 sync backup-source/ "s3://$BUCKET/backups/" \
--exclude "*.tmp" \
--checksum-mode ENABLED \
--dryrunPreview the first backup, then remove --dryrun and verify object counts, sizes, and a test restore.
Common mistake
A synchronized copy is not a complete backup strategy. Define retention, restore testing, credential isolation, monitoring, and protection from accidental or malicious deletion.
Cleanup
aws s3api list-object-versions \
--bucket "$BUCKET" \
--query "{Versions:Versions[].{Key:Key,VersionId:VersionId},Markers:DeleteMarkers[].{Key:Key,VersionId:VersionId}}"
# Permanently delete every listed version and marker before deleting the bucket.
rm backup-lifecycle.jsonVersioned buckets require version-aware cleanup. Do not run broad permanent deletion commands against a real backup bucket.
Next, we will learn Read your AWS caller identity deeply.