Infrastructure as Code

IaC-grunder

En praktisk introduktion till att beskriva infrastruktur som kod, hålla state synkat och granska ändringar innan de når produktion.

Infrastructure as Code (IaC) är praxisen att definiera och hantera infrastruktur via versionshanterade, maskinläsbara konfigurationsfiler snarare än manuella processer. Det löser tre ihållande problem i infrastrukturhantering: snowflake-servrar (system som bara existerar i en ingenjörs minne), odokumenterade manuella ändringar och oreproducerbara miljöer. I DevSecOps är IaC avgörande eftersom det för infrastrukturändringar in i samma gransknings-, revisions- och testningsdisciplin som tillämpas på applikationskod.

Lärandemål

Det här ska du kunna efter genomläsning.
  • Förklara önskat tillstånd, drift, plan och apply i ett leveransflöde.
  • Beskriva hur moduler och state stödjer återanvändning och kontroll.
  • Känna igen de granskningssteg som håller miljöer förutsägbara.

I korthet

En snabb mental modell innan du går på djupet.
Modell
  • Önskat tillstånd
  • Drift
  • Plan kontra apply
Byggblock
  • Moduler
  • State
  • Miljöer
Arbetssätt
  • Granska före apply
  • Versionsstyrda ändringar
  • Tydligt ägarskap

Kärnidén

IaC-verktyg som Terraform, Pulumi och AWS CloudFormation använder en deklarativ modell. Du beskriver det önskade sluttillståndet för infrastrukturen, och verktyget beräknar de steg som behövs för att nå det tillståndet. Den deklarativa modellen innebär att samma konfiguration kan tillämpas upprepade gånger och producerar samma resultat. Detta är idempotens, och det är den egenskap som gör IaC tillförlitlig i automatiserade pipelines.

Samarbetsfördelen med IaC är betydande. När infrastruktur definieras som kod kan den granskas i en pull request som vilken annan kodändring som helst. En kollega kan fråga 'varför är denna säkerhetsgrupp öppen på port 443 till 0.0.0.0/0?' innan resursen skapas. Detta är mycket effektivare än att upptäcka felkonfigurationen i en molnsäkerhetsgranskning månader senare.

Det mentala skiftet som IaC kräver är att se manuella ändringar av infrastruktur, att klicka i molnkonsolen, som undantag som skapar teknisk skuld snarare än som normala operationer. Varje manuell ändring är en ändring som inte finns i versionskontroll, inte är granskad, inte testad och inte automatiskt reproducerbar.

IaC är särskilt kraftfullt i DevSecOps eftersom det gör det möjligt att tillämpa infrastruktursäkerhetspolicy automatiskt. Säkerhetsregler som 'all lagring måste krypteras i vila' kan uttryckas som IaC-skanningspolicyer som körs i pipelinen innan någon apply sker.

Arbetsflöde

  • Definiera infrastruktur i kod och håll den i versionskontroll tillsammans med de applikationer som beror på den.
  • Kör alltid en plan för att förhandsgranska ändringar och granska utdata innan du tillämpar. Förstå vad som kommer att skapas, modifieras eller förstöras.
  • Använd granskningsportar för högpåverkandsändringar. Varje apply som förstör resurser, modifierar åtkomstkontroller eller berör produktion bör kräva explicit godkännande.

Basnivå

  • Behandla varje manuell konsoländring som en incident som kräver en uppföljande IaC-commit för att återföra koden i synk med verkligheten.
  • Håll miljöspecifika värden i separata variabelfiler. Kärninfrastrukturlogiken bör kunna återanvändas mellan miljöer.
  • Lagra tillstånd i en fjärrstyrd, låst backend och behandla det som en känslig operativ artefakt som kräver samma åtkomstkontroller som produktionsautentiseringsuppgifter.

Signaler att bevaka

Mönster som är värda att undersöka vidare.
  • Den driftsatta miljön stämmer inte längre med koden.
  • Folk gör brådskande ändringar direkt i molnportalen.
  • Samma konfiguration beter sig olika mellan miljöer utan tydlig förklaring.

FÖRDJUPNING

Önskat tillstånd

Önskat tillstånd är målbeskrivningen av hur infrastrukturen ska se ut. Vilka resurser som ska finnas, vad deras konfiguration ska vara och hur de ska relatera till varandra. IaC är starkast när det önskade tillståndet är fullständigt specificerat i kod. När man läser repositoryt ger en fullständig bild av vad som bör köras.

Den deklarativa modellen innebär att IaC-verktyget är ansvarigt för att räkna ut hur man går från aktuellt tillstånd till önskat tillstånd. Om du lägger till en ny resursdefinition skapar Terraform den. Om du tar bort en resursdefinition förstör Terraform den. Verktyget hanterar övergångslogiken, operatören hanterar avsikten.

