ЁЯЪА рдзрдбрд╛ 12 тАФ CI/CD рдордзреАрд▓ IaC рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг рдЪрд┐рддреНрд░: PR рд╡рд░ plan, merge рд╡рд░ apply
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ рдорд╛рдЧреАрд▓: lesson-11-testing-policy
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ11, рдЖрдгрд┐ рддреНрдпрд╛ рд╕рдЧрд│реНрдпрд╛рдВрдирд╛ рдПрдХрддреНрд░ рдмрд╛рдВрдзрдгрд╛рд░рд╛ conveyor belt. рдЖрд░рд╛рдЦрдбреНрдпрд╛рддреАрд▓ рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓
рдореНрд╣рдгрдЬреЗ рдПрдХ pull request. CI рддреНрдпрд╛рд╡рд░ validate, plan, policy рдЖрдгрд┐ cost рдЪрд╛рд▓рд╡рддреЗ рдЖрдгрд┐ review рд╕рд╛рдареА
plan post рдХрд░рддреЗ. рдлрдХреНрдд main рдордзреАрд▓ merge рдЪ apply рдХрд░рддреЛ тАФ рдЖрдгрд┐ рддреЛ review рдЭрд╛рд▓реЗрд▓рд╛рдЪ plan apply рдХрд░рддреЛ,
рдирд╛рд╣реАрддрд░ рдерд╛рдВрдмрддреЛ. CI рдереЛрдбрд╛ рд╡реЗрд│ рдЯрд┐рдХрдгрд╛рд▒реНрдпрд╛ OIDC token рдиреЗ рдЖрдкрд▓реА рдУрд│рдЦ рд╕рд┐рджреНрдз рдХрд░рддреЗ, рддреНрдпрд╛рдореБрд│реЗ рдХреЛрдгрддреАрд╣реА cloud key
рдХреБрдареЗрд╣реА рд╕рд╛рдард╡рд▓реЗрд▓реА рдирд╕рддреЗ. pipeline() рд╣реЗ iac/demo.py рдордзреНрдпреЗ рдЖрд╣реЗ;
oidc_token(), assume(), pr_pipeline() рдЖрдгрд┐ merge_pipeline() рд╣реЗ
iac/checks.py рдордзреНрдпреЗ; stale-plan рддрдкрд╛рд╕рдгреА
iac/engine.py рдордзреАрд▓ apply() рдордзреНрдпреЗ.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдЖрддрд╛ рдХреЛрдгреАрд╣реА рдЦрд┐рд╢рд╛рдд рдЖрд░рд╛рдЦрдбрд╛ рдШреЗрдКрди рдХрдВрддреНрд░рд╛рдЯрджрд╛рд░рд╛рдХрдбреЗ рдЬрд╛рдд рдирд╛рд╣реА. ЁЯУм рдкреНрд░рддреНрдпреЗрдХ рдирд╡рд╛ рдЖрд░рд╛рдЦрдбрд╛ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдЪреНрдпрд╛ рдЯреНрд░реЗрдордзреНрдпреЗ (рдПрдХ pull request) рдЬрд╛рддреЛ. рдПрдХ robot clerk ЁЯдЦ рддреЛ рдЙрдЪрд▓рддреЛ, рдзрдбрд╛ 11 рдордзреАрд▓ рдЪрд╛рд░рд╣реА рддрдкрд╛рд╕рдиреАрд╕ рдЪрд╛рд▓рд╡рддреЛ, рдЖрдгрд┐ рдХрдВрддреНрд░рд╛рдЯрджрд╛рд░рд╛рдЪреА рдпрд╛рджреА рд╕реВрдЪрдирд╛ рдлрд▓рдХрд╛рд╡рд░ рд▓рд╛рд╡рддреЛ: "рд╣рд╛ plan рдПрдХ library рдЬреЛрдбрддреЛ: рджрд░ рдорд╣рд┐рдиреНрдпрд╛рд▓рд╛ +тВ╣1200." рдПрдХ рд╡реНрдпрдХреНрддреА рддреЗ рд╡рд╛рдЪрддреЗ рдЖрдгрд┐ "рдордВрдЬреВрд░" рдореНрд╣рдгрддреЗ.
Robot рдХрдбреЗ campus рдЪреА рдХрд┐рд▓реНрд▓реА рдирд╕рддреЗ. рдлрд╛рдЯрдХрд╛рд╡рд░ рддреЛ рдПрдХ рджрд┐рд╡рд╕рд╛рдЪрд╛ pass ЁЯОл рджрд╛рдЦрд╡рддреЛ рдЬреНрдпрд╛рд╡рд░ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЕрд╕рддреЗ "рдореА campus-infra рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдЪрд╛ robot рдЖрд╣реЗ, main рд╡рд░ рдХрд╛рдо рдХрд░рддреЛ". рдкрд╣рд╛рд░реЗрдХрд░реА pass рддрдкрд╛рд╕рддреЛ рдЖрдгрд┐ рддреНрдпрд╛рд▓рд╛ рдПрдХрд╛ рддрд╛рд╕рд╛рд╕рд╛рдареА рдЖрдд рд╕реЛрдбрддреЛ. Pull request рд╡рд░ рдХрд╛рдо рдХрд░рдгрд╛рд▒реНрдпрд╛ robot рд▓рд╛ рдЕрд╕рд╛ pass рдорд┐рд│рддреЛ рдЬреЛ рдлрдХреНрдд read-only рджрд╛рд░ рдЙрдШрдбрддреЛ.
рд╢реБрдХреНрд░рд╡рд╛рд░реА рджреЛрди plans рдордВрдЬреВрд░ рд╣реЛрддрд╛рдд: #42 (рдПрдХ library) рдЖрдгрд┐ #43 (рдПрдХ gate). #43 рдЖрдзреА рдмрд╛рдВрдзрд▓рд╛ рдЬрд╛рддреЛ. #42 рдЪреА рдкрд╛рд│реА рдпреЗрддреЗ рддреЗрд╡реНрд╣рд╛ robot рдкрд╛рд╣рддреЛ рдХреА #42 рддрдкрд╛рд╕рд▓реНрдпрд╛рдирдВрддрд░ рдиреЛрдВрджрд╡рд╣реА рдмрджрд▓рд▓реА рдЖрд╣реЗ. рддреЛ рдкреБрдиреНрд╣рд╛ plan рдХрд░рддреЛ тАФ рдЖрдгрд┐ рдирд╡рд╛ plan рдирд╡реЗ gate рдкрд╛рдбреВрди рдЯрд╛рдХреЗрд▓, рдХрд╛рд░рдг gate рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдпреЗрдгреНрдпрд╛рдЖрдзреА #42 рдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛ рд▓рд┐рд╣рд┐рд▓рд╛ рдЧреЗрд▓рд╛ рд╣реЛрддрд╛. рдХреЛрдгреАрдЪ рд╣реЗ рдордВрдЬреВрд░ рдХреЗрд▓реЗ рдирд╡реНрд╣рддреЗ, рдореНрд╣рдгреВрди robot рдерд╛рдВрдмрддреЛ. рджреАрдкрд┐рдХрд╛ #42 рддрд╛рдЬреНрдпрд╛ рдЖрд░рд╛рдЦрдбреНрдпрд╛рдиреЗ update рдХрд░рддреЗ, рдирд╡рд╛ plan рдкреБрдиреНрд╣рд╛ рдлрдХреНрдд "рдПрдХ library рдЬреЛрдбрд╛" рдЕрд╕рд╛ рд╣реЛрддреЛ, рдЖрдгрд┐ рддреЛ рдкреБрдвреЗ рдЬрд╛рддреЛ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
pr["ЁЯУм pull request"] --> ci["ЁЯдЦ CI (OIDC: campus-plan, read-only)<br/>validate ┬╖ plan ┬╖ policy ┬╖ cost"]
ci --> review["ЁЯСА plan posted, reviewed"]
review --> merge["merge to main"]
merge --> ap["ЁЯдЦ CI (OIDC: campus-apply)<br/>lock ┬╖ apply the saved plan"]
ap -->|"state changed since plan"| stale["stale тЖТ re-plan"]
stale -->|"same changes"| ok["apply"]
stale -->|"different changes"| stop["stop, back to review"]
ap --> reg["ЁЯУТ remote register, locked"]
ЁЯЧ║я╕П рд░реЗрдЦрд╛рдЯрд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/terraform/lesson-diagrams.html#l12
тЭУ рдХрд╛рдп
- PR рд╡рд░ plan тАФ рдкреНрд░рддреНрдпреЗрдХ pull request
init,validate,planрдЖрдгрд┐ рддрдкрд╛рд╕рдгреНрдпрд╛ рдЪрд╛рд▓рд╡рддреЗ, рдЖрдгрд┐ plan comment рдореНрд╣рдгреВрди post рдХрд░рддреЗ. рддреЗ cloud рд╕рд╛рдареА read-only рдЕрд╕рд▓реЗрд▓реЗ credentials рд╡рд╛рдкрд░рддреЗ (plan рддрд░реАрд╣реА state рд╡рд╛рдЪрддреЛ рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ object refresh рдХрд░рддреЛ; state locking рдЕрд╕реЗрд▓ рддрд░ рддреНрдпрд╛рд▓рд╛ lock file рд╡рд░ write access рд╕реБрджреНрдзрд╛ рд▓рд╛рдЧрддреЛ, рдХрд┐рдВрд╡рд╛ рддреЛ-lock=falseрдиреЗ рдЪрд╛рд▓рд╡рд▓рд╛ рдЬрд╛рддреЛ). - Merge рд╡рд░ apply тАФ рдлрдХреНрдд
mainbranch рдЪ, CI рдордзреНрдпреЗ, apply рдХрд░реВ рд╢рдХрддреЗ. рд▓реЛрдХ laptops рд╡рд░реВрди apply рдХрд░рдд рдирд╛рд╣реАрдд. рддреНрдпрд╛рдореБрд│реЗ CI state рдЪреА рдПрдХрдореЗрд╡ рд▓рд┐рд╣рд┐рдгрд╛рд░реА рдмрдирддреЗ (рдзрдбрд╛ 08). - Saved plan тАФ
terraform plan -out=tfplanрдиреЗрдордХреНрдпрд╛ actions рдЖрдгрд┐ рдЬреНрдпрд╛ state рд╡рд░реВрди рддреЛ рдмрдирд╡рд▓рд╛ рддреА state рдиреЛрдВрджрд╡рддреЛ. рддреНрдпрд╛рдирдВрддрд░ state рдмрджрд▓рд▓реА рдЕрд╕реЗрд▓ рддрд░terraform apply tfplan"Saved plan is stale" рдореНрд╣рдгреВрди рдирдХрд╛рд░ рджреЗрддреЛ. - OIDC federation тАФ CI platform (GitHub Actions, GitLab CI, тАж) рдкреНрд░рддреНрдпреЗрдХ job рд╕рд╛рдареА signed,
рдереЛрдбрд╛ рд╡реЗрд│ рдЯрд┐рдХрдгрд╛рд░рд╛ identity token рджреЗрддреЗ. Cloud (AWS рд╕рд╛рдареА: рдПрдХ IAM OIDC identity
provider +
AssumeRoleWithWebIdentity) рддреНрдпрд╛рдЪрд╛ issuer, audience рдЖрдгрд┐ subject рддрдкрд╛рд╕рддреЗ, рдЖрдгрд┐ рддрд╛рддреНрдкреБрд░рддреА credentials рдкрд░рдд рджреЗрддреЗ (AWS рд╡рд░ default рдореНрд╣рдгреВрди 1 рддрд╛рд╕). Leak рдХрд┐рдВрд╡рд╛ rotate рдХрд░рдгреНрдпрд╛рд╕рд╛рд░рдЦреЗ long-lived рдХрд╛рд╣реАрдЪ рдирд╕рддреЗ. - Subject (
sub) claim тАФ job рдХреЛрдг рдЖрд╣реЗ рддреЗ. GitHub рдЪреА рдЙрджрд╛рд╣рд░рдгреЗ:repo:school/campus-infra:pull_request,repo:school/campus-infra:ref:refs/heads/main, рдЖрдгрд┐ GitHub environment рд╡рд╛рдкрд░рдгрд╛рд▒реНрдпрд╛ job рд╕рд╛рдареА,repo:school/campus-infra:environment:prod. рдХреЛрдгрддреЗ subjects role assume рдХрд░реВ рд╢рдХрддрд╛рдд рддреЗ role рдЪреА trust policy рдард░рд╡рддреЗ. - Orchestrators тАФ Atlantis, HCP Terraform, Spacelift, env0 рдЖрдгрд┐ рдЗрддрд░ рд╣рд╛ workflow рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА рдЪрд╛рд▓рд╡рддрд╛рдд, рдкреНрд░рддреНрдпреЗрдХ pull request рдиреБрд╕рд╛рд░ locking рдЖрдгрд┐ policy hooks рд╕рд╣.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдЖрдзреАрдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдзрдбреНрдпрд╛рдд рдЕрдкрдпрд╢рд╛рдЪрд╛ рдПрдХ рдЕрд╕рд╛ рдкреНрд░рдХрд╛рд░ рдЖрд╣реЗ рдЬреЛ рдорд╛рдгреВрд╕ рджрдбрдкрдгрд╛рдЦрд╛рд▓реА рд╡рд┐рд╕рд░рддреЛ: рди рд╡рд╛рдЪрд▓реЗрд▓рд╛ plan (03), leak рдЭрд╛рд▓реЗрд▓реА state (05), рджреЛрди рд▓рд┐рд╣рд┐рдгрд╛рд░реЗ (08), console рдордзреАрд▓ рджреБрд░реБрд╕реНрддреА (09), рдЪреБрдХреАрдЪреЗ workspace (10), рдЧрд╣рд╛рд│ tag (11). Pipeline рд╕реБрд░рдХреНрд╖рд┐рдд рдорд╛рд░реНрдЧрд╛рд▓рд╛рдЪ рдПрдХрдореЗрд╡ рдорд╛рд░реНрдЧ рдмрдирд╡рддреЗ. OIDC рдореБрд│реЗ CI рдордзрд▓реА рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рдЪреЛрд░реАрд▓рд╛ рдЬрд╛рдгрд╛рд░реА рдЧреЛрд╖реНрдЯ рдирд╛рд╣реАрд╢реА рд╣реЛрддреЗ тАФ secret рдордзрд▓реА long-lived cloud access key. рдЖрдгрд┐ apply рд╣реЛрдгрд╛рд░рд╛ plan рд╣рд╛рдЪ review рдЭрд╛рд▓реЗрд▓рд╛ plan рдЖрд╣реЗ рд╣реЗ рддрдкрд╛рд╕рд▓реНрдпрд╛рдиреЗ "рдордВрдЬреВрд░" рдЖрдгрд┐ "рдкреВрд░реНрдг" рдпрд╛рдВрдЪреНрдпрд╛рддреАрд▓ рдлрдЯ рдмрдВрдж рд╣реЛрддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
iac/checks.py рдордзреАрд▓ oidc_token(repo, event) GitHub Actions token рдордзреНрдпреЗ
рдЕрд╕рдгрд╛рд░реЗ claims (iss, aud, sub) рддрдпрд╛рд░ рдХрд░рддреЗ. assume(role, token) рддреЗ
ROLES рд╢реА shell-style matching рдиреЗ рддрдкрд╛рд╕рддреЗ, StringLike рдЕрд╕рд▓реЗрд▓реНрдпрд╛ IAM trust policy рд╕рд╛рд░рдЦреЗ.
pr_pipeline() validate тЖТ plan тЖТ policy тЖТ cost рдЪрд╛рд▓рд╡рддреЗ рдЖрдгрд┐ saved plan рдкрд░рдд рджреЗрддреЗ.
merge_pipeline() lock рдШреЗрддреЗ, saved plan apply рдХрд░рддреЗ, рдЖрдгрд┐ StalePlan рдЖрд▓рд╛ рддрд░ рдкреБрдиреНрд╣рд╛ plan рдХрд░рддреЗ
рдЖрдгрд┐ рдирд╡рд╛ plan рддреЗрдЪ рдмрджрд▓ рдХрд░рдд рдЕрд╕реЗрд▓ рддрд░рдЪ apply рдХрд░рддреЗ. iac/engine.py рдордзреАрд▓
apply() backend рдЪрд╛ serial рдХрд┐рдВрд╡рд╛ lineage plan рдкреЗрдХреНрд╖рд╛ рд╡реЗрдЧрд│рд╛ рдЕрд╕реЗрд▓ рддреЗрд╡реНрд╣рд╛ StalePlan рдЙрдард╡рддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 iac/demo.py pipeline
python3 - <<'EOF'
import sys; sys.path.insert(0, "iac")
from checks import oidc_token, assume
for event, ref in (("push", "refs/heads/main"), ("push", "refs/heads/feature-gym"), ("pull_request", None)):
t = oidc_token("school/campus-infra", event, ref)
print(f"{t['sub']:<52} тЖТ {assume('campus-apply', t)}")
t = oidc_token("someone/other-repo", "push")
print(f"{t['sub']:<52} тЖТ {assume('campus-plan', t)}")
EOF
python3 iac/test_iac.py
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
pipeline рд╣реЗ рдЫрд╛рдкрддреЗ:
тЖТ campus-apply: AccessDenied тАФ sub 'repo:school/campus-infra:pull_request' does not match
PR #42: plan (state serial 1) тЖТ Plan: 1 to add, 0 to change, 0 to destroy.
PR #42: cost тЖТ тВ╣1200/month тЖТ тВ╣2400/month (+1200)
merge #43: Apply complete! Resources: 1 added, 0 changed, 0 destroyed. (state serial 2)
merge #42: Saved plan is stale: the state was changed by another operation after the plan was created.
merge #42: re-plan (state serial 2) тЖТ Plan: 1 to add, 0 to change, 1 to destroy.
merge #42: the new plan is NOT the plan that was reviewed тЖТ stop, nothing applied
PR #42 (rebased on main): plan (state serial 2) тЖТ Plan: 1 to add, 0 to change, 0 to destroy.
merge #42: Apply complete! Resources: 1 added, 0 changed, 0 destroyed. (state serial 3)
тФАтФА main = campus: register serial 3 ┬╖ 3 resources ┬╖ campus 3 objects
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
repo:school/campus-infra:ref:refs/heads/main тЖТ campus-apply: granted, read-write (apply), session 3600 s
repo:school/campus-infra:ref:refs/heads/feature-gym тЖТ campus-apply: AccessDenied тАФ sub 'repo:school/campus-infra:ref:refs/heads/feature-gym' does not match
repo:school/campus-infra:pull_request тЖТ campus-apply: AccessDenied тАФ sub 'repo:school/campus-infra:pull_request' does not match
repo:someone/other-repo:ref:refs/heads/main тЖТ campus-plan: AccessDenied тАФ sub 'repo:someone/other-repo:ref:refs/heads/main' does not match
Tests 12/12 passed рдиреЗ рд╕рдВрдкрддрд╛рдд.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рдлрдХреНрдд рдпреЛрдЧреНрдп repository рдЪреА main рдЪ apply role assume рдХрд░реВ рд╢рдХрд▓реА; feature branch,
pull request рдЖрдгрд┐ рджреБрд╕рд░реА repository рдХрд░реВ рд╢рдХрд▓реА рдирд╛рд╣реА. рджреЛрди рдордВрдЬреВрд░ PRs рдордзреНрдпреЗ рд╢рд░реНрдпрдд рд▓рд╛рдЧрд▓реА: рджреБрд╕рд▒реНрдпрд╛рдЪрд╛
saved plan stale рдЭрд╛рд▓рд╛ рд╣реЛрддрд╛, рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ рддрд╛рдЬрд╛ plan рдкрд╣рд┐рд▓реНрдпрд╛рдЪреЗ gate destroy рдХрд░рдгрд╛рд░ рд╣реЛрддрд╛
тАФ рдореНрд╣рдгреВрди рдХреЛрдгреАрд╣реА review рди рдХреЗрд▓реЗрд▓реЗ рдХрд╛рд╣реАрддрд░реА apply рдХрд░рдгреНрдпрд╛рдРрд╡рдЬреА pipeline рдерд╛рдВрдмрд▓реА.
Rebase рдирдВрддрд░ plan рдкреБрдиреНрд╣рд╛ review рдЭрд╛рд▓реЗрд▓рд╛рдЪ рдЭрд╛рд▓рд╛, рдЖрдгрд┐ main, рдиреЛрдВрджрд╡рд╣реА (3 resources, serial
3) рдЖрдгрд┐ campus (3 objects) рдпрд╛ рд╕рдЧрд│реНрдпрд╛рдВрдЪреЗ рдПрдХрдордд рдЖрд╣реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- CI secrets рдордзреНрдпреЗ "рд╕рдзреНрдпрд╛рдкреБрд░рддреА" рдареЗрд╡рд▓реЗрд▓реА long-lived
AWS_ACCESS_KEY_ID sub=repo:school/*рдХрд┐рдВрд╡рд╛ рдлрдХреНрддaudрддрдкрд╛рд╕рдгрд╛рд░реА trust policy тАФ org рдордзрд▓реА рдХреЛрдгрддреАрд╣реА branch, рдХреЛрдгрддреАрд╣реА repo рддреА assume рдХрд░реВ рд╢рдХрддреЗ- apply job рд╕рд╛рд░рдЦрд╛рдЪ read-write role рд╡рд╛рдкрд░рдгрд╛рд░рд╛ plan job
- merge рдЪреНрдпрд╛ рд╡реЗрд│реА рдкреБрдиреНрд╣рд╛ plan рдХрд░рдгреЗ рдЖрдгрд┐ review рдЭрд╛рд▓реЗрд▓реНрдпрд╛ plan рд╢реА рддреБрд▓рдирд╛ рди рдХрд░рддрд╛ рдЬреЗ рдирд┐рдШреЗрд▓ рддреЗ apply рдХрд░рдгреЗ
- "рдЖрдгреАрдмрд╛рдгреАрд╕рд╛рдареА" console рдЖрдгрд┐ laptop applies рдЕрдЬреВрдирд╣реА рдЪрд╛рд▓реВ рдареЗрд╡рдгреЗ, рдЖрдгрд┐ рддреЗ рдкрд░рдд рд▓рд┐рд╣рд┐рдгреНрдпрд╛рдЪрд╛ рдХреЛрдгрддрд╛рд╣реА рдирд┐рдпрдо рдирд╕рдгреЗ (рдзрдбрд╛ 09)
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ AWS рдХрдбреЗ OIDC рд╕рд╣ GitHub Actions. Apply job prod рдирд╛рд╡рд╛рдЪреЗ GitHub
environment рд╡рд╛рдкрд░рддреЛ (рдЬреНрдпрд╛рд▓рд╛ reviewer рдЖрд╡рд╢реНрдпрдХ рдХрд░рддрд╛ рдпреЗрддреЛ), рдореНрд╣рдгреВрди рддреНрдпрд╛рдЪрд╛ sub
repo:school/campus-infra:environment:prod рдЕрд╕рддреЛ:
name: terraform
on:
pull_request:
push:
branches: [main]
permissions:
id-token: write # allow the job to request an OIDC token
contents: read
pull-requests: write # to comment the plan
jobs:
plan:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::111122223333:role/campus-plan
aws-region: ap-south-1
- run: terraform init -input=false
- run: terraform validate
- run: terraform plan -input=false -out=tfplan
apply:
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment: prod
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::111122223333:role/campus-apply
aws-region: ap-south-1
- run: terraform init -input=false
- run: terraform plan -input=false -out=tfplan
- run: terraform apply -input=false tfplan
Apply role рдЪреА trust policy:
{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:school/campus-infra:environment:prod"
}
}
}
рд╣рд╛ workflow merge рд╡рд░ рдкреБрдиреНрд╣рд╛ plan рдХрд░рддреЛ рдЖрдгрд┐ рддреЛ plan apply рдХрд░рддреЛ. review рдЭрд╛рд▓реЗрд▓рд╛ plan рдиреЗрдордХрд╛ apply
рдХрд░рд╛рдпрдЪрд╛ рдЕрд╕реЗрд▓, рддрд░ PR рдЪрд╛ tfplan artifact рдореНрд╣рдгреВрди рдареЗрд╡рд╛ рдЖрдгрд┐ рддреЛрдЪ apply рдХрд░рд╛ (stale рдЕрд╕реЗрд▓ рддрд░ Terraform
рддреЛ рдирд╛рдХрд╛рд░рддреЗ), рдХрд┐рдВрд╡рд╛ merge рдЖрдзреАрдЪ pull request рдордзреВрди apply рдХрд░рдгрд╛рд░реЗ Atlantis рд╕рд╛рд░рдЦреЗ tool рд╡рд╛рдкрд░рд╛.
CI/CD рд╢рд╛рд│рд╛ рдЖрдгрд┐
IAM рд╢рд╛рд│рд╛ pipelines рдЖрдгрд┐
trust policies рдмрджреНрджрд▓ рдЕрдзрд┐рдХ рдЦреЛрд▓рд╛рдд рдЬрд╛рддрд╛рдд.
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдЖрд╣реЗ: рддреБрдордЪреНрдпрд╛ CI secrets рдордзреНрдпреЗ cloud access keys рд╢реЛрдзрд╛. рдкреНрд░рддреНрдпреЗрдХ key рдЪреНрдпрд╛ рдЬрд╛рдЧреА рдЕрд╕рд╛ OIDC role рдареЗрд╡рд╛ рдЬреНрдпрд╛рдЪреА trust policy рдПрдХ repository рдЖрдгрд┐ рдПрдХ branch рдХрд┐рдВрд╡рд╛ environment рдирдореВрдж рдХрд░рддреЗ тАФ рдЖрдгрд┐ plan job рд▓рд╛ read-only role рджреНрдпрд╛.
ЁЯОУ рдЖрд░рд╛рдЦрдбрд╛ рдкреВрд░реНрдг рдЭрд╛рд▓рд╛
Clicks рдкреБрдиреНрд╣рд╛ рдХрд░рддрд╛ рдпреЗрдд рдирд╛рд╣реАрдд, рдЖрд░рд╛рдЦрдбрд╛ рдХрд░рддрд╛ рдпреЗрддреЛ тЖТ provider рдЪреЗ schema рд╕рд╛рдВрдЧрддреЗ рдХреА рдЖрд░рд╛рдЦрдбреНрдпрд╛рдд рдХрд╛рдп рд▓рд┐рд╣рд┐рддрд╛ рдпреЗрддреЗ
тЖТ plan рдлрдХреНрдд рдлрд░рдХ рдмрд╛рдВрдзрддреЛ, рдЖрдгрд┐ ForceNew рдореНрд╣рдгрдЬреЗ рдкреБрдирд░реНрдмрд╛рдВрдзрдгреА тЖТ variables рдЖрдгрд┐
for_each рдореБрд│реЗ рдПрдХ design рдЕрдиреЗрдХ рдЦреЛрд▓реНрдпрд╛рдВрдирд╛ рдмрд╕рддреЗ тЖТ рдиреЛрдВрджрд╡рд╣реА рдкреНрд░рддреНрдпреЗрдХ address рдПрдХрд╛ рдЦрд▒реНрдпрд╛
object рд╢реА рдЬреЛрдбрддреЗ, secrets рд╕рдХрдЯ тЖТ graph рдХрд╛рдорд╛рдЪрд╛ рдХреНрд░рдо рдард░рд╡рддреЛ рдЖрдгрд┐ рддреЗ parallel рдЪрд╛рд▓рд╡рддреЛ тЖТ modules
рдПрдХрд╛ pattern рд▓рд╛ рдПрдХрд╛ review рдЭрд╛рд▓реЗрд▓реНрдпрд╛ рдЧреЛрд╖реНрдЯреАрдд рдмрджрд▓рддрд╛рдд тЖТ рдПрдХ remote рдиреЛрдВрджрд╡рд╣реА, рдПрдХрд╛ рд╡реЗрд│реА рдПрдХрдЪ рд▓рд┐рд╣рд┐рдгрд╛рд░рд╛ тЖТ
refresh drift рд╢реЛрдзрддреЛ, import рдЖрдгрд┐ moved рдиреЛрдВрджрд╡рд╣реА рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдареЗрд╡рддрд╛рдд тЖТ environments рдирд╛
рд╕реНрд╡рддрдГрдЪреА state рдЖрдгрд┐ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ keys рдорд┐рд│рддрд╛рдд тЖТ рдХрдВрддреНрд░рд╛рдЯрджрд╛рд░рд╛рдЪреНрдпрд╛ рдЖрдзреА рддрдкрд╛рд╕рдиреАрд╕ plan рд╡рд╛рдЪрддрд╛рдд
тЖТ рдЖрдгрд┐ pipeline review рдЭрд╛рд▓реЗрд▓реНрдпрд╛ plan рд▓рд╛рдЪ рдЖрдд рдЬрд╛рдгреНрдпрд╛рдЪрд╛ рдПрдХрдореЗрд╡ рдорд╛рд░реНрдЧ рдмрдирд╡рддреЗ.
рддреБрдореНрд╣реА рдлрдХреНрдд Terraform рд╢рд┐рдХрд▓рд╛ рдирд╛рд╣реАрдд тАФ рдЖрддрд╛ рддреБрдореНрд╣реА рдХреЛрдгрддрд╛рд╣реА cloud рдкрд╛рд╣реВрди рдпреЛрдЧреНрдп
рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░реВ рд╢рдХрддрд╛: рддреНрдпрд╛рдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛ рдХреБрдареЗ рдЖрд╣реЗ, рддреНрдпрд╛рдЪреА рдиреЛрдВрджрд╡рд╣реА рдХреБрдареЗ рдЖрд╣реЗ, apply рдХреЛрдг рдХрд░реВ рд╢рдХрддреЗ, рдЖрдгрд┐
рддреНрдпрд╛рдВрдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░ рдХрд╛рдп рдмрджрд▓рд▓реЗ? ЁЯУЬЁЯС╖ЁЯОУ
тПня╕П рдкреБрдвреЗ
рдЗрддрд░ рд╢рд╛рд│рд╛. AWS рд╢рд╛рд│рд╛ рд╣рд╛ campus рдЖрд╣реЗ рдЬреЛ рд╣реЗ рдЖрд░рд╛рдЦрдбреЗ рд╕рд╣рд╕рд╛ рдмрд╛рдВрдзрддрд╛рдд; CI/CD рд╢рд╛рд│рд╛ conveyor belt рдЪрд╛рд▓рд╡рддреЗ; IAM рд╢рд╛рд│рд╛ trust policies рд▓рд┐рд╣рд┐рддреЗ; Argo CD рд╢рд╛рд│рд╛ рддреАрдЪ "desired state in git" рдХрд▓реНрдкрдирд╛ Kubernetes рдордзреНрдпреЗ рд▓рд╛рдЧреВ рдХрд░рддреЗ; рдЖрдгрд┐ School portal рдордзреНрдпреЗ рдмрд╛рдХреА рд╕рдЧрд│реЗ рдЖрд╣реЗ.
git checkout main
python3 iac/demo.py # one last run, for fun