ЁЯПл The SchoolтА║ЁЯкк IAMтА║ЁЯОй рдзрдбрд╛ 05 тАФ Roles рдЖрдгрд┐ STS: рдХрд╛рд░реНрдб рдирд╛рд╣реА, рдЯреЛрдкреА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯОй рдзрдбрд╛ 05 тАФ Roles рдЖрдгрд┐ STS: рдХрд╛рд░реНрдб рдирд╛рд╣реА, рдЯреЛрдкреА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 05 ┬╖ рдорд╛рдЧреЗ: lesson-04-how-aws-decides ┬╖ рдкреБрдвреЗ: lesson-06-machine-identities


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

рдзрдбреЗ 01тАУ04, рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд roles: password рдирд╕рд▓реЗрд▓реА рдЖрдгрд┐ рдХрд╛рдпрдордЪреА key рдирд╕рд▓реЗрд▓реА identity, рддреА рдХреЛрдг assume рдХрд░реВ рд╢рдХрддреЛ рддреЗ рд╕рд╛рдВрдЧрдгрд╛рд░реА trust policy, рддрд╛рддреНрдкреБрд░рддреА credentials рджреЗрдгрд╛рд░рд╛ STS, рдЖрдгрд┐ рдПрдХрд╛ session рд▓рд╛ рдорд░реНрдпрд╛рджрд┐рдд рдХрд░рдгрд╛рд░реА session policy. Files: trust-ci-deployer.json, ci-deploy.json, session-read-only.json.

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

рд╢рд╛рд│реЗрддрд▓реНрдпрд╛ рдХрд╛рд╣реА рдХрд╛рдорд╛рдВрд╕реЛрдмрдд рдПрдХ рдЯреЛрдкреА ЁЯОй рдпреЗрддреЗ: "рдкрд░реАрдХреНрд╖рд╛ рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХ" рдЪреА рдЯреЛрдкреА рдкрд░реАрдХреНрд╖реЗрдЪрд╛ рд╣реЙрд▓ рдЙрдШрдбрддреЗ. рддреА рдЯреЛрдкреА рдХреЛрдгрд╛рдЪреНрдпрд╛рдЪ рдорд╛рд▓рдХреАрдЪреА рдирд╕рддреЗ. рддреБрдореНрд╣реА рддреА рдШрд╛рд▓рд╛рдпрд▓рд╛ рдУрд│рдЦрдкрддреНрд░ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдХрдбреЗ рдорд╛рдЧрддрд╛; рдХрд╛рд░реНрдпрд╛рд▓рдп рдЯреЛрдкреАрдЪреНрдпрд╛ рд▓реЗрдмрд▓рд╡рд░рдЪреА рдпрд╛рджреА рддрдкрд╛рд╕рддреЗ ("рд╣реА рдлрдХреНрдд CI robot рдШрд╛рд▓реВ рд╢рдХрддреЛ"), рдЖрдгрд┐ рддреБрдореНрд╣реА рддреНрдпрд╛ рдпрд╛рджреАрдд рдЕрд╕рд╛рд▓ рддрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рддреА рдЯреЛрдкреА рдПрдХрд╛ рддрд╛рд╕рд╛рд╕рд╛рдареА рдорд┐рд│рддреЗ. рдордЧ рддреА рдЖрдкреЛрдЖрдк рдирд╛рд╣реАрд╢реА рд╣реЛрддреЗ.

