S3 Bucket Policy Project 8: Per-User Home Folders with ${aws:username}
Shared team bucket for IAM users: each person only sees home/${aws:username}/*. Policy variables make one policy serve many users — until someone assumes a role and username is empty. This project shows the happy path and the role pitfall.
What you'll learn in this chapter
- Why home-folder prefixes beat per-user buckets
- What ${aws:username} looks like in Resource/Condition
- How to test as two users: allow own, deny other
- Role session pitfall and alternatives
- Interview answers
1. Everyday project story
Nashik college lab admin Prof. Sunil Pawar and Austin bootcamp mentor Alicia Gomez give every student an IAM user. One bucket, many homes.
2. Why per-user prefixes?
Why do we need this?
One bucket is cheaper to manage than hundreds. Policy variables bind the caller identity into the Resource path.
- IAM users with username set
- Resource home/${aws:username}/*
- ListBucket limited by prefix condition
- Roles need ${aws:userid} or session tags instead
3. What is the policy?
What is it?
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "HomeList",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::rb-student-homes-ap-south-1",
"Condition": {
"StringLike": { "s3:prefix": ["home/${aws:username}/*", "home/${aws:username}"] }
}
},
{
"Sid": "HomeRW",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::rb-student-homes-ap-south-1/home/${aws:username}/*"
}
]
}
Line-by-line
- Principal account root here means “identities in this account evaluated with their IAM” — still pair with identity policies; many designs put this only in IAM user policies instead.
- ListBucket with s3:prefix home/username — cannot list others.
- Get/Put/Delete only under home/${aws:username}/*.
- ${aws:username} expands for IAM users.
- Assumed roles: username empty — use userid/tags.
- Prefer putting these statements in IAM identity policies for users; bucket policy shown for teaching resource-side variables.
Teaching note
In production, home-folder rules are often in IAM user policies (no Principal). Showing them on a bucket policy teaches the same variables. For roles, switch to ${aws:PrincipalTag/home} or ${aws:userid}.
4. CLI with output
How to do it (step by step)
# As user ananya
aws s3 cp notes.txt s3://rb-student-homes-ap-south-1/home/ananya/notes.txt --profile ananya
# upload success
aws s3 ls s3://rb-student-homes-ap-south-1/home/ananya/ --profile ananya
# notes.txt
5. Test allow and deny
# ALLOW — own prefix
aws s3 cp s3://rb-student-homes-ap-south-1/home/ananya/notes.txt - --profile ananya
# <file contents>
# DENY — peer prefix
aws s3 cp s3://rb-student-homes-ap-south-1/home/rohan/secret.txt - --profile ananya
# AccessDenied
6. Multi-industry
College labs (Nashik — Prof. Sunil Pawar), bootcamps (Austin — Alicia Gomez), agency freelancers (Goa — Ira Fernandes), enterprise desktop sync (Seoul — Min-jun Park).
7. AccessDenied debugging and Policy Simulator
When S3 returns AccessDenied, check in order: (1) Block Public Access, (2) matching bucket policy Deny, (3) missing IAM Allow, (4) KMS key policy, (5) VPC endpoint policy, (6) legacy ACL. IAM Policy Simulator can miss BPA/VPC/KMS — always re-test with real CLI from the real network path.
# Decode
aws s3api get-bucket-policy --bucket BUCKET --query Policy --output text | python3 -m json.tool
aws s3api get-public-access-block --bucket BUCKET
aws iam simulate-principal-policy --policy-source-arn ARN \
--action-names s3:GetObject --resource-arns arn:aws:s3:::BUCKET/key.txt
aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=GetObject --max-items 5
8. Lab: two-user homes
Do this in ap-south-1 (Mumbai) unless your org forbids it. Set a budget alert first.
How to do it (step by step)
- Create users ananya and rohan; attach home-folder IAM policy (recommended) or bucket policy variables.
- Each uploads to home/
/. - Cross-read peer home → AccessDenied.
- Assume a role without username; observe failure; fix with tags.
Cleanup (stop billing)
- Delete objects; delete users; delete bucket/policy.
- Remove lab groups.
9. Common errors and fixes
Each row is a real mistake students and juniors hit. Read the fix before you panic.
| Error / symptom | Fix |
|---|---|
| AccessDenied but IAM Allow looks fine | Find explicit Deny in bucket policy or BPA blocking public. |
| Policy JSON rejected on put | Validate with python3 -m json.tool; no smart quotes; use file://. |
| Policy Simulator Allow, CLI Deny | Simulator skips some layers; retest with real CLI/role/network. |
| Wrong Resource ARN shape | GetObject needs arn:...:bucket/* ; ListBucket needs bare bucket ARN. |
| Condition key typo or wrong case | Keys like aws:SourceIp are case-sensitive. |
| Missing Principal on bucket policy | Resource-based policies require Principal; identity policies must omit it. |
| Account-level BPA overrides bucket | Account Block Public Access can still block public grants. |
| Encrypted object / KMS forgotten | SSE-KMS needs key policy + kms:Decrypt/GenerateDataKey. |
| Role AccessDenied on home path | ${aws:username} empty for assumed roles. |
| List shows nothing | Missing ListBucket + prefix condition. |
10. Troubleshooting checklist
- Confirm region and endpoint hostname for the bucket.
- Print get-bucket-policy and get-public-access-block.
- Reproduce with a least-privilege lab IAM user.
- Binary-search Denies by commenting one Sid at a time in lab.
- Read CloudTrail errorCode and additionalEventData.
- If KMS involved, test key permissions separately.
- From VPC path: route to gateway prefix list + endpoint policy.
- Cleanup versioning/Object Lock labs carefully.
11. FAQ
Q. Is a bucket policy the same as an IAM policy?
No. Bucket policy is resource-based on the bucket; IAM is identity-based. For same-account, either can Allow; explicit Deny wins; cross-account needs both.
Q. Do I still need ACLs in 2026?
Prefer Bucket owner enforced (ACLs off) + bucket policy. Some log deliveries still need canned ACL on Put.
Q. What is Block Public Access?
Switches that block public ACLs/policies at account or bucket. Disable only the minimum for a deliberate public design.
Q. How do you debug AccessDenied fast?
BPA → bucket policy → IAM → KMS → VPCe → CloudTrail. Never “fix” with Action *.
Q. IAM policy vs bucket policy for homes?
Usually IAM identity policy; variables work in both.
Q. Federated users?
Prefer session tags for home prefix.
Q. Can admin see all?
Separate admin policy without prefix limit.
Q. DeleteObject on peer?
Denied by Resource path.
12. Interview Q&A
Q. What does ${aws:username} do?
Substitutes the IAM user name into the policy at evaluation.
Q. Why roles break this?
Assumed-role sessions do not have aws:username.
Q. Alternative keys?
aws:userid, aws:PrincipalTag/*, aws:userid with role unique id.
Q. Prove isolation?
User A reads A OK; A reads B AccessDenied.
Q. ListBucket without prefix condition risk?
Users can discover others keys.
Q. One bucket or many?
One bucket + prefixes is common for labs.
13. Tips in English, Marathi and Hindi
Ravindra Bagale's Tip (EN)
Never copy-paste username home policies onto role-based apps without rewriting the variable.
Ravindra Bagale's Tip (MR)
Role-based app वर username policy copy-paste करू नका — variable बदला.
Tip (HI)
Role-based ऐप पर username वाली policy कॉपी न करें — variable बदलें।
Try at home
- Two profiles: allow own, deny peer; save output.
- Try with an assumed role; note the error; write a tag-based fix.
- Draw home/ tree for 5 users.
In short
- home/${aws:username}/* isolates IAM users.
- ListBucket needs matching prefix condition.
- Roles need different variables.
- Test with two real users.
- Production often uses IAM identity policies.
14. Policy design checklist before you save
- Write the business rule in one sentence (who can do what from where).
- Choose Allow vs Deny-unless consciously; remember explicit Deny wins.
- List every Resource ARN shape you need (bucket vs bucket/*).
- Name every Condition key exactly (case-sensitive).
- Decide BPA settings before put-bucket-policy.
- Plan the allow test and the deny test with expected HTTP/CLI codes.
- Plan cleanup (versioning, Object Lock, KMS schedules).
- Paste JSON through python3 -m json.tool before apply.
15. Policy Simulator walkthrough
IAM Policy Simulator is great for identity policies and a first pass on resource policies, but it can miss Block Public Access, VPC endpoint policies, and some KMS denials. Use it to catch typos, then always re-test with AWS CLI from the real network path (office IP, VPC, or CloudFront).
- Open IAM → Policy simulator → pick the user/role.
- Add action s3:GetObject / PutObject and the object ARN.
- If you use resource policies, include the bucket policy text where the tool allows.
- Note Allow/Deny; then run the matching CLI from the real path.
- If Simulator Allow but CLI Deny, check BPA, VPCe, KMS, and explicit Denies next.
16. Copy-paste runbook (print this)
# 0) Region + names
export AWS_REGION=ap-south-1
export BUCKET=rb-lab-$(date +%s)-ap-south-1
# 1) Create + show BPA
aws s3api create-bucket --bucket $BUCKET --region $AWS_REGION \
--create-bucket-configuration LocationConstraint=$AWS_REGION
aws s3api get-public-access-block --bucket $BUCKET || true
# 2) Validate + apply policy
python3 -m json.tool policy.json >/dev/null
aws s3api put-bucket-policy --bucket $BUCKET --policy file://policy.json
aws s3api get-bucket-policy --bucket $BUCKET --query Policy --output text | python3 -m json.tool | head
# 3) Allow test + Deny test (fill per project)
# ... project-specific curls / aws s3 cp ...
# 4) Cleanup
aws s3 rm s3://$BUCKET --recursive || true
aws s3api delete-bucket-policy --bucket $BUCKET || true
aws s3api delete-bucket --bucket $BUCKET
17. Industry story bank (reuse the pattern)
Each project above uses one industry story. Use the same policy pattern in these other industries without rewriting the JSON from scratch — only change the bucket name, principal, and Condition values.
- Healthcare (Priya Nair, Apollo-style clinic): patient PDFs — prefer SSE-KMS + OrgID + MFA delete.
- Fintech (Arjun Mehta, UPI wallet): statements — office IP + SecureTransport + CloudFront OAC for the customer portal.
- EdTech (Sofia Alvarez, online course): course videos — CloudFront OAC only; never public ACLs.
- Logistics (Kenji Watanabe, fleet app): GPS dumps — VPC endpoint only from the private subnet runners.
- Media (Fatima Khan, newsroom): raw footage — Object Lock COMPLIANCE + deny delete.
- Retail (Lucas Meyer, D2C brand): product images — public read for /images/* only; deny everything else.
- SaaS (Ananya Iyer, B2B CRM): tenant exports — ${aws:username} or ${aws:PrincipalTag/tenant} prefixes.
- Government (Rahul Deshmukh, state portal): RTI archives — OrgID + MFA + Object Lock.
18. AccessDenied debugging flowchart
- Read the error code and the request ID. Save both.
- Confirm you are calling the right bucket and region.
- Check Block Public Access if the principal is * or a service that looks public.
- Decode the policy: is there an explicit Deny that matches? Deny wins.
- Check Condition keys: SecureTransport, SourceVpce, SourceIp, PrincipalOrgID, encryption headers.
- For KMS: does the key policy allow the caller? Bucket policy alone is not enough.
- For CloudFront: is OAC present and the distribution id matching?
- For VPC: are you really going through the endpoint (no public IP leak)?
- Simulate in IAM Policy Simulator, then re-test with CLI from the real path.
- Only then open a support case with the request id and a redacted policy.
19. What good looks like in a PR review
- Policy JSON validates and is indented.
- Every Statement has Sid, Effect, Action, Resource.
- No Principal:* with write actions unless BPA and a Deny fence exist.
- Allow test and Deny test are documented with expected output.
- Cleanup steps will not strand Object Lock or KMS keys.
Practice Tasks
Shivneri Schools is a education business in Junnar. Kavita Shinde looks after its IT and cloud work. They count money in INR and run their AWS resources in the ap-south-1 Region. In the tasks below you do real jobs for them using what this lesson teaches. All names, account IDs, IP addresses and numbers are made up for practice.
0 / 16
Easy Get homes policy
Why: Read prefix rules.
What to do: Get bucket policy shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Easy List with prefix
Why: Folder UX.
What to do: List objects shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Easy Alice cannot read Bob — 1
Why: Homes.
What to do: Enter 1 if Alice should not read Bob home prefix.
- Write down the numbers the task gives you.
- Work it out step by step on paper.
- Type only the final answer in the box.
- Click Check answer.
Easy ${aws:username} is a policy variable — 1
Why: Var.
What to do: Enter 1 if ${aws:username} is substituted per caller.
- Write down the numbers the task gives you.
- Work it out step by step on paper.
- Type only the final answer in the box.
- Click Check answer.
Easy Head homes bucket
Why: Exists.
What to do: Head bucket shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Easy Get BPA homes
Why: BPA.
What to do: Get public access block shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Medium Put into home prefix
Why: User upload.
What to do: Put object home/alice/notes.txt into shivnerischool-homes from ./notes.txt.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Medium Get home object
Why: User read.
What to do: Get object home/alice/notes.txt from shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Medium Allow ListBucket with prefix condition
Why: List own home.
What to do: Allow s3:ListBucket on shivnerischool-homes when s3:prefix is home/${aws:username}/.
- Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
- In each statement write Effect, Action and Resource.
- Give only what the task needs (least privilege).
- Use double quotes and commas correctly. Click Check answer.
Medium username variable JSON
Why: Policy var.
What to do: JSON example_key home/${aws:username}/file.txt.
- Start from the top-level keys the task names.
- Indent child keys with 2 spaces (no tabs).
- Fill in each property with the value from the task.
- Click Check answer. Key order does not matter.
Medium Avoid s3:* on /* for all users — 1
Why: LP.
What to do: Enter 1 if granting s3:* on bucket/* to everyone breaks isolation.
- Write down the numbers the task gives you.
- Work it out step by step on paper.
- Type only the final answer in the box.
- Click Check answer.
Medium Identity + resource policies both apply — 1
Why: Eval.
What to do: Enter 1 if identity and bucket policies are both evaluated.
- Write down the numbers the task gives you.
- Work it out step by step on paper.
- Type only the final answer in the box.
- Click Check answer.
Medium Get homes versioning
Why: State.
What to do: Get bucket versioning shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Hard Allow object access by username
Why: Home objects.
What to do: Allow s3:GetObject and s3:PutObject on arn:aws:s3:::shivnerischool-homes/home/${aws:username}/*.
- Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
- In each statement write Effect, Action and Resource.
- Give only what the task needs (least privilege).
- Use double quotes and commas correctly. Click Check answer.
Hard Federated note JSON
Why: userid tags.
What to do: JSON prefer_principal_tag_for_federation true.
- Start from the top-level keys the task names.
- Indent child keys with 2 spaces (no tabs).
- Fill in each property with the value from the task.
- Click Check answer. Key order does not matter.
Hard Delete homes policy
Why: Cleanup.
What to do: Delete bucket policy shivnerischool-homes.
- Read the task and decide which AWS service it is about.
- Write aws, then the service name, then the operation (the action word).
- Add each needed flag (--name) followed by its value from the task.
- Flags can be in any order. Click Check answer.
Revision, interview and comparison cards
Revise this lesson in a few minutes. Save the cards on your phone or download them as PNG files. The QR code on each card opens this lesson.








More cards: Ravi Sir's Cards.