· · 10 min leestijd Advanced

Declaratieve infrastructuur als compliance documentatie: Talos, NixOS en audit-ready systemen

Hoe declaratieve systemen zoals Talos en NixOS ISO 27001, NIS2 en SOC 2 compliance makkelijker maken door audit evidence automatisch te genereren.

Een auditor-kever met formulieren krijgt één printje uit een verzegelde machine, een kast met ordners verstoft

TL;DR Talos en NixOS booten van een bestand dat zegt wat de machine is. Dat bestand is precies wat een ISO 27001-, SOC 2- of NIS2-auditor wil zien, dus het verzamelen van bewijs krimpt tot een git log, een diff zonder output en een inventarisdump. Hieronder de mapping van config naar control, de scripts, en het deel dat gewoon werk blijft.

Een ISO 27001-audit begint weken voordat de auditor binnenstapt, met iemand die screenshots verzamelt. Configuratieschermen, firewallregels, een dashboard dat laat zien welke patches erop staan. Dan de Word-documenten die beschrijven wat de systemen geacht worden te doen. Dan de change tickets, opgediept uit het ticketsysteem, elk met een “serveronderhoud” erin dat een half jaar later niemand meer kan reconstrueren. Iedereen ziet dat als de prijs van zakendoen. Ik ook, jarenlang.

Toen draaide ik Talos en NixOS al een tijd, en één vraag van de auditor ging anders klinken. Z’n hele vak is één vraag, op twintig manieren gesteld. Bewijs dat het systeem staat zoals je zegt dat het staat. Op een declaratief systeem is dat antwoord kort. Hier is het bestand waar de node van boot.

Daar gaat deze post over. Ik koos deze systemen voor soevereiniteit en voor resilience, en de eigenschappen waarvoor ik ze koos, immutable images, reproduceerbare builds en een Git history die ik vertrouw, zijn precies de eigenschappen waar een auditor naar vist. Gepland was dat niet. Het lag er toen ik keek.

Wat auditors vragen

Strip het framework-eigen jargon weg en ISO 27001, SOC 2, NIS2 en PCI-DSS draaien allemaal om dezelfde vier vragen.

  1. Wat is je systeemconfiguratie? Assetmanagement, configuratiemanagement.
  2. Hoe beheers je wijzigingen? Changemanagement, toegangsbeheer.
  3. Kun je het bewijzen? Audit trails, bewijs.
  4. Is het consistent? Geen drift, geen ongedocumenteerde wijzigingen.

In een traditionele omgeving wordt elk van die vier met papier beantwoord. Een Word-document dat beschrijft wat er geconfigureerd hoort te zijn. Een screenshot die bewijst dat het er zo uitzag op één specifieke dinsdag. Een change ticket dat wijst naar “server updates” die wel of niet zijn gebeurd zoals het ticket beweert.

Geen van die documenten is fout op de dag dat hij geschreven wordt. Het document zegt dat automatische updates aanstaan, en dat stonden ze, tot de reorganisatie. De screenshot klopte toen hij genomen werd en zegt niks over vandaag. Wat er in de bewijsmap zit is een herinnering aan het systeem, en niemand legt die herinnering naast de machine tot de volgende audit.

Als de config de documentatie is

Draai Talos of NixOS en er is geen apart document dat kan wegdrijven, want de configuratie is het systeem. De machine weigert te booten in een andere staat dan de gedeclareerde, dus het bestand en de draaiende node kunnen niet stilletjes van elkaar afwijken.

Talos

# Dit is geen documentatie over het systeem.
# Dit IS het systeem.
machine:
  type: controlplane
  network:
    hostname: prod-control-01
  install:
    disk: /dev/sda
    image: ghcr.io/siderolabs/installer:v1.6.0
  sysctls:
    net.ipv4.ip_forward: "1"
  kubelet:
    extraArgs:
      rotate-server-certificates: "true"
cluster:
  clusterName: production
  apiServer:
    admissionControl:
      - name: PodSecurity
        configuration:
          defaults:
            enforce: "restricted"

Vraagt de auditor hoe de Kubernetes-nodes geconfigureerd zijn, dan geef je dit. Geen benadering, en geen snapshot van vorig kwartaal. De exacte staat, en de node dwingt hem op dit moment af.

NixOS

{
  # Security hardening - dit is zowel config ALS documentatie
  security.sudo.wheelNeedsPassword = true;
  security.auditd.enable = true;
  security.audit.rules = [
    "-w /etc/passwd -p wa -k identity"
    "-w /etc/group -p wa -k identity"
  ];

  # Firewall configuratie
  networking.firewall = {
    enable = true;
    allowedTCPPorts = [ 22 443 6443 ];
    logRefusedConnections = true;
  };

  # Automatische security updates
  system.autoUpgrade = {
    enable = true;
    allowReboot = false;
    dates = "04:00";
  };
}

