🏫 The School›🪪 IAM›⚖️ धडा 04 — AWS कसा निर्णय घेतो: deny, allow, deny जिंकतो
🖼️ See the drawing + lab 🏠 Course home 🌿 Branch on GitHub ✏️ View source
🖼️ आकृती आणि labThe drawing + lab पूर्ण पानावर उघडा ↗Open full page ↗

⚖️ धडा 04 — AWS कसा निर्णय घेतो: deny, allow, deny जिंकतो

📍 तुम्ही इथे आहात: 12 पैकी धडा 04 · मागे: lesson-03-policies · पुढे: lesson-05-roles-sts


📦 या ब्रँचमध्ये काय आहे

धडे 01–03, आणि त्यासोबत policy evaluation logic: सुरुवात deny पासून, Allow दार उघडते, आणि बाकी कोणीही काहीही म्हणो, स्पष्ट Deny ते बंद करतो. iam/evaluate.py मधला decide() हे पायरी-पायरीने करतो, आणि iam/demo.py मधला decide_() ते दाखवतो.

🧒 5 वर्षांच्या मुलाला समजावल्यासारखे

ओळखपत्र कार्यालयातली कारकून तीन नियम पाळते, नेहमी याच क्रमाने:

  1. "नाही" पासून सुरुवात. प्रत्येक उत्तर नाही म्हणूनच सुरू होते.
  2. "नाही, कधीच नाही" कार्ड शोधा. कुठेही कोणतेही कार्ड यासाठी "Deny" म्हणत असेल — थांबा. उत्तर नाही, जरी principal कडे "तुम्ही सगळे करू शकता" असे कार्ड असले तरी.
  3. "हो" कार्ड शोधा. एखादे जुळले तर उत्तर हो. एकही जुळले नाही तर ते नाही च राहते.

म्हणून "सगळे करू शकते" कार्ड असलेली कतरिनासुद्धा, "reports कधीच delete होत नाहीत" हे कार्ड लावले गेल्यावर शाळेचा report फेकून देऊ शकत नाही. गठ्ठ्यातल्या कार्डांचा क्रम महत्त्वाचा नाही — "कधीच नाही" नेहमी जिंकते.

🗺️ आकृती

flowchart LR
    req["📨 request<br/>katrina · s3:DeleteObject · school-reports/term1.pdf"]
    d{"explicit Deny<br/>in any policy?"}
    a{"an Allow<br/>matches?"}
    req --> d
    d -->|"1 yes"| deny["⛔ DENY<br/>nothing overrides it"]
    d -->|"no"| a
    a -->|"2 yes"| allow["✅ ALLOW"]
    a -->|"3 no"| imp["🚫 IMPLICIT DENY<br/>the default"]

🗺️ काढलेली आकृती + एक lab: https://school-edh.pages.dev/iam/lesson-diagrams.html#l04

❓ काय

🤔 का

कारण "मला नकार का मिळाला?" हा IAM मधला सगळ्यात नेहमीचा प्रश्न आहे, आणि त्याचे उत्तर नेहमी दोनपैकी एक असते: कुठेतरी स्पष्ट Deny (तो शोधा) किंवा कुठेच Allow नाही (नेमकेपणाने एक जोडा). कोणते ते ओळखले तर तास वाचतात.

🔧 कसे (या repo मध्ये)

decide() आधी प्रत्येक policy group मध्ये जुळणारा Deny शोधतो (पायरी 1), मग allow करायलाच हवे असे थर तपासतो, आणि मग identity policies. _scan() त्याला भेटलेला पहिला Deny परत देतो, किंवा Allow चे लेबल. कारण सांगणारी string निर्णय देणाऱ्या policy चे आणि Sid चे नाव सांगते — admin#Everything, deny-delete-reports#NeverDeleteReports.

🧪 करून पाहा

