Ravindra BagaleCourses & study guides मराठी Track your progress

S3 Bucket Policy Project 3: Restrict Access to a VPC Endpoint

Fatima Khan runs payroll files in a private Mumbai VPC. Security forbids S3 over the public internet path. A gateway VPC endpoint plus a bucket policy Condition on aws:SourceVpce keeps objects reachable only from that VPC path.

What you'll learn in this chapter

  • Why sensitive S3 should prefer VPC endpoint paths
  • What aws:SourceVpce Deny-unless means line by line
  • How to create endpoint, apply policy, test inside vs outside
  • Endpoint policy AND bucket policy
  • Interview answers

1. Everyday project story

Bengaluru bank engineer Arjun Mehta and Toronto fintech lead Sophie Martin store KYC scans in S3. Only app subnets via vpce-xxxxxxxx should read them.

2. Why VPC-endpoint-only?

Why do we need this?

Even private EC2 can reach S3 via public AWS endpoints. A restrictive bucket policy forces the gateway endpoint path and blocks stolen keys used from the internet.

  • Gateway endpoint for S3 (no interface ENI hourly)
  • Route table prefix list to S3
  • Bucket Deny unless aws:SourceVpce matches
  • Optional endpoint policy least privilege

3. What is the policy?

What is it?

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnlessFromMyVpce",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::rb-payroll-ap-south-1",
        "arn:aws:s3:::rb-payroll-ap-south-1/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-0a1b2c3d4e5f67890"
        }
      }
    }
  ]
}

