Teknisk indsigt

Design af en evidensbaseret audit engine til IoT-sikkerhed & driftssikkerhed

Af Thomas Bonderup 10 min read

Jeg byggede en evidensbaseret audit engine med Rust-prober og en Scala ZIO-backend for at automatisere indsamling af evidens, evaluere versionerede regler og skabe målbare forbedringer i sikkerhed/driftssikkerhed over tid.

Jeg byggede en evidensbaseret audit engine med Rust-prober og en Scala ZIO-backend for at automatisere indsamling af evidens, evaluere versionerede regler og skabe målbare forbedringer i sikkerhed/driftssikkerhed over tid.

Vigtigste pointer

  • Evidens-først audit-workflows forbedrer reproducerbarhed, sporbarhed og beslutningskvalitet.
  • Versionerede regler og deterministiske inputs gør forbedringer målbare over flere audit-cyklusser.
  • Driftssikkerhed, sikkerhed og observability bør vurderes samlet på tværs af IoT-grænseflader.

Problemet: audits er for langsomme, for manuelle og for inkonsistente

IoT-systemer fejler ofte i overgangene: devices ved edge -> gateway -> cloud ingestion -> processing -> dashboard. Hver overgang introducerer kompleksitet i form af forskellige protokoller, certifikater, netværk og operationelle antagelser. Det gør audits dyre, og det er svært at være konsistent, når evidens indsamles manuelt.

I mange traditionelle audits ser indsamling af evidens typisk sådan ud:

  • Screenshots.
  • Videndeling med et par software developers.
  • Møder.
  • Anbefalinger, som ofte er svære at reproducere.

Den tilgang er ikke effektiv, når du har behov for reproducerbarhed, sporbarhed og dokumentation til intern governance eller compliance — fx krav inspireret af NIS2 eller Cyber Resilience.

Jeg laver tekniske IoT-audits for kunder for at identificere huller i driftssikkerhed, sikkerhed og observability. Checklister har været en stor hjælp til at strømline audit-processen, men checklister er stadig afhængige af, at en person indsamler evidens korrekt hver gang.

Derfor besluttede jeg at bygge noget bedre:
En audit engine, der opfører sig som et command-line tool (CI).

Deterministiske inputs -> automatiseret evidens-indsamling -> regel-evaluering -> issues -> rapport -> sprint backlog

Hvad jeg auditerer (og hvorfor det betyder noget i IoT/data pipelines)

Når jeg laver en teknisk arkitektur-review, kortlægger jeg IoT-systemet end-to-end og leder efter risici på tværs af tre grundlæggende søjler:

  • Driftssikkerhed: fejlscenarier, retries, kø-dannelse, backpressure, message loss, operationel parathed.
  • Sikkerhed: transportsikkerhed, identitet & key management, sikre defaults, hardening.
  • Observability: tracing/metrics/logs, SLO’er, evnen til at debugge incidents.

Hvor teams kæmper, varierer meget. Nogle teams er driftssikre, men har svag sikkerhed. Andre er “sikre nok”, men har svært ved observability, hvilket bliver en udfordring under incidents.

Eksempel på audit-fokusområde: Transportsikkerhed (TLS/mTLS)

Transportsikkerhed ligger i overgangene, hvor IoT-systemer ofte bliver lidt “rodede”.

For MQTT, som ofte bruges i IoT, bliver et review hurtigt detaljeret:

  • korrekthed af TLS vs mTLS
  • protocol version
  • cipher suites og kompatibilitet
  • korrekthed af certificate chain
  • strategi for certifikat-rotation og risiko for udløb

Manuelt indsamling af al denne evidens kan lade sig gøre, men det er langsomt og kan let opstå.

Designmål

Jeg designede audit engine omkring en simpel idé:
Automatisér indsamling af evidens og gør resultaterne reproducerbare.

Konkrete mål:
1. Reproducerbarhed: Samme input og samme output

2. Evidence-first: Gem rå outputs, ikke kun konklusioner

3. Versionerede regler: Regler udvikler sig; over tid skal du stadig kunne reproducere tidligere resultater

4. Målbarhed: Vis forbedring (eller regression) mellem audit runs

5. Udvidelige prober: IoT spænder over mange protokoller og miljøer — prober skal være plugbare.

6. CLI-venligt workflow: Command-line tooling, der er forudsigeligt og scriptbart.

Overordnet arkitektur

Den overordnede arkitektur består af to hoveddele:

1. Rust-prober (evidence collectors)

  • accepter args (target, ports osv.)
  • udfører et specifikt check (fx MQTT TLS posture)
  • returnerer struktureret JSON-output via en fælles kontrakt

2. Scala ZIO-backend (orchestrator + rules + storage)

  • starter audit runs for assets
  • eksekverer prober og gemmer rå JSON-output som evidens
  • evaluerer regler mod evidens for at generere issues
  • gemmer evidens/issues/audit runs i en database
  • genererer en rapport