python3 iam/demo.py decide
python3 - <<'EOF'
import sys; sys.path.insert(0, "iam"); from evaluate import decide, load
katrina, R = "arn:aws:iam::111122223333:user/katrina", "arn:aws:s3:::school-reports/term1.pdf"
a, d = ("admin", load("admin")), ("deny-delete-reports", load("deny-delete-reports"))
print("admin, deny          ", decide(katrina, "s3:DeleteObject", R, identity=[a, d])[0])
print("deny, admin          ", decide(katrina, "s3:DeleteObject", R, identity=[d, a])[0])
print("other bucket         ", decide(katrina, "s3:DeleteObject", "arn:aws:s3:::school-homework/katrina/x", identity=[a, d])[0])
print("deny alone, GetObject", decide(katrina, "s3:GetObject", R, identity=[d])[0])
EOF

खऱ्या account वर (AWS CLI आणि credentials लागतात) — खरा पंच. पहिला call user ला प्रत्यक्ष जोडलेल्या policies तपासतो; दुसरा policy files जोडण्याआधीच तपासतो:

aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::111122223333:user/katrina --action-names s3:DeleteObject s3:GetObject --resource-arns arn:aws:s3:::school-reports/term1.pdf
aws iam simulate-custom-policy --policy-input-list "$(cat iam/policies/admin.json)" "$(cat iam/policies/deny-delete-reports.json)" --action-names s3:DeleteObject --resource-arns arn:aws:s3:::school-reports/term1.pdf

✅ तपासा — तुम्हाला काय दिसायला हवे

decide हे print करतो: ✅ ALLOW (फक्त admin), ⛔ DENY — explicit Deny in identity policy deny-delete-reports#NeverDeleteReports — nothing overrides it, GetObject साठी ✅ ALLOW (Deny फक्त delete करण्याबद्दल आहे), आणि काहीच न जोडलेल्या dipika साठी 🚫 IMPLICIT DENY. तुमचा snippet DENY, DENY (क्रम महत्त्वाचा नाही), ALLOW (Deny चा Resource homework bucket ला लागू होत नाही) आणि IMPLICIT DENY (एकटा Deny काहीच देत नाही) print करतो. खऱ्या account वर simulator चा EvalDecision हा s3:DeleteObject साठी explicitDeny असतो.

🏁 तुम्ही आत्ताच काय सिद्ध केले

स्पष्ट Deny कोणत्याही क्रमात कोणत्याही Allow वर मात करतो; Allow नसेल तर उत्तर नाही च राहते; आणि Deny नेहमी फक्त काढूनच घेतो.

⚠️ नेहमीच्या चुका

🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: "कामाला लागेल ते Allow करा, अकल्पनीयला Deny करा" (backups delete करणे, CloudTrail बंद करणे, मंजूर regions सोडून बाहेर जाणे) हाच जवळजवळ प्रत्येक खऱ्या permission design चा आकार आहे — आणि स्पष्ट denies मुळेच तो सुरक्षित ठरतो.

⏭️ पुढे

लोकांसाठी कार्डे ठीक आहेत — पण ज्याला दहा मिनिटांसाठी access हवा अशा robot चे काय? Roles आणि STS — जवळ बाळगायचे कार्ड नाही, तर घालायची टोपी.

git checkout lesson-05-roles-sts

⚖️ Lesson 04 — How AWS decides: deny, allow, deny wins

📍 You are here: Lesson 04 of 12 · Previous: lesson-03-policies · Next: lesson-05-roles-sts


📦 What's in this branch

Lessons 01–03, plus the policy evaluation logic: start at deny, an Allow opens the door, an explicit Deny closes it whatever else says. decide() in iam/evaluate.py implements it step by step, and decide_() in iam/demo.py shows it.

🧒 Explain like I'm 5

The ID office clerk follows three rules, always in this order:

  1. Start at "no". Every answer begins as no.
  2. Look for a "no, never" card. If any card anywhere says "Deny" for this — stop. The answer is no, even if the principal has a card that says "you may do everything".
  3. Look for a "yes" card. If one matches, the answer is yes. If none does, it stays no.