Line-by-line

  1. Effect Deny + StringNotEquals — deny if not from endpoint.
  2. Principal * — all callers including your IAM.
  3. Action s3:* — broad lock; IAM still must Allow needed actions.
  4. Resource bucket and bucket/* — List + object APIs.
  5. aws:SourceVpce = endpoint id vpce-...
  6. Deny does not grant; IAM Allow still required.

4. CLI with output

How to do it (step by step)

# Gateway endpoint
aws ec2 create-vpc-endpoint --vpc-id vpc-0123456789abcdef0 \
  --service-name com.amazonaws.ap-south-1.s3 \
  --route-table-ids rtb-aaa rtb-bbb --vpc-endpoint-type Gateway
# { "VpcEndpoint": { "VpcEndpointId": "vpce-0a1b2c3d4e5f67890", ... } }

aws s3api put-bucket-policy --bucket rb-payroll-ap-south-1 --policy file://vpce.json

5. Test allow and deny

# ALLOW — EC2 in VPC with endpoint route
aws s3 cp s3://rb-payroll-ap-south-1/payslip.pdf - --region ap-south-1 | wc -c
# >0

# DENY — laptop on internet, same IAM key
aws s3 cp s3://rb-payroll-ap-south-1/payslip.pdf /tmp/x --region ap-south-1
# An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

Both policies matter

VPC endpoint policy and bucket policy are both evaluated. An empty/deny endpoint policy blocks even if the bucket allows.

6. Multi-industry

Payroll (Mumbai — Fatima Khan), banking KYC (Bengaluru — Arjun Mehta), hospital records (Toronto — Sophie Martin), govt file share (Delhi — Kabir Singh).

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: SourceVpce lock

Do this in ap-south-1 (Mumbai) unless your org forbids it. Set a budget alert first.

How to do it (step by step)

  1. Create lab bucket + gateway endpoint on a private route table.
  2. Apply DenyUnlessFromMyVpce policy.
  3. From private EC2: GetObject succeeds.
  4. From internet laptop with same keys: AccessDenied.

Cleanup (stop billing)

  1. Delete bucket policy; delete endpoint; delete bucket.
  2. Remove lab routes if dedicated.

9. Common errors and fixes

Each row is a real mistake students and juniors hit. Read the fix before you panic.

Error / symptomFix
AccessDenied but IAM Allow looks fineFind explicit Deny in bucket policy or BPA blocking public.
Policy JSON rejected on putValidate with python3 -m json.tool; no smart quotes; use file://.
Policy Simulator Allow, CLI DenySimulator skips some layers; retest with real CLI/role/network.
Wrong Resource ARN shapeGetObject needs arn:...:bucket/* ; ListBucket needs bare bucket ARN.
Condition key typo or wrong caseKeys like aws:SourceIp are case-sensitive.
Missing Principal on bucket policyResource-based policies require Principal; identity policies must omit it.
Account-level BPA overrides bucketAccount Block Public Access can still block public grants.
Encrypted object / KMS forgottenSSE-KMS needs key policy + kms:Decrypt/GenerateDataKey.
Works nowhere after DenyWrong vpce id; or endpoint not on the RT used by the ENI.
Endpoint policy empty DenyAdd Allow in endpoint policy for your principals/actions.

10. Troubleshooting checklist

  1. Confirm region and endpoint hostname for the bucket.
  2. Print get-bucket-policy and get-public-access-block.
  3. Reproduce with a least-privilege lab IAM user.
  4. Binary-search Denies by commenting one Sid at a time in lab.
  5. Read CloudTrail errorCode and additionalEventData.
  6. If KMS involved, test key permissions separately.
  7. From VPC path: route to gateway prefix list + endpoint policy.
  8. Cleanup versioning/Object Lock labs carefully.
  9. Verify route to S3 prefix list on the instance.

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. Gateway vs Interface for S3?

Gateway is the usual cheap path for S3/DynamoDB.

Q. Same as SourceIp?

No — endpoint id vs client IP.

Q. AWS log services blocked?

May need carve-outs for CloudTrail/ALB.

Q. Does Deny replace IAM Allow?

No — Deny only blocks; IAM must still Allow.

12. Interview Q&A

Q. Force S3 via VPC endpoint how?

Bucket Condition aws:SourceVpce (often Deny if not equal) + endpoint on route tables.

Q. Stolen key from internet?

Should AccessDenied if SourceVpce required.

Q. Endpoint policy denies?

Request fails — both must allow.

Q. Find vpce id?

ec2 describe-vpc-endpoints.

Q. Interface endpoint when?

Special private DNS/hybrid cases; know cost.

Q. Deny-unless vs Allow-only?

Deny-unless stops other Allows from bypassing; design consciously.

13. Tips in English, Marathi and Hindi

Ravindra Bagale's Tip (EN)

Pair SourceVpce with private subnets when compliance demands no public S3 path.

Ravindra Bagale's Tip (MR)

Compliance: SourceVpce + private subnet.

Tip (HI)

Compliance में SourceVpce + private subnet रखें।

Try at home

  1. Inside-VPC allow and laptop deny; save errors.
  2. Typo the vpce id; confirm total deny; fix.
  3. Draw RT → prefix list → S3.

In short

  1. aws:SourceVpce locks to an endpoint.
  2. Deny-unless is common.
  3. Endpoint policy AND bucket policy.
  4. Test inside VPC and from internet.
  5. Carve out log services if needed.

14. Policy design checklist before you save

  1. Write the business rule in one sentence (who can do what from where).
  2. Choose Allow vs Deny-unless consciously; remember explicit Deny wins.
  3. List every Resource ARN shape you need (bucket vs bucket/*).
  4. Name every Condition key exactly (case-sensitive).
  5. Decide BPA settings before put-bucket-policy.
  6. Plan the allow test and the deny test with expected HTTP/CLI codes.
  7. Plan cleanup (versioning, Object Lock, KMS schedules).
  8. 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).

  1. Open IAM → Policy simulator → pick the user/role.
  2. Add action s3:GetObject / PutObject and the object ARN.
  3. If you use resource policies, include the bucket policy text where the tool allows.
  4. Note Allow/Deny; then run the matching CLI from the real path.
  5. 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

  1. Read the error code and the request ID. Save both.
  2. Confirm you are calling the right bucket and region.
  3. Check Block Public Access if the principal is * or a service that looks public.
  4. Decode the policy: is there an explicit Deny that matches? Deny wins.
  5. Check Condition keys: SecureTransport, SourceVpce, SourceIp, PrincipalOrgID, encryption headers.
  6. For KMS: does the key policy allow the caller? Bucket policy alone is not enough.
  7. For CloudFront: is OAC present and the distribution id matching?
  8. For VPC: are you really going through the endpoint (no public IP leak)?
  9. Simulate in IAM Policy Simulator, then re-test with CLI from the real path.
  10. 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

About this scenario

London Legal LLP is a law business in London. Oliver Hughes looks after its IT and cloud work. They count money in GBP and run their AWS resources in the eu-west-2 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 VPCe bucket policy

Why: Read fence.

What to do: Get bucket policy londonlegal-private.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Easy List private bucket

Why: Via endpoint.

What to do: List objects londonlegal-private.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Easy Outside VPC denied — 1

Why: Fence.

What to do: Enter 1 if internet path should AccessDenied with VPCe-only policy.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Route table needs prefix list — 1

Why: Gateway EP.

What to do: Enter 1 if S3 gateway endpoint needs route table association.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Head private bucket

Why: Exists.

What to do: Head bucket londonlegal-private.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Easy Get bucket location

Why: Region.

What to do: Get bucket location londonlegal-private.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Describe VPC endpoints

Why: Find vpce id.

What to do: Describe vpc endpoints.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Get object private

Why: In-VPC read.

What to do: Get object data.csv from londonlegal-private.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Allow GetObject account root path

Why: Baseline allow.

What to do: Allow s3:GetObject for arn:aws:iam::114543297314:root on arn:aws:s3:::londonlegal-private/*.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Medium SourceVpce JSON

Why: Condition value.

What to do: JSON aws:SourceVpce vpce-0abc123.

How:
  1. Start from the top-level keys the task names.
  2. Indent child keys with 2 spaces (no tabs).
  3. Fill in each property with the value from the task.
  4. Click Check answer. Key order does not matter.

Medium Endpoint policy also matters — 1

Why: Layers.

What to do: Enter 1 if VPC endpoint policy is evaluated too.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Medium SourceVpc ≠ SourceVpce — 1

Why: Different.

What to do: Enter 1 if aws:SourceVpc and aws:SourceVpce are different keys.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard Deny unless SourceVpce

Why: Endpoint only.

What to do: Deny s3:* when aws:SourceVpce is not vpce-0abc123 on arn:aws:s3:::londonlegal-private and objects.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Hard Resources bucket+objects JSON

Why: Both ARNs.

What to do: JSON Resource0 arn:aws:s3:::demo-private Resource1 arn:aws:s3:::demo-private/*.

How:
  1. Start from the top-level keys the task names.
  2. Indent child keys with 2 spaces (no tabs).
  3. Fill in each property with the value from the task.
  4. Click Check answer. Key order does not matter.

Hard Put object private

Why: In-VPC write.

What to do: Put object data.csv into londonlegal-private from ./data.csv.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Hard Delete private policy

Why: Cleanup.

What to do: Delete bucket policy londonlegal-private.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. 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.

Revision card: Restrict to VPC endpoint. Private data should not leave the VPC path to the public S3 endpoint. Deny s3:* unless aws:SourceVpce matches your gateway/interface endpoint id. Create endpoint → routes → bucket Deny-unless → test in-VPC allow / internet deny. Lucas Meyer ETL in private subnets reads S3 only via vpce-….
Revision card: Restrict to VPC endpoint · Download PNG · Open card page
Revision card: Endpoint policy layers. Bucket policy alone is not the whole story — endpoint policies apply too. Align both; fix routes to the S3 prefix list; confirm no NAT leak for the deny test. From bastion in VPC: allow. From laptop: deny. Ananya Iyer debugs missing route table association first.
Revision card: Endpoint policy layers · Download PNG · Open card page
Comparison: VPC endpoint path vs Public S3 endpoint via NAT. VPC endpoint path: aws:SourceVpce fence; no public egress needed for S3. Public S3 endpoint via NAT: Traffic exits NAT to public S3; SourceVpce Deny bites.
Comparison: VPC endpoint path vs Public S3 endpoint via NAT · Download PNG · Open card page
Comparison: S3 gateway endpoint vs S3 interface endpoint. S3 gateway endpoint: Prefix-list routes; no ENI charge pattern. S3 interface endpoint: ENIs + security groups; more control/cost.
Comparison: S3 gateway endpoint vs S3 interface endpoint · Download PNG · Open card page
Interview card: SourceVpce vs SourceVpc?. SourceVpce is the endpoint id; SourceVpc is the VPC id — different keys. Most S3 gateway designs use SourceVpce. vpce-0abc in StringEquals/NotEquals.
Interview card: SourceVpce vs SourceVpc? · Download PNG · Open card page
Interview card: Why allow-in-VPC still fails?. Missing route to the S3 gateway prefix list sends traffic to public path → Deny. Also check endpoint policy conflicts. Associate endpoint with private RT fixes it.
Interview card: Why allow-in-VPC still fails? · Download PNG · Open card page
Interview card: Why Deny-unless pattern?. Explicit Deny when SourceVpce ≠ yours blocks other Allows. List both bucket and object ARNs on the Deny Resource. Laptop aws s3 ls → AccessDenied.
Interview card: Why Deny-unless pattern? · Download PNG · Open card page
Interview card: Gateway or interface for S3?. Gateway endpoints are the common free private path for S3; interface is optional/advanced. Interface uses ENIs and security groups. Lab uses gateway endpoint + SourceVpce.
Interview card: Gateway or interface for S3? · Download PNG · Open card page

More cards: Ravi Sir's Cards.