Infrastruktura jako kod z agentami AI
Infrastruktura jako kod z agentami AI działa wtedy, gdy agent pisze i planuje zmianę, ale nigdy jej nie aplikuje. Claude Code, Codex lub Cursor tworzą Terraform, CloudFormation, CDK albo Pulumi na podstawie aktualnych schematów dostawców; deterministyczne bramki, maszynowo czytany plan i cykliczna kontrola dryfu dowodzą wyniku, a CI aplikuje zmianę po akceptacji planu przez wskazanego właściciela.
Dziedziczysz repozytorium Terraform bez dokumentacji, inżynier platformy, który je napisał, już odszedł, a replikę odczytu w drugim regionie trzeba mieć do piątku. Agent przeczyta moduły i napisze zmianę w kilka minut. Ryzyko kryje się gdzie indziej: w argumencie dostawcy wymyślonym na podstawie nieaktualnych danych treningowych, w zmianie nazwy, którą plan zamienia w destroy, albo w agencie z twoim profilem administratora, który uruchamia terraform apply, bo w prompcie padło „wdróż to”.
Ta strona jest dla deweloperów, którzy zmieniają infrastrukturę z pomocą agenta, i dla tech leadów, którzy decydują, czego agent może dotykać.
Co daje przepływ IaC prowadzony przez agenta
Dział zatytułowany „Co daje przepływ IaC prowadzony przez agenta”- Podział pracy, w którym agent pisze i planuje, CI aplikuje, a człowiek akceptuje plan zamiast czytać każdą linię HCL.
- Zabezpieczenia dla wszystkich trzech narzędzi: tożsamość chmurową tylko do odczytu, instrukcje w repozytorium i reguły poleceń blokujące
applyidestroy. - Konfigurację MCP i skilli, która opiera odpowiedzi agenta na aktualnym Terraform Registry i dokumentacji AWS IaC, razem z nazwami pakietów, które są błędne.
- Zestaw bramek dla każdego narzędzia IaC (Terraform lub OpenTofu, CloudFormation, CDK, Pulumi), uruchamianych, zanim ktokolwiek spojrzy na zmianę.
- Cztery prompty do skopiowania: brief z ograniczeniami, zmianę za bramkami, podsumowanie planu dla recenzenta i triaż dryfu.
- Kroki naprawcze dla blokad stanu, rozjechanych wersji dostawcy, ukrytych zastąpień zasobów i dryfu.
Kto co robi: agent planuje, CI aplikuje
Dział zatytułowany „Kto co robi: agent planuje, CI aplikuje”Szybkość agenta jest bezpieczna tylko wtedy, gdy niebezpieczne kroki są poza jego zasięgiem. Ustal podział przed pierwszym promptem:
| Krok | Agent | CI | Człowiek |
|---|---|---|---|
| Czytanie repozytorium, sprawdzanie schematów dostawcy | Tak | ||
| Pisanie HCL, szablonów albo kodu CDK/Pulumi | Tak | ||
fmt, validate, linter, skan bezpieczeństwa, testy | Uruchamia lokalnie | Uruchamia ponownie jako bramkę | |
plan / preview / synth | Lokalnie, z tożsamością tylko do odczytu | Wiążący plan na pull requeście | |
| Podsumowanie planu i oznaczenie usunięć | Tak | Przerywa build przy niezatwierdzonych usunięciach | Porównuje podsumowanie z planem |
apply / up / deploy | Nigdy | Po akceptacji, z zapisanego planu | Akceptuje; odpowiada za rollback |
Operacje na stanie (force-unlock, state rm) | Nigdy bez pytania | Decyduje |
Akceptuje właściciel zmienianego workspace’u lub stacka, a nie autor promptu. Akceptacja dotyczy planu (tego, co zmieni się w chmurze), który jest mniejszym i uczciwszym artefaktem niż diff.
Ustaw zabezpieczenia przed pierwszym promptem
Dział zatytułowany „Ustaw zabezpieczenia przed pierwszym promptem”-
Daj agentowi tożsamość tylko do odczytu. Utwórz w chmurze rolę lub profil, który może czytać zasoby i stan, ale nie może ich zmieniać, i niech to będzie jedyne poświadczenie w środowisku, w którym działa agent. Żadnego produkcyjnego profilu administratora, żadnego długowiecznego klucza do wdrożeń na tej maszynie. W AWS do planowania wystarczy rola z zarządzaną polityką
ReadOnlyAccessplus dostęp do bucketu ze stanem (przyuse_lockfileplan zapisuje też obiekt blokady obok stanu). Tę samą konfigurację dla AWS, Azure i Google Cloud opisuje strona o serwerach MCP chmury z tożsamościami tylko do odczytu. -
Zapisz reguły w instrukcjach repozytorium. Umieść je w
AGENTS.mddla Codeksa, wCLAUDE.mddla Claude Code (który sięga poAGENTS.mdtylko wtedy, gdy nie maCLAUDE.md, od v2.1.277 w kanalelatest) i w regule projektu w katalogu.cursor/rules/dla Cursora (format pliku i frontmatter opisuje strona o regułach projektu w Cursorze):## Infrastructure rules- Never run terraform apply, destroy, import or force-unlock, pulumi up or destroy, or cdk deploy. CI applies.- Before writing a resource, look up its arguments for the provider version pinned in versions.tf.- Every change must pass: terraform fmt -check, terraform validate, tflint, trivy config, terraform test.- Renaming or moving a resource requires a moved block. A plan with an unexplained replace is a failed change.- No wildcard IAM actions, no 0.0.0.0/0 ingress, encryption at rest on every storage resource. -
Wzmocnij instrukcje regułami poleceń. Instrukcje można zignorować, reguł poleceń nie. Każde narzędzie robi to inaczej:
W
.claude/settings.json:{"permissions": {"deny": ["Bash(terraform apply)","Bash(terraform apply *)","Bash(terraform destroy *)","Bash(terraform import *)","Bash(terraform force-unlock *)","Bash(tofu apply)","Bash(tofu apply *)","Bash(tofu destroy *)","Bash(tofu import *)","Bash(tofu force-unlock *)","Bash(pulumi up)","Bash(pulumi up *)","Bash(pulumi destroy *)","Bash(cdk deploy)","Bash(cdk deploy *)","Bash(cdk destroy *)","Bash(npx cdk deploy)","Bash(npx cdk deploy *)","Bash(npx cdk destroy *)"],"ask": ["Bash(terraform state rm *)","Bash(terraform state mv *)","Bash(terraform state push *)","Bash(tofu state rm *)","Bash(tofu state mv *)","Bash(tofu state push *)"]}}Lista zawiera zarówno samo polecenie (
terraform apply), jak i formę z argumentami (terraform apply *), więc reguła nie zależy od tego, czy końcowy wildcard pasuje też do polecenia bez argumentów. Regułyasksprawiają, że Claude Code zatrzymuje się i pyta przed operacjami na stanie, tak jak regułapromptw Codeksie poniżej.W
.codex/rules/infra.rules. Przykładymatchinot_matchsą sprawdzane przy wczytywaniu pliku. Codex wczytuje reguły projektu tylko w zaufanym projekcie, acodex exec --ignore-rulesje pomija, więc nie używaj tej flagi w CI (sprawdzone w źródłach codex-cli 0.157.1 i wcodex exec --help):prefix_rule(pattern = [["terraform", "tofu"], ["apply", "destroy", "import", "force-unlock"]],decision = "forbidden",justification = "CI applies from a reviewed plan, and a human handles imports and locks. Run terraform plan instead.",match = ["terraform apply tfplan", "tofu destroy", "terraform force-unlock 1a2b"],not_match = ["terraform plan -out tfplan", "terraform validate"],)prefix_rule(pattern = [["terraform", "tofu"], "state", ["rm", "mv", "push"]],decision = "prompt",justification = "State surgery needs a human. Say why before you run it.",match = ["terraform state rm aws_s3_bucket.logs"],not_match = ["terraform state list", "terraform state show aws_s3_bucket.logs"],)prefix_rule(pattern = ["pulumi", ["up", "destroy"]],decision = "forbidden",justification = "CI runs pulumi up from a reviewed preview.",match = ["pulumi up --yes"],not_match = ["pulumi preview"],)prefix_rule(pattern = ["cdk", ["deploy", "destroy"]],decision = "forbidden",justification = "CI deploys and destroys stacks. Run cdk synth or cdk diff instead.",match = ["cdk deploy --all", "cdk destroy MyStack"],not_match = ["cdk synth", "cdk diff"],)prefix_rule(pattern = ["npx", "cdk", ["deploy", "destroy"]],decision = "forbidden",justification = "CI deploys and destroys stacks. Run npx cdk synth or npx cdk diff instead.",match = ["npx cdk deploy --all", "npx cdk destroy MyStack"],not_match = ["npx cdk synth", "npx cdk diff"],)Polecenie sprawdzisz bez uruchamiania sesji:
codex execpolicy check --rules .codex/rules/infra.rules terraform apply tfplanzwraca"decision":"forbidden"(sprawdzone na codex-cli 0.157.1).O tym, które polecenia terminala czekają na twoją akceptację, decydują tryby uruchamiania Cursora (Run modes), a te żyją w ustawieniach każdego programisty, nie w repo (opisuje je strona o uprawnieniach, sandboksach i trybach akceptacji). Hooki Cursora potrafią obserwować i blokować etapy pętli agenta (zobacz dokumentację hooków Cursora), więc hook projektu może odrzucić
terraform apply. Zanim zaczniesz na nim polegać, sprawdź w aktualnej dokumentacji nazwę zdarzenia dla wykonania polecenia powłoki. Tak czy inaczej kontrolą jest tożsamość tylko do odczytu z kroku 1: niech będzie jedynym poświadczeniem chmurowym w powłoce, z której startuje Cursor.
Oprzyj agenta na aktualnych schematach dostawców
Dział zatytułowany „Oprzyj agenta na aktualnych schematach dostawców”Modele piszą argumenty dostawców z danych treningowych, które nie nadążają za dostawcami. Dostawca AWS dla Terraform był we wrześniu 2026 na linii 6.x, zgodnie z jego changelogiem; model, który wpisuje ~> 5.0, zgaduje. Większość tego problemu usuwa serwer MCP czytający registry plus skille od producenta.
| Stos | Na czym go oprzeć | Co to daje |
|---|---|---|
| Terraform / OpenTofu | Serwer MCP Terraform od HashiCorp (obraz Dockera hashicorp/terraform-mcp-server) | Zapytania do registry: wersje dostawców, dokumentacja zasobów, moduły. Workspace’y HCP Terraform z tokenem |
| Styl Terraform | Skille HashiCorp (hashicorp/agent-skills) | terraform-style-guide, terraform-test, refactor-module, terraform-search-import |
| CloudFormation / CDK | awslabs.aws-iac-mcp-server (PyPI) | Walidacja cfn-lint, zgodność cfn-guard, diagnoza nieudanych stacków, dokumentacja i przykłady CDK |
| Pulumi | @pulumi/mcp-server (npm 0.2.0, ostatnia publikacja 2025-09) | Zapytania do registry, preview, refresh. Udostępnia też pulumi-cli-up i deploy-to-aws (zwraca instrukcje, które kierują agenta do tworzenia zasobów AWS; oba sprawdzone w pakiecie 0.2.0), a reguły poleceń powłoki nie łapią żadnego z nich: zablokuj same narzędzia (w Claude Code dodaj mcp__pulumi__pulumi-cli-up i mcp__pulumi__deploy-to-aws do permissions.deny, o ile serwer zarejestrowano pod nazwą pulumi, na przykład przez claude mcp add pulumi -- npx @pulumi/mcp-server@0.2.0 stdio; prefiks to mcp__<nazwa-serwera>__) albo nie rejestruj serwera i oprzyj się na tożsamości tylko do odczytu, która blokuje je w obu przypadkach |
| Odczyty z żywego AWS | Agent Toolkit for AWS | Odczyty konta przez zarządzany AWS MCP Server |
Zarejestruj dwa serwery, których potrzebuje większość pracy z IaC:
# Terminal, root repozytorium. Serwer Terraform tylko z registry, przypięty obrazclaude mcp add terraform -s project -- docker run -i --rm hashicorp/terraform-mcp-server:1.3.0
# Walidacja CloudFormation i CDK; poświadczenia z profilu tylko do odczytuclaude mcp add aws-iac -s project -e AWS_PROFILE=agent-readonly -- uvx awslabs.aws-iac-mcp-server@latest
claude mcp listcodex mcp add terraform -- docker run -i --rm hashicorp/terraform-mcp-server:1.3.0codex mcp add aws-iac --env AWS_PROFILE=agent-readonly -- uvx awslabs.aws-iac-mcp-server@latestcodex mcp listOba wpisy trafiają do [mcp_servers.*] w ~/.codex/config.toml.
W .cursor/mcp.json:
{ "mcpServers": { "terraform": { "command": "docker", "args": ["run", "-i", "--rm", "hashicorp/terraform-mcp-server:1.3.0"] }, "aws-iac": { "command": "uvx", "args": ["awslabs.aws-iac-mcp-server@latest"], "env": { "AWS_PROFILE": "agent-readonly" } } }}Skille HashiCorp dodasz w Claude Code poleceniem claude plugin marketplace add hashicorp/agent-skills, a potem claude plugin install terraform@hashicorp; w pozostałych narzędziach instaluj je pojedynczo, na przykład npx skills add hashicorp/agent-skills/plugins/terraform/skills/terraform-style-guide. Konfigurację tokena HCP Terraform, listy dozwolonych narzędzi i koszt kontekstu każdego serwera opisuje strona MCP dla infrastruktury: Docker, Kubernetes i Terraform.
Opisz zmianę ograniczeniami, nie zasobami
Dział zatytułowany „Opisz zmianę ograniczeniami, nie zasobami”„Utwórz klaster EKS z trzema węzłami” daje generyczny klaster. Opisz ograniczenia biznesowe i poproś agenta, żeby przed napisaniem kodu wymienił swoje założenia. Ten prompt działa tak samo we wszystkich trzech narzędziach.
Punkt 4 jest tu najważniejszy. Wyciąga miejsca, w których agent zgaduje (czy baza źródłowa jest szyfrowana kluczem, który da się współdzielić między regionami? czy budżet jest miesięczny, czy na środowisko?), dopóki korekta kursu kosztuje jedną wiadomość. Punkt 5 zmusza agenta do przemyślenia zasięgu skutków, zanim czegokolwiek dotknie.
Wygeneruj zmianę za zestawem bramek
Dział zatytułowany „Wygeneruj zmianę za zestawem bramek”Niech agent napisze zmianę i uruchamia każde deterministyczne sprawdzenie, dopóki wszystkie nie przejdą. Decydują kody wyjścia, a nie relacja agenta o nich.
| Stos | Bramki, które uruchamia agent i powtarza CI |
|---|---|
| Terraform | terraform fmt -check -recursive · terraform validate · tflint --recursive · trivy config . lub checkov -d . · terraform test |
| OpenTofu | To samo z tofu zamiast terraform |
| CloudFormation | cfn-lint template.yaml · cfn-guard validate -d template.yaml -r rules/ |
| CDK | cdk synth z zarejestrowanym cdk-nag, tak aby problemy bezpieczeństwa przerywały synth |
| Pulumi | pulumi preview --policy-pack ./policy z pakietem polityk CrossGuard |
W CDK cdk-nag 3.x rejestruje się jako plugin walidacji: Validations.of(app).addPlugins(new AwsSolutionsChecks(app)); w punkcie wejścia aplikacji.
Moduł główny (root module) z aktualnymi wersjami przypina to, co modele najczęściej psują:
terraform { required_version = ">= 1.11" required_providers { aws = { source = "hashicorp/aws" version = "~> 6.0" } }
backend "s3" { bucket = "acme-tf-state-prod" key = "platform/terraform.tfstate" region = "us-east-1" encrypt = true use_lockfile = true # natywne blokowanie w S3; nowy projekt nie potrzebuje tabeli blokad w DynamoDB }}Skanery bezpieczeństwa zgłaszają za dużo (WAF wymagany na wewnętrznym load balancerze), a agent za mało (akcja IAM z wildcardem, którą sam napisał). Skaner zostaw jako bramkę, a każde wyciszenie traktuj jako przejrzaną linię w konfiguracji skanera z uzasadnieniem, nigdy jako ciche pominięcie, które agent dodaje, żeby build zrobił się zielony.
Zrób z planu artefakt do code review
Dział zatytułowany „Zrób z planu artefakt do code review”Recenzent nie czyta HCL linia po linii. Czyta plan, który mówi, co stanie się w chmurze, a CI pilnuje, żeby w planie nie było niespodzianki, której recenzent nie zatwierdził.
-
Zapisz plan jako JSON w CI. Job działa z rolą, która może tylko planować i nie sięga dalej niż odczyt stanu i zasobów oraz zapis obiektu blokady:
Okno terminala terraform plan -out tfplanterraform show -json tfplan > plan.jsonPlan wykonuje kod z pull requesta: binaria dostawców, programy
data "external"i źródła modułów. Dlatego job planu z poświadczeniami uruchamiaj tylko dla gałęzi z tego samego repozytorium, na wyzwalaczupull_request, który nie przekazuje sekretów forkom. Nigdy nie używajpull_request_targetdo checkoutu głowy pull requesta. Fork kontrybutora planuj dopiero wtedy, gdy maintainer przeczyta zmianę i wypchnie ją na gałąź w tym repozytorium, albo wcale: etykieta, która uruchamia plan z poświadczeniami na głowie forka, wykonuje kod forka z rolą planu. -
Przerwij build przy każdym niezadeklarowanym usunięciu lub zastąpieniu. Zastąpienie pojawia się w
resource_changesjakodeletepluscreate:Okno terminala jq -r '.resource_changes[] | select(any(.change.actions[]; . == "delete")) | .address' plan.json \> deletes.txtif [ -s deletes.txt ] && ! grep -q '^allow-delete:' pr-body.txt; thenecho "Plan deletes or replaces:"; cat deletes.txt; exit 1fipr-body.txtto opis pull requesta zapisany do pliku we wcześniejszym kroku. Autor wyraża zgodę liniąallow-delete:, w której podaje adresy i powód. Jeśli pull request otworzył agent, to on napisał też opis, więc ta linia jest deklaracją, a nie zabezpieczeniem: sprawdzenie tylko uwidacznia usunięcie, a zatrzymuje je dopiero wymagana akceptacja planu przez właściciela workspace’u. Przed akceptacją właściciel porównuje każdy adres zdeletes.txtz liniąallow-delete:. Bogatsze reguły (tagi, rozmiary instancji, regiony) sprawdzisz silnikiem polityk, takim jak Conftest, na tym samymplan.json. -
Poproś agenta o podsumowanie planu dla recenzenta. Podsumowanie jest mapą, nie dowodem: recenzent porównuje je z wyjściem planu.
-
Właściciel workspace’u akceptuje, CI aplikuje zapisany plan. CI uruchamia
terraform apply tfplanz tego samego pliku planu, więc wykonuje się dokładnie to, co zaakceptowano. Rollback to revert pull requesta i ten sam pipeline; operacje na stanie zostają przy właścicielu.
To infrastrukturalna wersja pakietu dowodów, który musi nieść pull request agenta: kody wyjścia bramek, zapisany plan, kontrola usunięć i podsumowanie. Jak recenzent przechodzi przez ten pakiet bez czytania każdej linii, opisuje strona o code review PR-a agenta, a podłączenie jobów do pipeline’u — strona o automatyzacji pipeline’ów z AI.
Wykrywaj dryf cyklicznie i rób jego triaż z agentem
Dział zatytułowany „Wykrywaj dryf cyklicznie i rób jego triaż z agentem”Dryf (poprawka wyklikana w konsoli, ręcznie dodana reguła security group) to miejsce, w którym kod infrastruktury po cichu przestaje być prawdą. Wykrywaj go samym narzędziem IaC według harmonogramu, a potem daj wynik agentowi do triażu. Wykrywanie jest deterministyczne; agent tylko porządkuje i wyjaśnia.
# Kod wyjścia 2 oznacza, że prawdziwa infrastruktura różni się od stanuterraform plan -refresh-only -detailed-exitcode -out drift.tfplanterraform show -json drift.tfplan > drift.jsonID=$(aws cloudformation detect-stack-drift --stack-name db-cluster-prod \ --query StackDriftDetectionId --output text)# Odpytuj, aż DetectionStatus będzie DETECTION_COMPLETEaws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id "$ID"aws cloudformation describe-stack-resource-drifts --stack-name db-cluster-prod \ --stack-resource-drift-status-filters MODIFIED DELETED > drift.json# Pokazuje, co odświeżenie zmieniłoby w stanie, bez zapisywaniapulumi refresh --preview-only --stack prodZanim zadziałasz na podstawie znaleziska, potwierdź dwie rzeczy, których agent nie wie: że wartość „oczekiwana” odpowiada kodowi na domyślnej gałęzi, a nie staremu planowi, i że ręczna zmiana nie była nieudokumentowaną poprawką zrobioną podczas incydentu. Zapytaj właściciela stacka; wybrana naprawa przechodzi potem przez ten sam pull request i przegląd planu co każda inna zmiana.
Co się psuje, gdy agenci piszą kod infrastruktury?
Dział zatytułowany „Co się psuje, gdy agenci piszą kod infrastruktury?”terraform apply w CI wisi na „Acquiring state lock”. Dwa uruchomienia nałożyły się na siebie albo wcześniejsze padło w trakcie apply. Najpierw odczytaj z komunikatu, kto trzyma blokadę i od kiedy. terraform force-unlock LOCK_ID uruchom dopiero wtedy, gdy potwierdzisz, że tamten proces nie żyje; odblokowanie trwającego apply może uszkodzić stan. Nakładanie się zatrzymasz grupą współbieżności (concurrency group) na jobie apply.
Plan zastępuje zasób, którego nikt nie chciał ruszać. Agent zmienił nazwę zasobu albo przeniósł go do modułu, więc Terraform widzi usunięcie i utworzenie. Kontrola usunięć w CI to łapie. Poproś agenta o blok moved ze starego adresu na nowy i planuj ponownie, aż zastąpienie zniknie.
terraform init pada po tym, jak agent zmienił wersję dostawcy. Plik blokady wciąż przypina starą wersję główną. Nie pozwalaj agentowi podnosić wersji głównej dostawcy w tej samej zmianie co funkcję; zrób to w osobnym pull requeście po lekturze przewodnika aktualizacji dostawcy. Uruchom terraform init -upgrade, żeby zaktualizować .terraform.lock.hcl, a potem terraform providers lock -platform=linux_amd64 -platform=darwin_arm64, żeby CI i laptopy miały te same skróty.
terraform validate odrzuca argument napisany przez agenta. Agent pominął sprawdzenie w registry albo czytał najnowszą dokumentację wobec starszego przypiętego dostawcy. Zrób ze sprawdzenia osobną turę i podaj w prompcie przypiętą wersję, jak w briefie z ograniczeniami powyżej.
Bramki przechodzą, ale zmiana jest zbyt liberalna. Generowane polityki IAM dryfują w stronę akcji z wildcardem i szerokich principali, na które wiele skanerów tylko ostrzega. Dodaj regułę polityki, która przerywa plan przy "Action": "*" i przy ruchu przychodzącym z 0.0.0.0/0, a ścieżki wrażliwe (IAM, sieć, KMS) trzymaj na liście, która zawsze wymaga akceptacji właściciela.
Serwer MCP nic nie zwraca albo zwraca stare dane. Najpierw sprawdź pakiet (zobacz ramkę z ostrzeżeniem powyżej: npm terraform-mcp-server i wycofane serwery AWS Labs to częste przyczyny), potem poświadczenia: AWS_PROFILE i region w env serwera oraz uprawnienia odczytu profilu. claude mcp list albo codex mcp list pokaże, czy serwer się połączył. Więcej w problemach z połączeniem MCP.
Hurtowy revert dryfu usuwa prawdziwą poprawkę. Ktoś otworzył port w trakcie incydentu, a revert znowu go zamyka. Nigdy nie cofaj dryfu z harmonogramu bez triażu; świeże zmiany kieruj ścieżką (c) z promptu o dryfie.
Agent wykonuje instrukcję ukrytą w wyjściu planu lub w tagu zasobu. Wyjście planu, tagi i opisy to dane, które trafiają do modelu. Trzymaj agenta w trybie tylko do odczytu, gdy je czyta, i nie łącz w tej samej sesji serwerów z prawem zapisu. Zobacz bezpieczeństwo MCP.