ЁЯПл The SchoolтА║ЁЯкк IAMтА║ЁЯЪз рдзрдбрд╛ 08 тАФ Guardrails: рдкреНрд░рддреНрдпреЗрдХ policy рд╡рд░рдЪреЗ рдЫрдд
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЪз рдзрдбрд╛ 08 тАФ Guardrails: рдкреНрд░рддреНрдпреЗрдХ policy рд╡рд░рдЪреЗ рдЫрдд

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 08 ┬╖ рдорд╛рдЧреАрд▓: lesson-07-conditions-abac ┬╖ рдкреБрдвреАрд▓: lesson-09-cross-account


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ07, рдЖрдгрд┐ рджреЛрди рдЫрддреЗ: рдПрдХрд╛ identity рд╡рд░ permission boundary (boundary-developers.json) рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг account рд╡рд░ AWS Organizations рдЪреНрдпрд╛ service control policies (scp-full-access.json, scp-two-regions.json).

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдПрдХрд╛ рдирд╡реНрдпрд╛ lab рд╕рд╣рд╛рдпреНрдпрд┐рдХреЗрд▓рд╛ "lab рдордзреНрдпреЗ рдХрд╛рд╣реАрд╣реА рдХрд░реВ рд╢рдХрддреЗ" рдЕрд╕реЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдХрд╛рд░реНрдб рдорд┐рд│рддреЗ. рд╡рд┐рдЬреНрдЮрд╛рди рд╕рдордиреНрд╡рдпрд┐рдХрд╛ рддреНрдпрд╛рд╡рд░ рдПрдХ рдЫрдд ЁЯЪз рдШрд╛рд▓рддреЗ: "тАжрдкрдг рдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдХрдзреАрдЪ рдирд╛рд╣реА: рдЙрдкрдХрд░рдгреЗ рд╡рд╛рдкрд░рдгреЗ, рдиреЛрдВрджрд╡рд╣реНрдпрд╛ рд╡рд╛рдЪрдгреЗ". рдХрд╛рд░реНрдбрд╡рд░ рдЕрдЬреВрдирд╣реА "рдХрд╛рд╣реАрд╣реА" рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЖрд╣реЗ тАФ рдкрдг рдЫрддрд╛рдЪреНрдпрд╛ рд╡рд░ рдЬреЗ рдХрд╛рд╣реА рдЖрд╣реЗ рддреЗ рд╣рд╛рддрд╛рд▓рд╛ рд▓рд╛рдЧрддрдЪ рдирд╛рд╣реА. рд╣реАрдЪ permission boundary.

рдордЧ рд╕рдВрдкреВрд░реНрдг рд╢рд╛рд│рд╛ рдПрдХрд╛ рд╢рд╛рд│рд╛ рдордВрдбрд│рд╛рдЪреА рдЕрд╕рддреЗ, рдЖрдгрд┐ рдордВрдбрд│ рдЪрд╛рд▓рд╡рдд рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рд│реЗрд╕рд╛рдареА рддреНрдпрд╛рдЪреЗ рд╕реНрд╡рддрдГрдЪреЗ рдирд┐рдпрдо рдЕрд╕рддрд╛рдд: "рдХреЛрдгрддреАрд╣реА рд╢рд╛рд│рд╛ рдпрд╛ рджреЛрди рд╢рд╣рд░рд╛рдВрдмрд╛рд╣реЗрд░ рд╢рд╛рдЦрд╛ рдЙрдШрдбрдгрд╛рд░ рдирд╛рд╣реА". рдПрдЦрд╛рджреНрдпрд╛ рд╢рд╛рд│реЗрдЪреНрдпрд╛ рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрд▓рд╛рд╣реА рддреЛ рдирд┐рдпрдо рдореЛрдбрддрд╛ рдпреЗрдд рдирд╛рд╣реА. рд╣реАрдЪ SCP.

