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

S3 Bucket Policy Project 5: Enforce HTTPS with aws:SecureTransport

Compliance lead Gauri Sawant in Pune must prove every S3 call uses TLS. A single Deny when aws:SecureTransport is false blocks HTTP. Students still get surprised because browsers silently upgrade — so you test with curl http://.

What you'll learn in this chapter

  • Why enforce HTTPS at the bucket
  • What aws:SecureTransport means line by line
  • How to test HTTP deny vs HTTPS allow with curl
  • TLS version vs SecureTransport
  • Interview answers

1. Everyday project story

Chennai hospital CIO Dr. Anil Krishnan and Frankfurt SaaS founder Jonas Becker both store customer uploads. Auditors ask: can anyone still speak plain HTTP to the bucket?

2. Why SecureTransport?

Why do we need this?

HTTP leaks credentials and data on the wire. Bucket policy can Deny any request where aws:SecureTransport is false — simple and effective.

  • One Deny statement covers all principals
  • Works with IAM users, roles, and anonymous
  • Does not by itself pin TLS 1.2+ — that is separate
  • Always prove with curl http not only a browser

3. What is the policy?

What is it?

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::rb-secure-uploads-ap-south-1",
        "arn:aws:s3:::rb-secure-uploads-ap-south-1/*"
      ],
      "Condition": {
        "Bool": { "aws:SecureTransport": "false" }
      }
    }
  ]
}