рдЯреЛрдкреА рдШрд╛рддрд▓реА рдЕрд╕рддрд╛рдирд╛ рддреБрдордЪреНрдпрд╛рдХрдбреЗ рдЯреЛрдкреАрдЪреНрдпрд╛ рдкрд░рд╡рд╛рдирдЧреНрдпрд╛ рдЕрд╕рддрд╛рдд тАФ рддреБрдордЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдирд╛рд╣реАрдд. рдЖрдгрд┐ рдХрд╛рд░реНрдпрд╛рд▓рдп рддреБрдореНрд╣рд╛рд▓рд╛ рддреНрдпрд╛рд╡рд░ рдПрдХ sticker рд▓рд╛рд╡реВрди рдЯреЛрдкреА рджреЗрдК рд╢рдХрддреЗ: "рдЖрдЬ рдлрдХреНрдд рдмрдШрд╛, рд╣рд╛рдд рд▓рд╛рд╡реВ рдирдХрд╛". рддреЛ sticker рдлрдХреНрдд рдкрд░рд╡рд╛рдирдЧреНрдпрд╛ рдХрд╛рдвреВрди рдШреЗрдК рд╢рдХрддреЛ, рдХрдзреАрдЪ рдирд╡реАрди рджреЗрдК рд╢рдХрдд рдирд╛рд╣реА.

рд╣рд╛рдЪ role: рдЯреЛрдкреА. рд▓реЗрдмрд▓ рдореНрд╣рдгрдЬреЗ рддрд┐рдЪреА trust policy. рдПрдХрд╛ рддрд╛рд╕рд╛рдЪрд╛ pass STS (Security Token Service) рдХрдбреВрди рдпреЗрддреЛ. Sticker рдореНрд╣рдгрдЬреЗ session policy.

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

flowchart LR
    who["ЁЯдЦ user/ci-robot"]
    trust["ЁЯП╖я╕П trust policy<br/>Principal: user/ci-robot<br/>Action: sts:AssumeRole"]
    sts["ЁЯОЯя╕П STS AssumeRole<br/>ASIAтАж key + session token<br/>expires in 1 hour"]
    sess["ЁЯОй assumed-role/ci-deployer/build-42"]
    perm["ЁЯУЭ ci-deploy policy<br/>ecr:PutImage тАж"]
    who -->|"1 may I wear it?"| trust -->|"2 yes"| sts --> sess
    sess -->|"3 acts with"| perm

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

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

ЁЯдФ рдХрд╛

рджреАрд░реНрдШрдХрд╛рд│рд╛рдЪреНрдпрд╛ keys рдлреБрдЯрддрд╛рдд тАФ git рдордзреНрдпреЗ, logs рдордзреНрдпреЗ, laptops рдордзреНрдпреЗ тАФ рдЖрдгрд┐ рдХреЛрдгрд╛рдЪреНрдпрд╛ рд▓рдХреНрд╖рд╛рдд рдпреЗрдИрдкрд░реНрдпрдВрдд рдЪрд╛рд▓реВрдЪ рд░рд╛рд╣рддрд╛рдд. рддрд╛рддреНрдкреБрд░рддреА credentials рдЖрдкреЛрдЖрдк рд╕рдВрдкрддрд╛рдд, рдирд╛рд╡ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ session рд╢реА рдЬреЛрдбрд▓реЗрд▓реА рдЕрд╕рддрд╛рдд, рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ рдХрдзреАрдЪ rotate рдХрд░рд╛рд╡реЗ рд▓рд╛рдЧрдд рдирд╛рд╣реА. AWS services, CI systems, рдЗрддрд░ accounts рдЖрдгрд┐ рд▓реЛрдХ (рдзрдбрд╛ 10) рдпрд╛рдВрдирд╛ access roles рдордзреВрдирдЪ рдорд┐рд│рд╛рдпрд▓рд╛ рд╣рд╡рд╛.

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

iam/demo.py рдордзрд▓рд╛ roles() ci-robot рдЖрдгрд┐ dipika рд╕рд╛рдареА matches() рдиреЗ trust statement рддрдкрд╛рд╕рддреЛ, рддрд╛рддреНрдкреБрд░рддреНрдпрд╛ credentials рдЪреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг print рдХрд░рддреЛ, рдЖрдгрд┐ рдордЧ session рд╕рд╛рдареА decide() call рдХрд░рддреЛ тАФ рдПрдХрджрд╛ рдлрдХреНрдд role policy рд╕рд╣, рдЖрдгрд┐ рдПрдХрджрд╛ read-only session policy рдЬреЛрдбреВрди (session=).

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

