Zurück zu den Updates
New releaseAug 20, 2026

LeitWacht v1.21.0

Leitwacht Control Plane – Laufzeitsicherheit für GitLab Runner CI/CD: Richtlinienerstellung, Multi-Tenancy, Audit, GitLab-Integration

Teilen

GitLab Runner Leitwacht

Netzwerk-Egress-Erzwingung für GitLab Runner CI/CD-Container. Leitwacht verhindert Supply-Chain-Angriffe, die Secrets exfiltrieren, indem gesteuert wird, worauf jeder Job-Container im Netzwerk zugreifen kann.

So funktioniert es

Leitwacht ist ein eigenständiger Agent, der auf jedem Knoten zusammen mit GitLab Runner läuft. Er fängt Container-Start-Ereignisse ab, bindet Erzwingungsprimitive ein und meldet alle Netzwerkaktivitäten an ein zentrales Backend. Es sind keine Änderungen an GitLab Runner erforderlich.

Erzwingungs-Stack (pro Container)

Container-Prozess
    |
    | DNS-Abfrage (Port 53)
    v
nftables-Weiterleitung ──> DNS-Proxy (:15353)
                         |
                         |── Allowlist-Prüfung (FQDN-Übereinstimmung)
                         |── Blockieren: NXDOMAIN-Antwort
                         |── Erlauben: Weiterleitung an Upstream, hinzufügen der aufgelösten IPs zur eBPF-Allow-Map
                         |── Aufzeichnung: Domain, aufgelöste IPs, PID, Prozessname
                         v
                    Upstream-DNS (CoreDNS / extern)
    
Container-Prozess
    |
    | TCP/UDP-Egress (beliebiger Port)
    v
eBPF cgroup-skb/egress-Filter
    |── IP in Allow-Map? ──> ERLAUBEN (gezählt)
    |── IP in vertrauenswürdigen CIDRs? ──> ERLAUBEN (Pod-Netz, Service-Netz)
    |── Cloud-Metadaten (169.254.169.254)? ──> BLOCKIEREN (immer)
    |── DoT (Port 853)? ──> BLOCKIEREN (immer)
    |── IPv6 (nicht Loopback)? ──> BLOCKIEREN (immer)
    |── Standard ──> BLOCKIEREN (Drop-Ereignis an Ringbuf)

Pod-Level-Sharing (Kubernetes)

Alle Container in einem K8s-Pod teilen sich einen Netzwerk-Namensraum. Leitwacht erstellt einen einzigen NetnsContext pro Pod, der den gemeinsamen Zustand (DNS-Proxy, nftables-Regeln, eBPF-Maps) besitzt. Jeder Container erhält seine eigene cgroup-skb-Anbindung, sodass kein Geschwistercontainer den Filter umgehen kann.