Elke control zit in code, en de auditor weet dat hij live is omdat NixOS geen generatie bouwt die er niet mee klopt. “Ja, het staat geconfigureerd, maar we hadden het even uitgezet en zijn het vergeten” bestaat hier niet. De build bevat de control, of de build faalt.

Gedeclareerde staat mappen op de controls

“Vertrouw me, het staat allemaal in Git” haalt op zichzelf geen audit. Iemand moet elk stuk config koppelen aan de control die het invult, en die iemand ben jij. Zo doe ik dat voor vier controls waar ik naar gevraagd word.

ISO 27001: A.12.1.2 - Change Management

De eis zegt dat wijzigingen aan systemen beheerst moeten worden. Het traditionele antwoord is change tickets, een goedkeuringsworkflow en met de hand geschreven documentatie.

Op een declaratief systeem is elke wijziging een Git-commit, heeft een pull request een review nodig voor hij merget, en is mergen naar main wat deployt. De Git history is het changelog.

# Je change management bewijs
git log --oneline --since="2025-01-01" -- infrastructure/

2d8d00e Add NixOS vs Talos comparison
e49f5bd Add Talos Linux blog post
defb991 Switch image generation to DALL-E
...

Elke commit draagt wie hem maakte, wanneer, wat er veranderde, wie het goedkeurde in de PR-review, en waarom in de message. Een ticketsysteem geeft je een slechtere versie van hetzelfde, losgekoppeld van de wijziging zelf.

ISO 27001: A.12.6.1 - Management of Technical Vulnerabilities

De eis zegt dat informatie over technische kwetsbaarheden verkregen moet worden en dat er passende maatregelen genomen worden. Bij Talos is de OS-versie één regel:

machine:
  install:
    image: ghcr.io/siderolabs/installer:v1.7.0  # Specifieke versie

Updaten is die regel aanpassen en deployen. De Git history laat zien welke versie er op welke datum draaide, en blijkt een nieuwe versie een kwetsbaarheid mee te brengen, dan is de rollback een revert.

NIS2: Artikel 21 - Cybersecurity Risk Management

De eis vraagt om passende technische en organisatorische maatregelen om risico’s te beheersen. Zo zien drie van die maatregelen eruit in NixOS, netwerksegmentatie, encryptie at rest en toegangsbeheer:

{
  # Netwerk segmentatie
  networking.vlans = {
    management = { id = 10; interface = "eth0"; };
    production = { id = 20; interface = "eth0"; };
  };

  # Encryptie at rest
  boot.initrd.luks.devices."encrypted".device = "/dev/sda2";

  # Access control
  services.openssh = {
    enable = true;
    settings = {
      PermitRootLogin = "no";
      PasswordAuthentication = false;
    };
  };
}

Elke control is zichtbaar, en de build dwingt hem af.

SOC 2: CC6.1 - Logical Access Controls

De eis zegt dat de organisatie logical access security software, infrastructuur en architecturen implementeert. Dit is degene waar ik het meeste plezier aan beleef, want Talos beantwoordt logical access control door geen login te hebben. Er is geen SSH. Al het beheer loopt via de API, elke API-call is geauthenticeerd met mTLS , en wat je mag zodra je binnen bent is Kubernetes RBAC.

# Talos machine config
machine:
  features:
    rbac: true  # Kubernetes RBAC enabled
  # Geen SSH configuratie omdat SSH niet bestaat

De auditor kan op de node zelf nakijken dat er geen SSH-daemon is om in te breken. Meer valt er niet te inspecteren, en er is geen beleidsdocument met “alsjeblieft niet doen” erin.

De audit die zichzelf draait

Omdat alles in code leeft, is het verzamelen van bewijs dat vroeger weken opvrat nu drie scripts op een schema.

Configuration drift report

#!/bin/bash
# Voor Talos: vergelijk gedeclareerd vs actueel

for node in $(talosctl get members -o json | jq -r '.[] | .hostname'); do
  echo "=== $node ==="
  talosctl get machineconfig -n $node -o yaml > /tmp/actual.yaml
  diff infrastructure/talos/$node.yaml /tmp/actual.yaml
done

Geen output betekent geen drift, en die lege diff gaat zo de bewijsmap in.

NixOS system closure

# Genereer complete lijst van alle software en versies
nix-store -q --requisites /run/current-system | \
  xargs -I {} nix-store -q --binding name {} 2>/dev/null | \
  sort -u > system-inventory.txt

Eén commando en je hebt de complete software-inventaris, elk pakket en elke library met de versie die draait. Auditors die gewend zijn dat met de hand na te jagen klaren op als je ze een bestand geeft.

Git-based audit trail

# Genereer wijzigingsrapport voor auditperiode
git log --pretty=format:"%h|%an|%ad|%s" \
  --date=short \
  --since="2025-01-01" \
  --until="2025-12-31" \
  -- infrastructure/ > annual-changes.csv