python3 iam/demo.py roles
python3 - <<'EOF'
import sys; sys.path.insert(0, "iam"); from evaluate import decide, load, matches
trust = load("trust-ci-deployer")["Statement"][0]
role = "arn:aws:iam::111122223333:role/ci-deployer"
print("ci-robot may assume:", matches(trust, "sts:AssumeRole", role, {}, "arn:aws:iam::111122223333:user/ci-robot"))
print("partner may assume: ", matches(trust, "sts:AssumeRole", role, {}, "arn:aws:iam::444455556666:user/ci-robot"))
sess = "arn:aws:sts::111122223333:assumed-role/ci-deployer/build-43"
ci = [("ci-deploy", load("ci-deploy"))]
wide = [("session-s3", {"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": "s3:*", "Resource": "*"}]})]
print("in both:            ", decide(sess, "ecr:GetAuthorizationToken", "*", identity=ci, session=[("session-read-only", load("session-read-only"))])[0])
print("session only:       ", decide(sess, "s3:GetObject", "arn:aws:s3:::school-reports/term1.pdf", identity=ci, session=wide)[0])
EOF

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS CLI рдЖрдгрд┐ credentials рд▓рд╛рдЧрддрд╛рдд):

aws iam create-role --role-name ci-deployer --assume-role-policy-document file://iam/policies/trust-ci-deployer.json
aws iam put-role-policy --role-name ci-deployer --policy-name ci-deploy --policy-document file://iam/policies/ci-deploy.json
aws sts assume-role --role-arn arn:aws:iam::111122223333:role/ci-deployer --role-session-name build-42 --duration-seconds 3600
aws sts assume-role --role-arn arn:aws:iam::111122223333:role/ci-deployer --role-session-name build-43 --policy file://iam/policies/session-read-only.json

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

roles рд╣реЗ print рдХрд░рддреЛ: ЁЯОй ci-robot тАж trust policy lets them тЬЕ, ЁЯОй dipika тАж refuses ЁЯЪл, рдЙрджрд╛рд╣рд░рдгрд╛рджрд╛рдЦрд▓ credentials рдЪреА рдУрд│, рдордЧ тЬЕ role session тЖТ ecr:PutImage ALLOW рдЖрдгрд┐ ЁЯЪл same session + read-only session policy IMPLICIT DENY тАФ outside the session policy passed to AssumeRole. рддреБрдордЪрд╛ snippet True, False (рддреЗрдЪ user рдирд╛рд╡, рдкрдг рд╡реЗрдЧрд│реЗ account тАФ рд▓реЗрдмрд▓рд╡рд░рдЪрд╛ principal рдирд╛рд╣реА), ALLOW (рджреЛрдШрд╛рдВрдиреАрд╣реА allow рдХреЗрд▓реЗрд▓реЗ) рдЖрдгрд┐ IMPLICIT DENY (session policy s3:* рд▓рд╛ allow рдХрд░рддреЗ, рдкрдг role рдХрдбреЗ рддреЗ рдХрдзреАрдЪ рдирд╡реНрд╣рддреЗ тАФ session policy рдХрд╛рд╣реА рдЬреЛрдбреВ рд╢рдХрдд рдирд╛рд╣реА) print рдХрд░рддреЛ. рдЦрд▒реНрдпрд╛ account рд╡рд░ assume-role рдПрдХ Credentials block рдкрд░рдд рджреЗрддреЛ, рдЬреНрдпрд╛рдЪрд╛ AccessKeyId ASIA рдиреЗ рд╕реБрд░реВ рд╣реЛрддреЛ.

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