So Katrina, who has the "may do everything" card, still cannot throw away a school report once the "reports are never deleted" card is pinned up. The order of the cards in the pile does not matter — "never" always wins.

🗺️ Diagram

flowchart LR
    req["📨 request<br/>katrina · s3:DeleteObject · school-reports/term1.pdf"]
    d{"explicit Deny<br/>in any policy?"}
    a{"an Allow<br/>matches?"}
    req --> d
    d -->|"1 yes"| deny["⛔ DENY<br/>nothing overrides it"]
    d -->|"no"| a
    a -->|"2 yes"| allow["✅ ALLOW"]
    a -->|"3 no"| imp["🚫 IMPLICIT DENY<br/>the default"]

🗺️ Drawn version + a lab: https://school-edh.pages.dev/iam/lesson-diagrams.html#l04

❓ What

🤔 Why

Because "why was I denied?" is the most common IAM question, and the answer is always one of two things: an explicit Deny somewhere (find it) or no Allow anywhere (add one, narrowly). Knowing which one saves hours.

🔧 How (in this repo)

decide() scans every policy group for a matching Deny first (step 1), then checks the layers that must allow, then the identity policies. _scan() returns the first Deny it meets, or the label of an Allow. The reason string names the policy and Sid that decided — admin#Everything, deny-delete-reports#NeverDeleteReports.

🧪 Try it

python3 iam/demo.py decide
python3 - <<'EOF'
import sys; sys.path.insert(0, "iam"); from evaluate import decide, load
katrina, R = "arn:aws:iam::111122223333:user/katrina", "arn:aws:s3:::school-reports/term1.pdf"
a, d = ("admin", load("admin")), ("deny-delete-reports", load("deny-delete-reports"))
print("admin, deny          ", decide(katrina, "s3:DeleteObject", R, identity=[a, d])[0])
print("deny, admin          ", decide(katrina, "s3:DeleteObject", R, identity=[d, a])[0])
print("other bucket         ", decide(katrina, "s3:DeleteObject", "arn:aws:s3:::school-homework/katrina/x", identity=[a, d])[0])
print("deny alone, GetObject", decide(katrina, "s3:GetObject", R, identity=[d])[0])
EOF

On a real account (needs the AWS CLI and credentials) — the real referee. The first call tests a user's actual attached policies; the second tests policy files before you attach them:

aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::111122223333:user/katrina --action-names s3:DeleteObject s3:GetObject --resource-arns arn:aws:s3:::school-reports/term1.pdf
aws iam simulate-custom-policy --policy-input-list "$(cat iam/policies/admin.json)" "$(cat iam/policies/deny-delete-reports.json)" --action-names s3:DeleteObject --resource-arns arn:aws:s3:::school-reports/term1.pdf

✅ Verify — what you should see

decide prints ✅ ALLOW (admin only), ⛔ DENY — explicit Deny in identity policy deny-delete-reports#NeverDeleteReports — nothing overrides it, ✅ ALLOW for GetObject (the Deny is only about deleting), and 🚫 IMPLICIT DENY for dipika with nothing attached. Your snippet prints DENY, DENY (order does not matter), ALLOW (the Deny's Resource does not cover the homework bucket) and IMPLICIT DENY (a Deny alone grants nothing). On a real account the simulator's EvalDecision is explicitDeny for s3:DeleteObject.

🏁 What you just proved

An explicit Deny beats any Allow, in any order; without an Allow the answer is still no; and a Deny only ever takes away.

⚠️ Common mistakes

🏭 Why this matters in production: "Allow what the job needs, Deny the unthinkable" (deleting backups, turning off CloudTrail, leaving approved regions) is the shape of almost every real permission design — and explicit denies are what make it safe.

⏭️ Next

Cards for people are fine — but what about a robot that needs access for ten minutes? Roles and STS — the hat you wear, not the card you carry.

git checkout lesson-05-roles-sts
← PreviouspoliciesNext →roles sts

This page is the lesson's README from the lesson-04-how-aws-decides branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.