Rust-prober: hvorfor Rust, hvordan en probe ser ud, og hvad den outputter

Jeg valgte Rust, fordi det er fremragende til at bygge hurtig, robust CLI-tooling, og fordi det skalerer godt fra low-level detaljer til ergonomi på højere niveau.

En probe er et simpelt binary:

  • parse CLI args
  • TCPStream med connect (eksempel: tokio::net::TcpStream)
  • TlsConnector wrap med tokio_rustls::TlsConnector
  • indsamle findings i en typed output struct
  • serialisere til JSON

Her er et eksempel på en output-kontrakt:

#[derive(Debug, serde::Serialize)]
pub struct ProbeOutput {
    pub probe: &'static str,
    pub version: &'static str,
    pub status: &'static str,
    pub summary: String,
    pub started_at: String,
    pub findings: Option<TlsFindings>,
    pub error: Option<ProbeErrorView>,
}

Scala ZIO backend

Backenden består af et HTTP API med en auditEngine-controller, der indeholder et endpoint:

POST /assets/{assetId}/audit-runs

Flow:

  1. Først hentes et asset fra databasen via et repository
  2. opret et auditRun record
  3. kør en eller flere prober via CLI-eksekvering (ZIO Process library)
  4. gem rå JSON-output som Evidence
  5. evaluer regler mod evidens
  6. upsert genererede issues og færdiggør audit run
override def runAuditForAsset(assetId: Long): Task[AuditRunResponse] =
    for {
      asset <- assetRepo
        .getById(assetId)
        .someOrFail(new RuntimeException(s"Cannot get asset to run audit: $assetId doesn't exists"))

      now <- zio.Clock.instant

      auditRun <- auditRunRepo.create(
        AuditRun(
          id = -1L,
          assetId = asset.id,
          status = AuditRunStatus.Running,
          startedAt = now,
          finishedAt = None,
          issuesFound = 0
        )
      )

      probeJson <- probeRunner.runMqttTlsPosture(asset)

      evidence <- evidenceRepo.create(
        Evidence(
          id = -1L, // generated by the DB,
          assetId = asset.id,
          probe = config.probe_name,
          collectedAt = now,
          rawJson = probeJson,
          auditRunId = auditRun.id
        )
      )

      issueDrafts = rules.evaluate(evidence, asset)

      issues <- ZIO.foreach(issueDrafts)(draft =>
        issueRepo.upsertFromDraft(asset.id, draft, evidence.id, auditRun.id, evidence.collectedAt)
      )

      _ <- auditRunRepo.complete(auditRun.id, issues.size, now).ignore

    } yield AuditRunResponse(auditRun.id, asset.id, issues)

En rules engine bruges til at evaluere evidens ved hjælp af JSON parsing, normalisering og pattern matching for at generere potentielle issueDrafts, fx en forældet TLS-protokolversion.

IssueDraft(
 key = "mqtt_tls.outdated_tls_version",
 severity = "High",
 title = "Outdated TLS protocol version in use",
 description =
  s"The MQTT endpoint negotiates an outdated TLS protocol version ($tlsVersion). " +
  "TLS 1.0 and 1.1 are deprecated and vulnerable to known cryptographic attacks. " +
  "Only TLS 1.2 or TLS 1.3 should be allowed",
)

Hvordan jeg bruger audit engine i audits

I audits bruger jeg audit engine til at accelerere og standardisere de dele, der bør automatiseres:

  • indsamling af evidens
  • omdanne evidens til en prioriteret backlog af issues
  • genkøre audits for at verificere forbedringer efter ændringer

Det giver to fordele:

1. Mindre tid brugt på manuel indsamling af evidens

2. Mere tid på ekspert vurdering — arkitektur tradeoffss, risikoprioritering og operationel hardening.

Det er stadig tidligt i udviklingen, men det hjælper mig allerede med at levere:

  • konsistent evidens
  • hurtigere iteration på tværs af miljøer
  • målbare ændringer

Næste skridt

Hvis du bygger eller driver et IoT-system og vil have et klart overblik over huller på tværs af sikkerhed, driftssikkerhed og observability, tilbyder jeg en dyb teknisk IoT Audit.

Det får du:

  • evidensbaserede findings
  • en prioriteret backlog
  • klare næste skridt til at hardne produktion

Du er velkommen til at kontakte mig.

Anvend dette i din platform

If you are dealing with similar architecture or reliability issues, I can help scope a concrete improvement plan.

Relateret indhold

Drøft en lignende udfordring

Del din arkitekturkontekst og det oenskede resultat.

Foretrækker du direkte kontakt? Ring på +45 22 39 34 91 eller skriv til tb@tbcoding.dk.

Bedst til teams med arkitektur-, stabilitets-, security- eller leverance-risiko i kritiske systemer.

Typisk svartid: 1-2 dage