Role рдШрд╛рддрд▓рд╛ рдЬрд╛рддреЛ, рддреЛ рдХреЛрдгрд╛рдЪреНрдпрд╛ рдорд╛рд▓рдХреАрдЪрд╛ рдирд╕рддреЛ: trust policy рддреЛ рдХреЛрдг рдШрд╛рд▓реВ рд╢рдХрддреЛ рддреЗ рдирд┐рд╡рдбрддреЗ, STS pass рддрд╛рддреНрдкреБрд░рддрд╛ рдмрдирд╡рддреЛ, рдЖрдгрд┐ session policy role рдХрдбреЗ рдЖрдзреАрдЪ рдЕрд╕рд▓реЗрд▓реЗ рдлрдХреНрдд рдХрдореАрдЪ рдХрд░реВ рд╢рдХрддреЗ.

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

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдиреАрдЯ рдЪрд╛рд▓рд╡рд▓реЗрд▓реНрдпрд╛ AWS рд╡реНрдпрд╡рд╕реНрдерд╛рдВрдордзреНрдпреЗ рдЬрд╡рд│рдЬрд╡рд│ рдкреНрд░рддреНрдпреЗрдХ caller рд╣рд╛ role session рдЕрд╕рддреЛ тАФ services, pipelines, рдЗрддрд░ accounts рдЖрдгрд┐ SSO рдордзреВрди рдпреЗрдгрд╛рд░реЗ рд▓реЛрдХ тАФ рдЖрдгрд┐ рджреАрд░реНрдШрдХрд╛рд│рд╛рдЪреНрдпрд╛ access keys рдЪреА рд╕рдВрдЦреНрдпрд╛ рдЬрд╡рд│рдЬрд╡рд│ рд╢реВрдиреНрдп рдЕрд╕рддреЗ.

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

рдЬреЛ robot AWS рдордзреНрдпреЗ рдореБрд│реАрдЪ рдирд╛рд╣реА тАФ GitHub Actions, рдПрдЦрд╛рджрд╛ pod, рдПрдЦрд╛рджрд╛ Lambda тАФ рддреНрдпрд╛рд▓рд╛ рд╕рд╛рдард╡рд▓реЗрд▓реНрдпрд╛ key рд╢рд┐рд╡рд╛рдп рдЯреЛрдкреА рдХрд╢реА рдорд┐рд│рддреЗ? Machine identities.

git checkout lesson-06-machine-identities

ЁЯОй Lesson 05 тАФ Roles & STS: the hat, not the card

ЁЯУН You are here: Lesson 05 of 12 ┬╖ Previous: lesson-04-how-aws-decides ┬╖ Next: lesson-06-machine-identities


ЁЯУж What's in this branch

Lessons 01тАУ04, plus roles: an identity with no password and no permanent key, a trust policy that says who may assume it, STS issuing temporary credentials, and a session policy that narrows one session. Files: trust-ci-deployer.json, ci-deploy.json, session-read-only.json.

ЁЯзТ Explain like I'm 5

Some jobs in school come with a hat ЁЯОй: the "exam invigilator" hat opens the exam hall. Nobody owns the hat. You ask the ID office to wear it; the office checks the list on the hat's label ("only the CI robot may wear this"), and if you are on it, you get the hat for one hour. Then it vanishes by itself.

Wearing the hat, you have the hat's permissions тАФ not your own. And the office can give you the hat with a sticker on it: "today, only look, do not touch". The sticker can only take permissions away, never add any.

That is a role: the hat. The label is its trust policy. The one-hour pass comes from STS (Security Token Service). The sticker is a session policy.

ЁЯЧ║я╕П Diagram

flowchart LR
    who["ЁЯдЦ user/ci-robot"]
    trust["ЁЯП╖я╕П trust policy<br/>Principal: user/ci-robot<br/>Action: sts:AssumeRole"]
    sts["ЁЯОЯя╕П STS AssumeRole<br/>ASIAтАж key + session token<br/>expires in 1 hour"]
    sess["ЁЯОй assumed-role/ci-deployer/build-42"]
    perm["ЁЯУЭ ci-deploy policy<br/>ecr:PutImage тАж"]
    who -->|"1 may I wear it?"| trust -->|"2 yes"| sts --> sess
    sess -->|"3 acts with"| perm

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