Skillnaden mellan Terraform (önskat tillstånd) och Ansible (procedurellt, men kan göras idempotent) återspeglar olika filosofier. Terraform modellerar explicit gapet mellan aktuellt och önskat tillstånd med hjälp av en tillståndsfil, planerar sedan och tillämpar en minimal ändringsuppsättning. Ansibles modell kör uppgifter i ordning och förlitar sig på uppgiftsidempotens.

Oföränderlig infrastruktur är en designfilosofi som utökar önskat tillstånd till dess logiska slutsats. Istället för att uppdatera en körande resurs (modifiera en servers konfiguration på plats) ersätter du den med en ny byggd från den uppdaterade definitionen. Detta eliminerar en hel klass av konfigurationsavvikelseproblem.

Avvikelse

Avvikelse är divergensen mellan vad IaC-koden säger ska finnas och vad som faktiskt finns i molnmiljön. Den kan orsakas av manuella ändringar (en ingenjör redigerar en resurs i molnkonsolen för att lösa ett brådskande problem), extern automatisering eller infrastruktur som skapades utanför IaC-arbetsflödet helt och hållet.

Avvikelse är en säkerhetsrisk eftersom det innebär att det finns infrastrukturkonfiguration som inte finns i versionskontroll, inte granskad och inte föremål för IaC-säkerhetsskanning. En säkerhetsgruppsregel som lagts till manuellt för att avblockera en specifik ingenjörs arbete kan introducera exponering som aldrig avsiktligt designades, dokumenterades eller granskades.

När avvikelse detekteras kräver svaret bedömning. Ibland är livetillståndet korrekt och koden behöver uppdateras. Ibland är koden korrekt och livetillståndet behöver återställas. Det viktiga är att beslutet fattas explicit snarare än att divergensen fortsätter på obestämd tid.

Den organisatoriska orsaken till avvikelse är vanligtvis att IaC-arbetsflödet känns långsammare eller mer besvärligt än en direkt konsoländring. Att minska avvikelse kräver både tekniska förbättringar (snabbare pipelines, tydligare dokumentation) och kulturella (behandla manuella ändringar som exceptionella snarare än normala).

Plan kontra apply

Plan-steget genererar en förhandsgranskning av de ändringar som skulle göras om konfigurationen tillämpades på det aktuella infrastrukturtillståndet. Terraforms planresultat visar varje resurs som skulle skapas (+), modifieras (~) eller förstöras (-), tillsammans med de specifika egenskapsändringar för varje modifierad resurs. Denna utdata är det primära mekanismen för mänsklig granskning innan infrastrukturändringar görs.

Att granska planresultaten är en färdighet som utvecklas med erfarenhet. Granskare bör leta efter. Oväntade resurersättningar (en modifiering som kräver att en resurs förstörs och återskapas), stora antal påverkade resurser, ändringar av säkerhetskänsliga resurser och produktionstillståndsändringar som borde ha testats i staging först.

I automatiserade CI/CD-pipelines körs plan automatiskt vid varje pull request och dess utdata publiceras som en PR-kommentar. Apply-steget körs sedan bara efter att PR:n godkänts och slagits ihop med den skyddade grenen. Denna tvåstegmodell tillämpar principen om granskning före apply även i ett fullt automatiserat arbetsflöde.

En subtil fallgrop i planbaserade arbetsflöden är att planen är en ögonblicksbild av den förväntade ändringen vid en specifik tidpunkt. Fjärrstyrd plankörning med låsfiler hanterar detta genom att säkerställa att plan och apply körs atomärt med ett tillståndslås.

Moduler

En modul är en återanvändbar enhet av IaC-konfiguration. Moduler kapslar in en uppsättning resurser och deras relationer bakom ett definierat gränssnitt. Anropare specificerar indata (variabler) och tar emot utdata utan att behöva känna till implementeringsdetaljerna. En 'vpc'-modul kan acceptera CIDR-intervallet och antalet tillgänglighetszoner, och hantera alla undernät, routningstabeller och gateways internt.

Modulversionshantering är en kritisk operativ praxis. Moduler publicerade till Terraform Registry eller ett internt artefaktlager bör vara versionshanterade med semantisk versionshantering, och anropare bör pinna till en specifik version snarare än att använda en rörlig referens. En opinnad modulreferens innebär att nästa gång Terraform initialiserar, kan det hämta en nyare version av modulen med annat beteende.

Gränssnittsdesignprincipen för moduler är. Exponera bara de indata anroparen måste kontrollera, dölj de implementeringsdetaljer som bör förbli interna. En modul som kräver att anroparen tillhandahåller dussintals lågnivåparametrar ger ingen meningsfull abstraktion. Ett väldesignat modul har ett litet, stabilt gränssnitt.

