Simovits

Infrastruktur som kod


Det jag tänkte berätta om i den här bloggen är ett koncept som kallas för “infrastruktur som kod”. Det är förvisso inte självskrivande dokumentation, men något som garanterar att den dokumentation som finns är korrekt.

Douglas Adams skrev i sin berömda trilogi i fem delar om jordbon Arthur Dents äventyr som intergalaktisk liftare. I en av de första kapitlen skildras en ordväxling mellan huvudpersonen och förmannen Mr. Prosser, som är i färd med att riva Arthurs hus med en bulldozer:

P: Men herr Dent, planerna på att riva ditt hus har funnits tillängliga på det lokala planeringskontoret i nio månader.

A: Javisst, de var utställda i ett låst arkivskåp, som var inställt i en avstängd toalett som i sin tur var försedd med skylten “Varning för leoparden”.

Liftarens Guide till Galaxen


Jag tror att när Arthur Dent låg där i leran framför bulldozern och pratade med Mr. Prosser kan han ha känt sig som en säkerhetskonsult. För oss säkerhetskonsulter är nämligen dokumentation en stor del av vår vardag. Läsa, tolka eller upprätta, våra uppdrag har i regel alltid att göra med dokumentation på ett eller annat sätt. Och ofta brister säkerhetsrelaterad dokumentation i riktighet och, precis som i Adams böcker, tillgänglighet.

Man kan säga att det ofta är den befintliga dokumentationens skick och beskaffenhet som avgör utfallet av av en säkerhetstestning, med andra ord om vi lyckas bryta säkerheten eller ej:

Men konfigurationsfiler och källkod, är ju faktiskt också en form av dokumentation. Och jag förstår verkligen hur dokumentationen kan bli lidande! Jag har nog aldrig träffat någon som har gillat att dokumentera, mer än kanske själva känslan av att ha den kontroll och överblick som bra dokumentation ger.



Provisioneringsverktyg

Infrastruktur som kod innebär att man upprättar beskrivningar av olika typer av resurser i textfiler och dessa lämnas till program som sätter upp den digitala miljön efter instruktionerna. Låt oss titta på ett exempel där vi bygger en server i Amazons AWS-molntjänst med hjälp av Hashicorps Terraform, ett provisioneringsverktyg som utför just detta. Terraforms konfigurationsmallar skrivs med HCL, en syntax som är väldigt lättläst även för människor.
Vi skapar en textfil, i exemplet kallat “main.tf” med följande innehåll:

provider "aws" {
	region = "eu-north-1"
}

resource "aws_key_pair" "deployer" {
	key_name = "min_nyckel"
	public_key = <MASKERAD>}

resource "aws_instance" "example" {
	ami = "ami-0653812935d0743fe"
	instance_type = "t3.micro"
	vpc_security_group_ids = [aws_security_group.instance.id]
	key_name = "min_nyckel"
	tags = {
		Name = "terraform_example"
	}
}

resource "aws_security_group" "instance" {
	ingress {
                # Tillåt SSH-åtkomst
		from_port = 22
		to_port = 22
		protocol = "tcp"
		# Ändra nätverket nedan för att begränsa åtkomst
		cidr_blocks = ["0.0.0.0/0"]
	}
}

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the web server"
}


För att skapa resursen som beskrivs i mallen ovan behöver man bara ladda hem och installera Terraform från Hashicoprs hemsida, och från samma katalog som main.tf befinner sig i köra följande kommandon:

export AWS_ACCESS_KEY_ID=<DITT ACCESS-ID>
export AWS_SECRET_ACCESS_KEY=<DIN ACCESS-NYCKEL>
terraform init
terraform apply


Observera att access-nyckeln är en känslig uppgift! Att exportera miljövariabler som i exemplet gör att de lagras i klartext i skalhistoriken.

Terraform kommer att använda ID och nyckel till AWS för att autentisera sig och därefter börja skapa den beskrivna resursen. Med hjälp av ami-beteckningen vet Terraform vilken diskavbildning som ska användas och storleken på servern, i det här fallet en t3.micro-instans med 2 CPU-kärnor och 1 GB RAM.
För att jag ska kunna logga in säkert i servern kommer Terraform att lägga in min SSH-nyckel och förbereda miljöns brandvägg att tillåta åtkomsten.

I exemplet kommer en åtkomstregel skapas för att tillåta åtkomst från hela Internet (0.0.0.0/0), men i verkligheten begränsar jag naturligtvis detta till de specifika IP-adresser jag kommer att ansluta ifrån. Det sista kodblocket är en bekvämlighetsåtgärd där jag ber Terraform att rapportera vilken publik IP-adress servern blir tilldelad efter att den har byggts färdigt.

Att använda Terraform eller motsvarande verktyg för att tillämpa infrastruktur som kod medför mest nytta för de som har en IT-miljö som inte bara är molnbaserad, utan även är molnanpassad. En verksamhet som reser och river infrastruktur efter behov vill definitivt titta på möjligheterna till att automatisera så mycket av processen som möjligt, för att undvika monotont och repetitivt arbete samt undvika mänskliga felkällor. Men även en helt lokal virtualiserad infrastruktur kan manageras på det här sättet, de flesta större provisioneringsverktygen på marknaden har stöd för hypervisor-mjukvaror såsom ESXI, Xen och Proxmox.