Importeren in Excel, en klaar.

Compliant tussen de audits door

Het kan nog een stap verder. Combineer de declaratieve systemen met GitOps en het cluster corrigeert zichzelf het hele jaar terug naar de gedeclareerde staat, of er nu iemand komt kijken of niet.

# ArgoCD Application voor infrastructuur
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: infrastructure
spec:
  source:
    repoURL: https://github.com/company/infrastructure
    path: kubernetes/
  destination:
    server: https://kubernetes.default.svc
  syncPolicy:
    automated:
      prune: true
      selfHeal: true  # Automatisch drift fixen

Patcht iemand tijdens een incident een node met de hand? ArgoCD draait het bij de volgende sync terug. Dus “was je compliant op 14 maart” heeft een antwoord in de Git log en de sync-historie van 14 maart, en dat hoef ik niet te onthouden.

De saaie delen goed doen

Niks hiervan werkt vanzelf. Declaratieve infrastructuur maakt goed compliance-bewijs mogelijk, en daarna bepalen vier gewoontes of je het ook krijgt.

1. Schrijf commit messages die iets zeggen

# Slecht
git commit -m "Update config"

# Goed
git commit -m "Enable audit logging per ISO 27001 A.12.4.1

- Added auditd configuration for file access monitoring
- Configured log retention for 90 days
- Addresses finding from Q3 security review

Ticket: SEC-1234"

Je Git history wordt ooit door een auditor gelezen. Schrijf hem voor die lezer.

2. Tag compliance-gerelateerde config

{
  # ISO 27001 A.12.4.1 - Event Logging
  security.auditd.enable = true;

  # ISO 27001 A.13.1.1 - Network Controls
  networking.firewall.enable = true;

  # NIS2 Art.21(2)(d) - Supply Chain Security
  nix.settings.require-sigs = true;
}

Een comment die een regel config aan een control koppelt maakt van de audit een grep in plaats van een speurtocht.

3. Pin elke versie

# Talos machine config
machine:
  install:
    image: ghcr.io/siderolabs/installer:v1.6.0  # Niet :latest

Auditors willen weten wat er op een bepaalde datum draaide. Gepinde versies plus Git history geven dat antwoord gratis. :latest gooit het weg.

4. Automatiseer het verzamelen van bewijs

#!/bin/bash
# Kwartaal compliance rapport generator

REPORT_DIR="compliance-reports/$(date +%Y-Q%q)"
mkdir -p $REPORT_DIR

# Systeem inventory
nix-store -q --requisites /run/current-system > $REPORT_DIR/inventory.txt

# Configuratie snapshots
cp -r /etc/nixos $REPORT_DIR/nixos-config/

# Wijzigingslog
git log --since="3 months ago" -- infrastructure/ > $REPORT_DIR/changes.txt

# Drift check
./scripts/check-drift.sh > $REPORT_DIR/drift-report.txt

echo "Rapport gegenereerd in $REPORT_DIR"

Draai het elk kwartaal, archiveer de output, en de map ligt klaar als de auditor voor de deur staat.

Eerlijk over de kosten

Ik ga niet doen alsof dit gratis is. Talos en NixOS hebben allebei een steilere leercurve dan Ubuntu installeren en door een hardening guide klikken. Vooral NixOS vecht de eerste maand tegen je terwijl je de taal leert. Je ruilt een vergevingsgezinde setup in voor een strenge, en die strengheid voel je op dag één.

Dan is er nog het mappingwerk. Het systeem geeft je afgedwongen staat onder versiebeheer, en iemand moet nog steeds gaan zitten om elk stuk config aan de control te koppelen die het invult. De auditor doet die vertaling niet voor je, en de tooling ook niet. Op dag één kan het voelen alsof je een compliance-taak hebt toegevoegd in plaats van er een kwijt te zijn.

Het verschil zit in wanneer je betaalt. Dit betaal je één keer, en elke audit daarna leest dezelfde repository. De screenshot-en-Word-document-aanpak betaalt elke cyclus opnieuw, en de rekening groeit mee met het landschap.

Probeer het op één cluster

Je hoeft niet het hele landschap om te zetten om te zien of dit standhoudt. Pak één cluster. Zet het op met Talos, zet de config in Git, richt ArgoCD erop met selfHeal aan. Draai het een kwartaal en kijk hoe je bewijsmap eruitziet als de audit eraan komt, naast het team dat nog een slide deck uit screenshots bouwt.

De eerste alinea van deze post klopt dus nog steeds. De screenshots, de Word-documenten en de tickets zijn wat een audit vraagt, en op een traditionele opzet zijn ze de enige manier om te antwoorden. Wat ik jarenlang over het hoofd zag is dat het allemaal plaatsvervangers zijn voor één bestand, het bestand dat zegt wat de machine is. Talos en NixOS booten van dat bestand. Geef het af, en wat overblijft is het mappingwerk.