Att testa moduler kräver verktyg utöver Terraform i sig. Terratest (Go-baserat) möjliggör att skriva integrationstester som tillämpar en modul på en verklig molnmiljö och verifierar den resulterande infrastrukturen med påståenden. Investeringen i modultestning lönar sig snabbt i organisationer med många team som använder samma moduler.

Tillstånd

Terraform-tillståndsfilen är registret som kopplar resurserna definierade i kod till de verkliga resurserna i molnet. Den lagrar resurs-ID:n, konfigurationsattribut, beroenden och metadata som Terraform behöver för att korrekt beräkna vilka ändringar som behövs vid nästa apply. Utan tillståndsfilen kan Terraform inte veta vilka molnresurser det hanterar.

Tillståndsfiler innehåller känslig information. Resurs-ID:n, ARN:er, IP-adresser och ibland faktiska känsliga värden visas i tillståndet. Åtkomst till tillståndsfilen ger betydande information om infrastrukturen. Av denna anledning måste tillståndet lagras i en säker fjärrbackend, en S3-bucket med kryptering, versionshantering och begränsad åtkomst, inte i en lokal fil eller i versionskontroll.

Tillståndslåsning förhindrar att samtidiga Terraform-operationer korrumperar tillståndet. Om två personer eller två CI-jobb kör terraform apply samtidigt mot samma tillstånd kan de producera motstridiga ändringar och lämna tillståndet i ett inkonsekvent tillstånd. Fjärrbackends som stöder låsning förvärvar ett lås innan operationer som modifierar tillståndet.

Manuell tillståndsmanipulation (terraform state mv, terraform state rm, terraform import) är ibland nödvändig men alltid riskfylld. Dessa kommandon modifierar direkt tillståndsfilen på sätt som inte kan ångras med en enkel apply. Alla manuella tillståndsoperationer bör föregås av en tillståndsbackup.

Miljöer

IaC-miljöer representerar distinkta driftsättningar av samma infrastrukturkonfiguration med olika variabelvärden, åtkomstkontroller och risktoleranser. De två huvudmönstren för att hantera flera miljöer i Terraform är. Arbetsytebaserade (att använda terraform workspace för att underhålla separata tillståndsfiler för varje miljö) och katalogbaserade (separata kataloger för dev, staging och prod). Det katalogbaserade tillvägagångssättet föredras generellt för produktionsanvändning.

Variabelfiler ger miljöspecifika värden utan att ändra kärninfrastrukturlogiken. En produktionsmiljö kan använda en större instanstyp, fler tillgänglighetszoner och strängare nätverkspolicyer än utveckling. Men samma modulkonfiguration. Att hålla arkitekturen konsekvent medan man bara varierar de värden som behöver skilja sig är det ideal som gör miljöer jämförbara.

Explosionsradiesisolering mellan miljöer kräver separata tillstånd, separata molnkonton eller projekt (där möjligt) och separata åtkomstkontroller. Om utveckling och produktion delar samma molnkonto kan en dåligt avgränsad IAM-policy i utvecklingsmiljöns CI potentiellt påverka produktionsresurser.

Åtkomstkontroll för IaC-miljöer bör återspegla de olika risknivåerna. Utvecklingsmiljöer kan tillåta att utvecklare kör terraform apply direkt. Produktionsmiljöer bör endast tillämpas via CI med obligatoriska godkännanden och en skyddad grenport.

Ändringsgranskning

Att granska en IaC-ändring kräver att förstå både vad kodändringen gör och vad den resulterande planresultaten innebär. Koddiffet visar avsikt, planresultaten visar konsekvens. En granskare som bara läser koddiffet och missar att en egenskapändring kommer att orsaka att Terraform förstör och återskapar en produktionsdatabas har inte faktiskt granskat ändringen.

Automatiserad policytillämpning med verktyg som Sentinel, OPA eller Conftest ger konsistens till ändringsgranskning. Istället för att förlita sig på mänskliga granskare för att komma ihåg varje säkerhetskrav kodar policyer dessa krav som maskin-kontrollerbara regler som körs på varje planresultat.

Distinktionen mellan att granska syntax (linting) och att granska avsikt är viktig för IaC. Linting och SAST för IaC fångar formateringsproblem, föråldrad syntax och kända felkonfigurationsmönster. Avsiktsgranskning kräver att man frågar sig om det är rätt ändring? Är omfånget begränsat? Dessa frågor kräver mänskligt omdöme och domänkunskap.

Vanliga farliga mönster att leta efter i IaC-granskningar inkluderar. IAM-policyer med Action '*' eller Resource '*', säkerhetsgrupper med ingress 0.0.0.0/0 på känsliga portar, lagringsresurser med offentlig åtkomst, krypteringsinställningar satta till false och resursborttagningar utan motsvarande datamigreringsplaner.