En nackdel med den här tillämpningen av infrastruktur som kod är att den lämpar sig mindre bra för IT-miljöer av det äldre snittet, där de digitala resurserna sätts upp och driftas kontinuerligt. Ju längre tid som går och ju fler förändringar som sker efter den initiala provisioneringen ju mindre värde får automatiseringen och standardiseringen som mallarna utgör. Infrastruktur som är helt fysisk är ovanlig i dessa tider, men skulle IT-miljön vara av den typen är den svår att provisionera med verktyg som Terraform.



Konfigurationshanteringsverktyg

Det är fortfarande möjligt att beskriva infrastrukturen i kod med konfigurationshanteringsverkyg som till exempel Salt, Ansible, Puppet och Chef, även i de fall där provisioneringsverktyg upplevs olämpliga. Konfigurationshanteringsverktygen har en del skillnader sig emellan, men gemensamt för dem är att de tar vid där lösningar som Terraform lämnar över. En server som är färdiginstallerad och grundkonfigurerad är redo att hanteras via de här verktygen.

Mitt favoritverktyg bland dessa är Salt, en lösning vars hanteringsmodell bygger på att en server får rollen som master, och alla resurser som ska hanteras (minions) genom Salt förses med en liten agentmjukvara. Det är förvisso något mer omständigt att komma igång med Salt jämfört med exempelvis Ansible, som inte kräver någon mjukvara installerad på de resurser som ska hanteras, men Salts hanteringsmodell erbjuder många fördelar som gör den lite högre tröskeln klart värd att ta sig över.

På master-servern kan därefter beskrivningar av de olika resurserna läggas upp, på Salt-språk kallat states. För exempel på hur man snabbt kan komma igång med Salt har jag länkat till Salts dokumentation[3] nedan, men här är ett enkelt exempel på hur man kan installera ett program på de hanterade servrarna genom verktyget:

nano:
  pkg.installed: []

/etc/nanorc:
  file.managed:
    - source: salt://nanorc
    - mode: 644
    - user: root
    - group: root


En Salt-master av standardutförande lagrar sina states i /srv/salt/, så om koden ovan läggs in i filen nano.sls i den katalogen kan man sedan applicera sagda state genom kommandot:

salt '*' state.apply nano


Förutom att installera nano kommer varje hanterad server att ansluta till master-servern och hämta konfigurationsfilen nanorc och placera den i /etc/nanorc på det egna filsystemet. Filen får rätt åtkomstskydd och rätt ägare i samma moment. Smidigt!


State-filer går sedan att mappa mot olika rollbeskrivningar, genom vad Salt kallar top-filer. Säg att vi definerar hur nginx och postgresql ska installeras och konfigureras i varsin state-fil, och nu vill förklara för Salt att alla webservrar ska bestyckas med mjukvarorna skapar vi följande top-fil:

base:
  '*':
    - nano

  'webserver*':
    - nginx
    - postgresql


Top-filen instruerar Salt att alla servrar i flottan skall ha nano installerat, och alla minions som har ett namn som börjar med “webserver” skall utöver nano även installera nginx och postgresql. Top-filen appliceras med:

salt '*' state.apply


Alla minions som saknar programvarorna kommer att installera dem omgående, och de som redan är provisionerade rätt kommer att återrapportera detta:

Givetvis kan provisioneringsverktyg som Terraform och konfigurationshanteringsverktyg som Salt kombineras! Se till exempel den länkade artikeln[4] för just en sådan kombination, där de bygger infrastruktur på platformen Profitbricks.



Slutord


IT-världen utvecklas fort och sättet vi bygger och hanterar våra IT-miljöer ser väldigt annorlunda ut idag mot hur det såg ut för ett decennium sedan. Att dokumentera på traditionella sätt i Microsoft Word blir snabbt ohållbart så fort verksamhetens digitala resurser blir för många.
Infrastruktur som kod ger dokumentation som är enkel att granska och verifiera vid säkerhetsgranskningar och ger en effektivare möjlighet att följa upp att rätt nivå av säkerhet har blivit uppnådd.
Det blir också mycket lättare att planera för incidenter som ransomware-angrepp, eller andra verksamhetshotande händelser. Även om bara en andel av verksamheten defineras i kod är det en andel som ni så när på minuten kan beräkna återställningstid för.

Dessutom kan all kod och alla konfigurationer versionshanteras! Det finns därför inga hinder att redan idag börja titta på hur ni kan använda infrastruktur som kod, börja i liten skala och sakta utöka omfattningen.

[1] https://en.wikipedia.org/wiki/Infrastructure_as_code
[2] https://www.terraform.io/
[3] https://docs.saltstack.com/en/master/topics/tutorials/walkthrough.html
[4] https://devops.ionos.com/tutorials/use-terraform-and-saltstack-for-provisioning-and-configuration-management/