рдЫрдд рдХрдзреАрдЪ рдХрд╛рд╣реА рджреЗрдд рдирд╛рд╣реА. рд╢рд┐рдбреА рдХрд┐рддреА рдЙрдВрдЪ рдЬрд╛рдК рд╢рдХрддреЗ рдПрд╡рдвреЗрдЪ рддреЗ рдард░рд╡рддреЗ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    id["ЁЯУЭ identity policy<br/>admin: * on *"]
    b["ЁЯЪз boundary<br/>s3:* ┬╖ logs:* ┬╖ cloudwatch:* ┬╖ ec2:Describe*"]
    scp["ЁЯПЫя╕П SCP<br/>deny outside ap-south-1 ┬╖ us-east-1"]
    eff["тЬЕ effective<br/>identity тИй boundary тИй SCP"]
    id --> eff
    b -->|"1 ceiling on one identity"| eff
    scp -->|"2 ceiling on the account"| eff
    eff -.->|"iam:CreateUser"| no["ЁЯЪл outside the boundary"]

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/iam/lesson-diagrams.html#l08

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг admins рдЪреБрдХрд╛ рдХрд░рддрд╛рдд, credentials рдлреБрдЯрддрд╛рдд, рдЖрдгрд┐ teams рдирд╛ рд╕реНрд╡рддрдГрдЪреЗ roles рдмрдирд╡рдгреНрдпрд╛рдЪреЗ рд╕реНрд╡рд╛рддрдВрддреНрд░реНрдп рд╣рд╡реЗ рдЕрд╕рддреЗ. Guardrails "рдХреГрдкрдпрд╛ рдХрд░реВ рдирдХрд╛" рдЪреЗ "рдХрд░рддрд╛рдЪ рдпреЗрдд рдирд╛рд╣реА" рдХрд░рддрд╛рдд: рдХреЛрдгреАрд╣реА рдордВрдЬреВрд░ regions рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░ рдЬрд╛рдК рд╢рдХрдд рдирд╛рд╣реА, audit trail рдмрдВрдж рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА, рдХрд┐рдВрд╡рд╛ рд╕реНрд╡рддрдГрд▓рд╛ рдЫрддрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рджреЗрдК рд╢рдХрдд рдирд╛рд╣реА.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

iam/demo.py рдордзреАрд▓ guardrails() dipika рд▓рд╛ admin policy boundary рд╕рд╣ рдЖрдгрд┐ boundary рд╢рд┐рд╡рд╛рдп (boundary=) рджреЗрддреЗ, рдордЧ katrina рдЪреА admin policy рджреЛрди SCPs рдЦрд╛рд▓реА (scps=) рджреЛрди regions рдордзреНрдпреЗ рдЪрд╛рд▓рд╡рддреЗ. iam/evaluate.py рдордзреНрдпреЗ decide() рдЪреНрдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛ 2 рдЖрдгрд┐ 4 рд╕рд╛рдВрдЧрддрд╛рдд "allow рдХрд░рд╛рдпрд▓рд╛рдЪ рд╣рд╡реЗ, рдХрдзреАрдЪ рджреЗрдд рдирд╛рд╣реА".

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 iam/demo.py guardrails
python3 - <<'EOF'
import sys; sys.path.insert(0, "iam"); from evaluate import decide, load
dipika, katrina = "arn:aws:iam::111122223333:user/dipika", "arn:aws:iam::111122223333:user/katrina"
admin, b = [("admin", load("admin"))], [("boundary-developers", load("boundary-developers"))]
print("boundary alone      ", decide(dipika, "s3:PutObject", "arn:aws:s3:::dev-scratch/x", identity=[], boundary=b)[0])
deny_only = [("scp-two-regions", load("scp-two-regions"))]
print("SCP deny-list only  ", decide(katrina, "ec2:RunInstances", "*", {"aws:RequestedRegion": "ap-south-1"}, identity=admin, scps=deny_only))
scps = [("scp-full-access", load("scp-full-access"))] + deny_only
print("IAM from sa-east-1  ", decide(katrina, "iam:CreateUser", "*", {"aws:RequestedRegion": "sa-east-1"}, identity=admin, scps=scps)[0])
EOF

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS CLI рдЖрдгрд┐ credentials рд▓рд╛рдЧрддрд╛рдд; SCP commands organization рдЪреНрдпрд╛ management account рдордзреВрди рдЪрд╛рд▓рддрд╛рдд, рдЖрдгрд┐ IDs рдЙрджрд╛рд╣рд░рдгрд╛рджрд╛рдЦрд▓ рдЖрд╣реЗрдд):

aws iam create-policy --policy-name boundary-developers --policy-document file://iam/policies/boundary-developers.json
aws iam put-user-permissions-boundary --user-name dipika --permissions-boundary arn:aws:iam::111122223333:policy/boundary-developers
aws organizations create-policy --name two-regions --type SERVICE_CONTROL_POLICY --description "Only ap-south-1 and us-east-1" --content file://iam/policies/scp-two-regions.json
aws organizations attach-policy --policy-id p-examplepolicyid111 --target-id ou-ab12-cd34ef56

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