тЭУ What

ЁЯдФ Why

Long-lived keys leak тАФ in git, in logs, in laptops тАФ and stay valid until someone notices. Temporary credentials expire by themselves, are tied to a named session, and never need rotating. Roles are how AWS services, CI systems, other accounts and people (lesson 10) should get access.

ЁЯФз How (in this repo)

roles() in iam/demo.py checks the trust statement with matches() for ci-robot and for dipika, prints an example of temporary credentials, then calls decide() for the session тАФ once with only the role policy, once with the read-only session policy added (session=).

ЁЯзк Try it

python3 iam/demo.py roles
python3 - <<'EOF'
import sys; sys.path.insert(0, "iam"); from evaluate import decide, load, matches
trust = load("trust-ci-deployer")["Statement"][0]
role = "arn:aws:iam::111122223333:role/ci-deployer"
print("ci-robot may assume:", matches(trust, "sts:AssumeRole", role, {}, "arn:aws:iam::111122223333:user/ci-robot"))
print("partner may assume: ", matches(trust, "sts:AssumeRole", role, {}, "arn:aws:iam::444455556666:user/ci-robot"))
sess = "arn:aws:sts::111122223333:assumed-role/ci-deployer/build-43"
ci = [("ci-deploy", load("ci-deploy"))]
wide = [("session-s3", {"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": "s3:*", "Resource": "*"}]})]
print("in both:            ", decide(sess, "ecr:GetAuthorizationToken", "*", identity=ci, session=[("session-read-only", load("session-read-only"))])[0])
print("session only:       ", decide(sess, "s3:GetObject", "arn:aws:s3:::school-reports/term1.pdf", identity=ci, session=wide)[0])
EOF

On a real account (needs the AWS CLI and credentials):

aws iam create-role --role-name ci-deployer --assume-role-policy-document file://iam/policies/trust-ci-deployer.json
aws iam put-role-policy --role-name ci-deployer --policy-name ci-deploy --policy-document file://iam/policies/ci-deploy.json
aws sts assume-role --role-arn arn:aws:iam::111122223333:role/ci-deployer --role-session-name build-42 --duration-seconds 3600
aws sts assume-role --role-arn arn:aws:iam::111122223333:role/ci-deployer --role-session-name build-43 --policy file://iam/policies/session-read-only.json

тЬЕ Verify тАФ what you should see

roles prints ЁЯОй ci-robot тАж trust policy lets them тЬЕ, ЁЯОй dipika тАж refuses ЁЯЪл, the example credentials line, then тЬЕ role session тЖТ ecr:PutImage ALLOW and ЁЯЪл same session + read-only session policy IMPLICIT DENY тАФ outside the session policy passed to AssumeRole. Your snippet prints True, False (same user name, different account тАФ not the principal on the label), ALLOW (allowed by both) and IMPLICIT DENY (the session policy allows s3:*, but the role never had it тАФ a session policy cannot add). On a real account, assume-role returns a Credentials block whose AccessKeyId starts with ASIA.

ЁЯПБ What you just proved

A role is worn, not owned: the trust policy picks who may wear it, STS makes the pass temporary, and a session policy can only shrink what the role already has.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: in well-run AWS estates, nearly every caller is a role session тАФ services, pipelines, other accounts and people via SSO тАФ and the number of long-lived access keys is close to zero.

тПня╕П Next

How does a robot that is not in AWS at all тАФ GitHub Actions, a pod, a Lambda тАФ get a hat without a stored key? Machine identities.

git checkout lesson-06-machine-identities
тЖР Previoushow aws decidesNext тЖТmachine identities

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