Line-by-line

  1. Sid DenyInsecureTransport — clear intent.
  2. Effect Deny — blocks matching requests.
  3. Principal * — everyone.
  4. Action s3:* — all S3 APIs.
  5. Resource bucket + /*.
  6. Bool aws:SecureTransport false — fires only on non-TLS.

4. CLI with output

How to do it (step by step)

aws s3api put-bucket-policy --bucket rb-secure-uploads-ap-south-1 --policy file://https-only.json
# (empty success)

echo secret > t.txt
aws s3 cp t.txt s3://rb-secure-uploads-ap-south-1/t.txt
# upload success over HTTPS CLI

5. Test allow and deny

# ALLOW — HTTPS
curl -s -o /dev/null -w "%{http_code}\n" -I \
  https://rb-secure-uploads-ap-south-1.s3.ap-south-1.amazonaws.com/t.txt
# 403 without public read is OK for private buckets; use signed HTTPS CLI for content:
aws s3 cp s3://rb-secure-uploads-ap-south-1/t.txt -   # works (HTTPS)

# DENY — force HTTP (note: may redirect; use --http1.1 and endpoint that speaks HTTP)
aws s3 cp s3://rb-secure-uploads-ap-south-1/t.txt /tmp/x --no-sign-request --endpoint-url http://s3.ap-south-1.amazonaws.com
# AccessDenied when policy sees SecureTransport=false

6. TLS version note

SecureTransport only means “was TLS used?”. Pinning TLS 1.2+ is done via CloudFront security policies, load balancer policies, or S3 TLS settings where available — not this bool alone.

7. Multi-industry

Healthcare uploads (Chennai — Dr. Anil Krishnan), SaaS (Frankfurt — Jonas Becker), fintech KYC (Pune — Gauri Sawant), edtech assignments (Indore — Kavita Joshi).

8. 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

9. Lab: HTTPS-only bucket

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; put DenyInsecureTransport.
  2. Upload with AWS CLI (HTTPS) — success.
  3. Attempt HTTP access; confirm Deny/AccessDenied.
  4. Show auditor the policy Sid and curl evidence.

Cleanup (stop billing)

  1. Delete policy and bucket.
  2. Remove lab objects first.

10. 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.
Browser still “works” on http URLSilent redirect to https — use curl -v http://.
Thought SecureTransport pins TLS1.2It does not — configure TLS policy elsewhere.

11. 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.

12. 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. Does this replace IAM?

No — still need Allow; this only Denies HTTP.

Q. Presigned HTTP URLs?

They fail under this Deny — generate https URLs.

Q. CloudFront origin protocol?

Use HTTPS only to origin when possible.

Q. Cost of this policy?

Negligible — standard bucket policy.

13. Interview Q&A

Q. Condition for HTTPS-only S3?

Deny when aws:SecureTransport is false.

Q. TLS 1.0 still possible?

SecureTransport may still be true; pin versions separately.

Q. How to demo for audit?

CLI HTTPS success + HTTP AccessDenied evidence.

Q. Principal * Deny safe?

Yes for this pattern — only matches non-TLS.

Q. Interaction with public website?

Website endpoint is HTTP — conflicts; use CloudFront HTTPS.

Q. Bool value type?

String "false" / "true" in JSON policy.

14. Tips in English, Marathi and Hindi

Ravindra Bagale's Tip (EN)

Always keep a SecureTransport Deny on buckets that hold credentials-adjacent data — it is cheap insurance.

Ravindra Bagale's Tip (MR)

Credentials-adjacent buckets वर SecureTransport Deny — स्वस्त insurance.

Tip (HI)

संवेदनशील bucket पर SecureTransport Deny सस्ता बीमा है।

Try at home

  1. Apply policy; capture HTTPS allow + HTTP deny.
  2. Explain SecureTransport vs TLS version aloud.
  3. Add this Sid to an existing lab policy JSON.

In short

  1. Deny when aws:SecureTransport is false.
  2. Test with curl/CLI HTTP — not only browsers.
  3. TLS version pinning is separate.
  4. Still need IAM Allows.
  5. Conflicts with raw S3 HTTP website endpoint.

15. 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.

16. 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.

17. 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

18. 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.

19. 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.

20. 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

Milan Furniture is a furniture business in Milan. Giulia Rossi looks after its IT and cloud work. They count money in EUR and run their AWS resources in the eu-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 HTTPS policy

Why: Read Deny HTTP.

What to do: Get bucket policy milanfurniture-tls.

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 TLS bucket

Why: Over HTTPS.

What to do: List objects milanfurniture-tls.

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 HTTP denied — 1

Why: Fence.

What to do: Enter 1 if HTTP requests should AccessDenied.

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 HTTPS allowed — 1

Why: Allow.

What to do: Enter 1 if HTTPS should succeed when otherwise allowed.

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 TLS bucket

Why: Exists.

What to do: Head bucket milanfurniture-tls.

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 BPA TLS

Why: BPA.

What to do: Get public access block milanfurniture-tls.

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 Put via HTTPS

Why: Allow path.

What to do: Put object note.txt into milanfurniture-tls from ./note.txt.

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 via HTTPS

Why: Allow read.

What to do: Get object note.txt from milanfurniture-tls.

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 account Get/Put

Why: Baseline.

What to do: Allow s3:GetObject and s3:PutObject for account root on milanfurniture-tls 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.

Medium SecureTransport false JSON

Why: Condition.

What to do: JSON aws:SecureTransport false.

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 Presign still needs TLS — 1

Why: Conditions bind.

What to do: Enter 1 if presigned HTTP URLs still hit SecureTransport Deny.

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 Condition type is Bool — 1

Why: Type.

What to do: Enter 1 if SecureTransport uses Bool condition.

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 Get encryption TLS

Why: SSE.

What to do: Get bucket encryption milanfurniture-tls.

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 Deny when SecureTransport false

Why: Force TLS.

What to do: Deny all s3 actions when aws:SecureTransport is false on milanfurniture-tls bucket 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 Prefer explicit Deny JSON

Why: Deny wins.

What to do: JSON prefer_explicit_deny true.

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 Delete TLS policy

Why: Cleanup.

What to do: Delete bucket policy milanfurniture-tls.

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: Enforce HTTPS. HTTP leaks tokens and bodies on the wire. Explicit Deny when aws:SecureTransport is false on bucket and object ARNs. Put Deny statement → HTTPS allow test → HTTP deny test. Priya Nair blocks http:// put-object in the clinic docs bucket.
Revision card: Enforce HTTPS · Download PNG · Open card page
Revision card: Why explicit Deny?. An Allow-if-true elsewhere can still permit HTTP unless Deny wins. Use Bool aws:SecureTransport false; pair with least-privilege Allows. Presigned http URLs also fail — conditions still bind. Sofia Alvarez demos AccessDenied on http endpoint.
Revision card: Why explicit Deny? · Download PNG · Open card page
Comparison: Explicit Deny insecure vs Allow only if SecureTransport true. Explicit Deny insecure: Deny wins against other Allows; closes holes. Allow only if SecureTransport true: Easy to bypass if another Allow exists.
Comparison: Explicit Deny insecure vs Allow only if SecureTransport true · Download PNG · Open card page
Comparison: HTTP request vs HTTPS request. HTTP request: Tokens and bodies exposed; SecureTransport false. HTTPS request: Encrypted in transit; SecureTransport true.
Comparison: HTTP request vs HTTPS request · Download PNG · Open card page
Interview card: How is SecureTransport expressed?. Bool condition aws:SecureTransport false on an explicit Deny for s3:*. Cover bucket and object ARNs. http put → AccessDenied.
Interview card: How is SecureTransport expressed? · Download PNG · Open card page
Interview card: Why not only Allow-if-true?. Other Allow statements can still permit HTTP; explicit Deny closes the hole. Defense against broad identity policies. Identity Allow * + resource Deny HTTP → still deny HTTP.
Interview card: Why not only Allow-if-true? · Download PNG · Open card page
Interview card: Do presigned URLs bypass TLS Deny?. No — conditions still apply to the signed request. Use https presigns only. http presign → AccessDenied.
Interview card: Do presigned URLs bypass TLS Deny? · Download PNG · Open card page
Interview card: CloudFront origin should use?. HTTPS to the S3 origin; pair with OAC. Avoid http origin “for debugging” in prod. Origin protocol policy HTTPS only.
Interview card: CloudFront origin should use? · Download PNG · Open card page

More cards: Ravi Sir's Cards.