Pod (gemeinsamer Netns)
 +-- NetnsContext (1 pro Pod)
 |    +-- DNS-Proxy (1 Goroutine-Paar)
 |    +-- nftables-Weiterleitungsregeln
 |    +-- eBPF-Programm + Maps
 |    +-- Ringbuf-Leser
 |
 +-- Container A
 |    +-- CgroupLink (eBPF an A's Cgroup gebunden)
 |    +-- ViolationRecorder
 |
 +-- Container B
      +-- CgroupLink (eBPF an B's Cgroup gebunden)
      +-- ViolationRecorder

Agent-Backend-Kommunikation

+------------------+          gRPC           +------------------+
|  Leitwacht-Agent  | ──────────────────────> |  Leitwacht-Server |
|  (pro Knoten)    |                         |  (zentral)       |
|                  |  GetPolicy(project)     |                  |
|  - Watcher       | <───────────────────── |  - Policy-Speicher|
|  - Enforcer      |                         |  - Violation-DB  |
|  - DNS-Proxy     |  ReportViolations(job)  |  - REST-API      |
|  - Reporter      | ──────────────────────> |  - Frontend SPA  |
|  - Honeypot LSM  |                         |  - Benachrichtigungen|
|                  |  Heartbeat()            |  - Baselines     |
|                  | ──────────────────────> |  - Anomalieerkenn.|
+------------------+                         +------------------+

Architektur

Komponenten

KomponenteBeschreibung
Agent (cmd/agent)DaemonSet auf Runner-Knoten. Überwacht containerd auf Job-Container, bindet eBPF + DNS-Proxy ein, meldet Verstöße. Erfordert root + Linux.
Server (cmd/server)Zentrales Backend. REST-API für das Frontend, gRPC für Agenten. Speichert Richtlinien, Verstöße, Baselines. Postgres oder SQLite.
Frontend (frontend/)SvelteKit SPA. Richtlinienverwaltung, Verstoßanzeige, Baseline-Verwaltung, Anomalieerkennung, Prüfprotokoll.

Wichtige Pakete

Dieses Repository ist der EE-Server + der EE-lizenzierte Agent. Die Netzwerk-Erzwingungs-Datenebene, die in den obigen Diagrammen gezeigt wird (eBPF, DNS-Proxy, nftables, der containerd-Watcher), befindet sich im separaten, MPL-2.0 Community-Edition-Modul leitwacht-agent, das dieses Repository als Abhängigkeit nutzt; cmd/agent + ee/ sind der EE-Build, der es wiederverwendet und mit dem Backend verbindet.

PaketZweck
internal/agentgrpcgRPC-Server: nimmt Agent-Meldungen über Verstöße entgegen, stellt Richtlinien- und Regel-Streams bereit
internal/apiREST-API-Handler, Authentifizierungs-Middleware, RBAC-Bereichsbegrenzung
internal/authOIDC (GitLab)-Authentifizierung, Sitzungen, CSRF
internal/storeGORM-Datenzugriff (Projekte, Verstöße, Baselines) + ClickHouse
internal/license, internal/licensemgrEE-Lizenzprüfung (Ed25519 JWS) + Lebenszyklus- und Konfigurations-Gate (siehe LIZENZ)
internal/notifyAlarmzustellung (E-Mail/SES, Slack) + Vorlagen
internal/retentionDatenaufbewahrung / Bereinigung
internal/mcp, internal/mcpauthMCP-Server + Authentifizierung
ee/reporterEE-Agent gRPC-Client, der Verstöße und Hinweise an das Backend sendet
ee/policycache, ee/rulewatcher, ee/rulestoreEE-Agent-Richtlinien-Cache + Regelbeobachter/-Speicher (BBolt)
contract/Gemeinsames Go-Modul: .proto-Quellen + generierte agentpb-Drahttypen

Bereitstellung

Voraussetzungen

  • Kubernetes-Cluster mit containerd-Laufzeit
  • GitLab Runner mit Kubernetes Executor
  • FF_NETWORK_PER_BUILD=true auf den Runnern (jeder Job erhält einen eigenen Netzwerk-Namensraum)

Helm-Charts

Server (helm/) — als OCI-Chart veröffentlicht. Benötigt Postgres + ClickHouse und einige vorab erstellte Secrets (DB-DSN, Auth-Keys). Siehe docs/DEPLOY.md für das vollständige Runbook.

helm install leitwacht \
  oci://registry.gitlab.com/leitwacht/leitwacht/charts/leitwacht --version 1.18.0 \
  --set image.tag=1.18.0 \
  --set ingress.domain=example.com --set ingress.hosts[0]=leitwacht.example.com \
  --set grpcIngress.domain=example.com --set grpcIngress.hosts[0]=grpc-leitwacht.example.com \
  --set app.oidcIssuer=https://gitlab.com --set app.oidcClientId=<oauth-app-id> \
  --set clickhouse.embedded.password=<password>

Agent (helm/agent/):

helm install leitwacht-agent \
  oci://registry.gitlab.com/leitwacht/leitwacht/charts/leitwacht-agent --version 1.18.0 \
  --set agent.backendAddr="leitwacht.namespace.svc.cluster.local:9090" \
  --set agent.defaultAction=audit \
  --set agent.dnsUpstream="10.96.0.10:53,1.1.1.1:53" \
  --set agent.trustedCIDRs="10.244.0.0/16,10.96.0.0/12"

Erzwingungsmodi

ModusDNS-RichtlinieeBPF-FilterAnwendungsfall
auditAlle weiterleiten, Verstöße aufzeichnenAlle erlauben, Abweisungen aufzeichnenBaseline-Erstellung, Erstausrollen
blockNXDOMAIN für nicht erlaubteNicht erlaubte IPs abweisenProduktionserzwingung
allowKeine ErzwingungKeine ErzwingungAusgenommene Projekte

Entwicklung

Build

# Backend
go build ./cmd/agent
go build ./cmd/server

# Frontend
cd frontend && pnpm install && pnpm build

# gRPC-Vertragsneugenerierung (edit contract/proto/**, dann):
cd contract && buf generate proto/

Die eBPF-Datenebene befindet sich nicht in diesem Repository – sie lebt im leitwacht-agent (CE)-Modul. Generieren Sie dort ihre BPF-Skelette neu (siehe Makefile dieses Repos: make ebpf-generate).

Test

# Unit-Tests (beliebige Plattform)
go test ./...

# Integrations- / e2e-Tests, die Sidecars benötigen (ClickHouse + Postgres) befinden sich unter
# internal/store, internal/api, internal/agentgrpc – diese zuerst starten.

# Frontend
cd frontend && pnpm test

Lint

# Backend
golangci-lint run ./...

# Frontend
cd frontend && pnpm lint

Dokumentation

DokumentInhalt
docs/DEPLOY.mdVollständiges Kubernetes-Bereitstellungs-Runbook (Secrets, ClickHouse, Migrationen, Lizenzinstallation, Exposition)
docs/MULTI_ORG.mdMulti-Organisations- / Multi-Mandanten-Setup
LICENSE, NOTICEBSL 1.1-Bedingungen (Wechsellizenz: MPL-2.0) und die CE/EE-Lizenzaufteilung
leitwacht-agentDas MPL-2.0 Community-Edition-Datenebenen-Agent (eBPF / DNS-Proxy / nftables-Erzwingung) – die Engine hinter den obigen Diagrammen

Kategorien