guardrails boundary рд╢рд┐рд╡рд╛рдп dipika рдЪреНрдпрд╛ admin рд╕рд╛рдареА тЬЕ ALLOW рдЫрд╛рдкрддреЗ, boundary рд╕рд╣ ЁЯЪл IMPLICIT DENY тАФ outside the permission boundary тАФ the boundary is a ceiling, not a grant, s3:PutObject рд╕рд╛рдареА тЬЕ ALLOW (рдЫрддрд╛рдЪреНрдпрд╛ рдЖрдд), ap-south-1 рдордзреНрдпреЗ тЬЕ ALLOW рдЖрдгрд┐ sa-east-1 рдордзреНрдпреЗ тЫФ DENY тАФ explicit Deny in SCP scp-two-regions#OnlyMumbaiAndVirginia. рддреБрдордЪрд╛ snippet рдЖрдзреА IMPLICIT DENY рдЫрд╛рдкрддреЛ (boundary рдХрд╛рд╣реАрдЪ рджреЗрдд рдирд╛рд╣реА), рдордЧ ('IMPLICIT DENY', "the organization's SCPs do not allow this action for the account") тАФ FullAWSAccess рд╢рд┐рд╡рд╛рдп рдордВрдЬреВрд░ region рдордзреНрдпреЗрд╕реБрджреНрдзрд╛ рдХрд╛рд╣реАрдЪ allow рд╣реЛрдд рдирд╛рд╣реА тАФ рдЖрдгрд┐ sa-east-1 рдордзреВрди iam:CreateUser рд╕рд╛рдареА ALLOW, рдХрд╛рд░рдг SCP рдЪрд╛ NotAction IAM рд▓рд╛ рд╕реВрдЯ рджреЗрддреЛ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

Boundaries рдЖрдгрд┐ SCPs рдлрдХреНрдд рдХрд╛рдвреВрдирдЪ рдШреЗрддрд╛рдд: рдЫрддрд╛рдЦрд╛рд▓рдЪреА admin policy рддреНрдпрд╛ рдЫрддрд╛рдЗрддрдХреАрдЪ рддрд╛рдХрджрд╡рд╛рди рдЕрд╕рддреЗ, рдЖрдгрд┐ рдЬреНрдпрд╛ рдЫрддрд╛рдЦрд╛рд▓реА рдХреЛрдгрддреЗрд╣реА Allow рдирд╛рд╣реА рддреЗ рдХрд╛рд╣реАрдЪ allow рдХрд░рдд рдирд╛рд╣реА.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: multi-account landing zone рдиреЗрд╣рдореА baseline SCPs рд╕реЛрдмрддрдЪ рдпреЗрддреЛ тАФ organization рд╕реЛрдбрдгреНрдпрд╛рд╕ рдирдХрд╛рд░, CloudTrail рдЖрдгрд┐ GuardDuty рдмрдВрдж рдХрд░рдгреНрдпрд╛рд╕ рдирдХрд╛рд░, рдордВрдЬреВрд░ рдирд╕рд▓реЗрд▓реНрдпрд╛ regions рдирд╛ рдирдХрд╛рд░, root-user actions рдирд╛ рдирдХрд╛рд░ тАФ рдЖрдгрд┐ roles рдмрдирд╡рдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ team рд╕рд╛рдареА boundaries.

тПня╕П рдкреБрдвреЗ

рдПрдХрд╛ partner рд╢рд╛рд│реЗрдЪреНрдпрд╛ auditor рд▓рд╛ рддреБрдордЪреЗ reports рд╡рд╛рдЪрд╛рдпрдЪреЗ рдЖрд╣реЗрдд. Cross-account access рдЖрдгрд┐ resource policies тАФ рджреЛрди рджрд░рд╡рд╛рдЬреЗ, рджреЛрди рдЪрд╛рд╡реНрдпрд╛.

git checkout lesson-09-cross-account

ЁЯЪз Lesson 08 тАФ Guardrails: ceilings above every policy

ЁЯУН You are here: Lesson 08 of 12 ┬╖ Previous: lesson-07-conditions-abac ┬╖ Next: lesson-09-cross-account


ЁЯУж What's in this branch

Lessons 01тАУ07, plus the two ceilings: a permission boundary on one identity (boundary-developers.json) and AWS Organizations service control policies on a whole account (scp-full-access.json, scp-two-regions.json).

ЁЯзТ Explain like I'm 5

A new lab assistant gets a card that says "may do anything in the lab". The science coordinator adds a ceiling ЁЯЪз above it: "тАжbut never more than: use the equipment, read the logbooks". The card still says "anything" тАФ but whatever is above the ceiling is simply out of reach. That is a permission boundary.

Then the whole school belongs to a school board, and the board has its own rules for every school it runs: "no school may open a branch outside these two cities". Even the principal of one school cannot break that. That is an SCP.

