Zo gaat een ISO 27001 audit meestal. Weken voordat de auditor langskomt begint iemand screenshots te verzamelen. Configuratieschermen, firewall regels, een dashboard dat laat zien welke patches zijn uitgerold. Daarna komen de Word documenten die beschrijven wat de systemen geacht worden te doen. Daarna de change tickets, opgediept uit een ticketsysteem, elk refererend aan een vaag “server onderhoud” dat niemand zes maanden later nog volledig kan reconstrueren. Iedereen behandelt dit als de prijs van zakendoen. Ik ook, jarenlang.

Toen draaide ik Talos en NixOS lang genoeg om iets te merken. De hele taak van de auditor is vragen “bewijs dat het systeem geconfigureerd is zoals je beweert.” En met declaratieve infrastructuur houdt die vraag op een kloof te bevatten. De configuratie en het bewijs zijn hetzelfde bestand.

Dat is het argument dat ik hier wil maken: de eigenschappen die mij deze systemen lieten kiezen voor soevereiniteit en resilience (immutability, reproduceerbaarheid, een Git history die je echt kunt vertrouwen) zijn toevallig precies waar een auditor naar vist. Compliance houdt op een apart project te zijn. Het valt uit het correct doen van infrastructuur.

Wat auditors echt vragen

Strip de framework-specifieke jargon weg en ISO 27001, SOC 2, NIS2 en PCI-DSS cirkelen allemaal rond dezelfde vier vragen:

  1. Wat is je systeemconfiguratie? (Asset management, configuration management)
  2. Hoe controleer je wijzigingen? (Change management, access control)
  3. Kun je het bewijzen? (Audit trails, bewijs)
  4. Is het consistent? (Geen drift, geen ongedocumenteerde wijzigingen)

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

De rot zit in de kloof. Het document beweert dat automatische updates aanstaan. Niemand heeft gecontroleerd of dat nog waar is sinds de laatste reorganisatie. De screenshot klopte op de dag dat hij genomen werd en zegt niets over vandaag. Je documenteert het systeem niet. Je documenteert een herinnering aan het systeem, en herinneringen driften.

Als de config de documentatie is

Draai Talos of NixOS en die kloof sluit zich, want de configuratie is het systeem. Er bestaat geen apart document dat stilletjes met de realiteit kan oneens zijn, omdat de machine weigert te booten in een andere staat dan degene die je hebt gedeclareerd.

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"

Als de auditor vraagt “hoe zijn je Kubernetes nodes geconfigureerd?”, geef je ze dit. Geen benadering van de config, geen snapshot van vorig kwartaal. De exacte, huidige, afgedwongen staat.

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 het live is omdat NixOS geen generatie bouwt die niet matcht. Er is geen “ja het is geconfigureerd maar we hebben het tijdelijk uitgezet en zijn het vergeten.” De build is de afdwinging.

Gedeclareerde staat mappen naar de controls

Het raam staat open. Nu loop ik door hoe specifieke config mapt naar specifieke requirements, want “vertrouw me, het staat allemaal in Git” haalt op zichzelf geen audit. Je moet het mappingwerk doen.

ISO 27001: A.12.1.2 - Change Management

Requirement: Wijzigingen aan systemen moeten gecontroleerd worden.

Traditionele aanpak: Change tickets, approval workflows, handmatige documentatie.

Declaratieve aanpak:

  • Alle wijzigingen zijn Git commits
  • Pull requests vereisen review
  • Merge naar main triggert deployment
  • Git history IS het change log
# 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 wijziging draagt wie het maakte, wanneer, wat veranderde, wie het goedkeurde (de PR reviewers), en waarom (de commit message). Een ticketsysteem geeft je een slechtere versie van datzelfde, losgekoppeld van de echte wijziging.

ISO 27001: A.12.6.1 - Management of Technical Vulnerabilities

Requirement: Informatie over technische kwetsbaarheden moet worden verkregen en passende maatregelen genomen.

Declaratieve aanpak met Talos:

machine:
  install:
    image: ghcr.io/siderolabs/installer:v1.7.0  # Specifieke versie
  • Exacte OS versie staat in Git
  • Updaten betekent versie wijzigen en deployen
  • Je kunt bewijzen welke versie op elk moment draaide
  • Rollback is triviaal als een kwetsbaarheid gevonden wordt in een nieuwe versie

NIS2: Artikel 21 - Cybersecurity Risk Management

Requirement: Passende technische en organisatorische maatregelen om risico’s te beheren.

Declaratief bewijs:

{
  # 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, auditeerbaar en afgedwongen.

SOC 2: CC6.1 - Logical Access Controls

Requirement: De entiteit implementeert logical access security software, infrastructuur en architecturen.

Dit is degene waar ik het meeste van geniet. De Talos aanpak van logical access control is geen login hebben.

  • Geen SSH toegang überhaupt
  • Alle management via geauthenticeerde API
  • mTLS voor alle API communicatie
  • Role-based access via Kubernetes RBAC
# Talos machine config
machine:
  features:
    rbac: true  # Kubernetes RBAC enabled
  # Geen SSH configuratie omdat SSH niet bestaat

De auditor kan verifiëren dat er letterlijk geen SSH daemon is om in te breken. Access control wordt afgedwongen door architectuur, niet door een beleidsdocument dat zegt alsjeblieft niet doen.

De audit die zichzelf draait

Hier begint de kloof zich echt te sluiten. Omdat alles in code leeft, wordt de evidence collection die vroeger weken opvrat een handvol scripts die je op een schema draait.

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 nul drift, en die lege output is het bewijs. Probeer dat eens te produceren met screenshots.

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, een complete software inventory: elk pakket, elke library, elke versie die daadwerkelijk draait. Auditors die gewend zijn dit met de hand na te jagen klaren op als je ze een bestand overhandigt.

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

Importeer in Excel, geef aan auditor. Klaar.

De hele tijd compliant, niet tijdens de audit

Er is een diepere versie hiervan. Combineer declaratieve systemen met GitOps en je houdt op compliant te zijn in pieken rond audit seizoen. Het cluster corrigeert zichzelf continu terug naar de gedeclareerde staat.

# 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

Iemand maakt om 2 uur ’s nachts tijdens een incident een handmatige wijziging? ArgoCD reverteert het. De gedeclareerde staat is de enige staat die het systeem tolereert. Dus de vraag “was je compliant op 14 maart” houdt op een gok te zijn. Het systeem was compliant op 14 maart omdat het niets anders kan zijn.

De saaie delen goed doen

Niets hiervan werkt vanzelf. Declaratieve infrastructuur maakt geweldig compliance bewijs mogelijk, maar je moet nog steeds gedisciplineerd zijn over een paar gewoontes. Dit zijn degene die zich terugbetalen.

1. Schrijf betekenisvolle commit messages

# 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 gelezen door een auditor. 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 linkt aan een specifieke control verandert de audit van een speurtocht in een grep.

3. Pin elke versie

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

Auditors willen exact weten wat er draaide op een specifieke datum. Gepinde versies plus Git history geeft je dat antwoord gratis; :latest gooit het weg.

4. Automatiseer evidence collection

#!/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, geef het door als de auditor langskomt.

Wees eerlijk over de kosten

Ik ga niet doen alsof dit gratis is. Hier komen is echt werk. Talos en NixOS hebben allebei een leercurve die steiler is dan Ubuntu installeren en door een hardening guide klikken. NixOS vooral zal je de eerste maand bevechten terwijl je de taal leert. Je ruilt een vertrouwde, vergevende setup in voor een die strenger is en minder vergevend aan de voorkant.

Er is ook het mappingwerk. Het systeem geeft je afgedwongen, version-controlled staat, maar iemand moet nog steeds gaan zitten en elk stuk config verbinden met de control die het invult. De auditor doet die vertaling niet voor je, en de tooling ook niet. Dat is echte inspanning, en op dag één kan het voelen alsof je een compliance taak hebt toegevoegd in plaats van er een weggehaald.

De reden dat het de moeite waard is: die kosten worden één keer betaald, aan de voorkant, en daarna amortiseren ze over elke audit voor altijd. De traditionele aanpak betaalt de screenshot-en-Word-document belasting elke audit cyclus, en de belasting loopt op naarmate het systeem groeit.

De kloof sluiten

Je hoeft niet het hele landschap om te zetten om te ontdekken 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 evidence collection eruitziet als audit tijd langskomt. Vergelijk dat dan met het team dat nog steeds een slide deck bouwt uit screenshots.

Wat je echt doet is non-compliance structureel onmogelijk maken in plaats van beloven het te vermijden. Traditionele compliance vraagt mensen zich correct te gedragen en hoopt dan dat de documentatie matcht. Declaratieve infrastructuur verwijdert de kloof waar de leugen leeft. Het systeem kan niet driften van zijn gedeclareerde staat, de history kan niet stilletjes herschreven worden, en het bewijs genereert zichzelf als bijproduct van het draaien van het ding.

Dat is dezelfde reden dat ik deze stack voor alles draai: ik wil begrijpen en vertrouwen wat ik draai, helemaal tot onderaan. De audit halen is gewoon hoe dat vertrouwen er van buitenaf uitziet.