A ceiling never gives anything. It only decides how high the ladder can go.

ЁЯЧ║я╕П Diagram

flowchart LR
    id["ЁЯУЭ identity policy<br/>admin: * on *"]
    b["ЁЯЪз boundary<br/>s3:* ┬╖ logs:* ┬╖ cloudwatch:* ┬╖ ec2:Describe*"]
    scp["ЁЯПЫя╕П SCP<br/>deny outside ap-south-1 ┬╖ us-east-1"]
    eff["тЬЕ effective<br/>identity тИй boundary тИй SCP"]
    id --> eff
    b -->|"1 ceiling on one identity"| eff
    scp -->|"2 ceiling on the account"| eff
    eff -.->|"iam:CreateUser"| no["ЁЯЪл outside the boundary"]

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/iam/lesson-diagrams.html#l08

тЭУ What

ЁЯдФ Why

Because admins make mistakes, credentials leak, and teams need freedom to create their own roles. Guardrails turn "please don't" into "can't": no one can leave approved regions, turn off the audit trail, or grant themselves more than their ceiling.

ЁЯФз How (in this repo)

guardrails() in iam/demo.py gives dipika the admin policy with and without the boundary (boundary=), then runs katrina's admin policy under two SCPs (scps=) in two regions. In iam/evaluate.py, steps 2 and 4 of decide() say "must allow, never grants".

ЁЯзк Try it

python3 iam/demo.py guardrails
python3 - <<'EOF'
import sys; sys.path.insert(0, "iam"); from evaluate import decide, load
dipika, katrina = "arn:aws:iam::111122223333:user/dipika", "arn:aws:iam::111122223333:user/katrina"
admin, b = [("admin", load("admin"))], [("boundary-developers", load("boundary-developers"))]
print("boundary alone      ", decide(dipika, "s3:PutObject", "arn:aws:s3:::dev-scratch/x", identity=[], boundary=b)[0])
deny_only = [("scp-two-regions", load("scp-two-regions"))]
print("SCP deny-list only  ", decide(katrina, "ec2:RunInstances", "*", {"aws:RequestedRegion": "ap-south-1"}, identity=admin, scps=deny_only))
scps = [("scp-full-access", load("scp-full-access"))] + deny_only
print("IAM from sa-east-1  ", decide(katrina, "iam:CreateUser", "*", {"aws:RequestedRegion": "sa-east-1"}, identity=admin, scps=scps)[0])
EOF

On a real account (needs the AWS CLI and credentials; the SCP commands run from the organization's management account, and the IDs are examples):

aws iam create-policy --policy-name boundary-developers --policy-document file://iam/policies/boundary-developers.json
aws iam put-user-permissions-boundary --user-name dipika --permissions-boundary arn:aws:iam::111122223333:policy/boundary-developers
aws organizations create-policy --name two-regions --type SERVICE_CONTROL_POLICY --description "Only ap-south-1 and us-east-1" --content file://iam/policies/scp-two-regions.json
aws organizations attach-policy --policy-id p-examplepolicyid111 --target-id ou-ab12-cd34ef56

тЬЕ Verify тАФ what you should see

guardrails prints тЬЕ ALLOW for dipika's admin without a boundary, ЁЯЪл IMPLICIT DENY тАФ outside the permission boundary тАФ the boundary is a ceiling, not a grant with it, тЬЕ ALLOW for s3:PutObject (inside the ceiling), тЬЕ ALLOW in ap-south-1 and тЫФ DENY тАФ explicit Deny in SCP scp-two-regions#OnlyMumbaiAndVirginia in sa-east-1. Your snippet prints IMPLICIT DENY (a boundary grants nothing), then ('IMPLICIT DENY', "the organization's SCPs do not allow this action for the account") тАФ without FullAWSAccess nothing is allowed even in an approved region тАФ and ALLOW for iam:CreateUser from sa-east-1, because the SCP's NotAction exempts IAM.

ЁЯПБ What you just proved

Boundaries and SCPs only ever take away: an admin policy under a ceiling is only as strong as the ceiling, and a ceiling with no Allow under it allows nothing.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: a multi-account landing zone always ships baseline SCPs тАФ deny leaving the organization, deny disabling CloudTrail and GuardDuty, deny unapproved regions, deny root-user actions тАФ and boundaries for any team allowed to create roles.

тПня╕П Next

A partner school's auditor needs to read your reports. Cross-account access and resource policies тАФ two doors, two keys.

git checkout lesson-09-cross-account
тЖР Previousconditions abacNext тЖТcross account

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