LeitWacht v1.21.0
New releaseAug 20, 2026Leitwacht control plane — runtime security for GitLab Runner CI/CD: policy au 2026-8-20 08:3:14 Author: kitploit.com(查看原文) 阅读量:5 收藏

New releaseAug 20, 2026

Leitwacht control plane — runtime security for GitLab Runner CI/CD: policy authoring, multi-tenancy, audit, GitLab integration

Network egress enforcement for GitLab Runner CI/CD containers. Leitwacht prevents supply chain attacks from exfiltrating secrets by controlling what each job container can access on the network.

How It Works

Leitwacht is a standalone agent that runs alongside GitLab Runner on each node. It intercepts container start events, attaches enforcement primitives, and reports all network activity to a central backend. No modifications to GitLab Runner required.

Enforcement Stack (per container)

Container Process
    |
    | DNS query (port 53)
    v
nftables redirect ──> DNS Proxy (:15353)
                         |
                         |── Allowlist check (FQDN match)
                         |── Block: NXDOMAIN response
                         |── Allow: forward to upstream, add resolved IPs to eBPF allow map
                         |── Record: domain, resolved IPs, PID, process name
                         v
                    Upstream DNS (CoreDNS / external)
    
Container Process
    |
    | TCP/UDP egress (any port)
    v
eBPF cgroup-skb/egress filter
    |── IP in allow map? ──> ALLOW (counted)
    |── IP in trusted CIDRs? ──> ALLOW (pod net, svc net)
    |── Cloud metadata (169.254.169.254)? ──> BLOCK (always)
    |── DoT (port 853)? ──> BLOCK (always)
    |── IPv6 (non-loopback)? ──> BLOCK (always)
    |── Default ──> BLOCK (drop event to ringbuf)

Pod-Level Sharing (Kubernetes)

All containers in a K8s pod share one network namespace. Leitwacht creates a single NetnsContext per pod that owns the shared state (DNS proxy, nftables rules, eBPF maps). Each container gets its own cgroup-skb attachment so no sibling can bypass the filter.

Pod (shared netns)
 +-- NetnsContext (1 per pod)
 |    +-- DNS Proxy (1 goroutine pair)
 |    +-- nftables redirect rules
 |    +-- eBPF program + maps
 |    +-- Ringbuf reader
 |
 +-- Container A
 |    +-- CgroupLink (eBPF attached to A's cgroup)
 |    +-- ViolationRecorder
 |
 +-- Container B
      +-- CgroupLink (eBPF attached to B's cgroup)
      +-- ViolationRecorder

Agent-Backend Communication

+------------------+          gRPC           +------------------+
|  Leitwacht Agent  | ──────────────────────> |  Leitwacht Server |
|  (per node)      |                         |  (central)       |
|                  |  GetPolicy(project)     |                  |
|  - Watcher       | <───────────────────── |  - Policy store  |
|  - Enforcer      |                         |  - Violation DB  |
|  - DNS Proxy     |  ReportViolations(job)  |  - REST API      |
|  - Reporter      | ──────────────────────> |  - Frontend SPA  |
|  - Honeypot LSM  |                         |  - Notifications |
|                  |  Heartbeat()            |  - Baselines     |
|                  | ──────────────────────> |  - Anomaly det.  |
+------------------+                         +------------------+

Architecture

Components

ComponentDescription
Agent (cmd/agent)DaemonSet on runner nodes. Watches containerd for job containers, attaches eBPF + DNS proxy, reports violations. Requires root + Linux.
Server (cmd/server)Central backend. REST API for the frontend, gRPC for agents. Stores policies, violations, baselines. Postgres or SQLite.
Frontend (frontend/)SvelteKit SPA. Policy management, violation viewer, baseline management, anomaly detection, audit log.

Key Packages

This repository is the EE server + EE-licensed agent. The network-enforcement data plane shown in the diagrams above (eBPF, DNS proxy, nftables, the containerd watcher) lives in the separate, MPL-2.0 Community-Edition module leitwacht-agent, which this repo consumes as a dependency; cmd/agent + ee/ are the EE build that reuses it and wires it to the backend.

PackagePurpose
internal/agentgrpcgRPC server: ingests agent violation reports, serves policy + rule streams
internal/apiREST API handlers, auth middleware, RBAC scoping
internal/authOIDC (GitLab) authentication, sessions, CSRF
internal/storeGORM data access (projects, violations, baselines) + ClickHouse
internal/license, internal/licensemgrEE license verify (Ed25519 JWS) + lifecycle and config gate (see LICENSE)
internal/notifyAlert delivery (email/SES, Slack) + templates
internal/retentionData-retention / pruning
internal/mcp, internal/mcpauthMCP server + auth
ee/reporterEE agent gRPC client pushing violations + advisories to the backend
ee/policycache, ee/rulewatcher, ee/rulestoreEE agent policy cache + rule watch/store (BBolt)
contract/Shared Go module: .proto sources + generated agentpb wire types

Deployment

Prerequisites

  • Kubernetes cluster with containerd runtime
  • GitLab Runner using the Kubernetes executor
  • FF_NETWORK_PER_BUILD=true on runners (each job gets its own network namespace)

Helm Charts

Server (helm/) — published as an OCI chart. Needs Postgres + ClickHouse and a few pre-created secrets (DB DSN, auth keys). See docs/DEPLOY.md for the full 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"

Enforcement Modes

ModeDNS PolicyeBPF FilterUse Case
auditForward all, record violationsAllow all, record dropsBaseline building, initial rollout
blockNXDOMAIN for non-allowlistedDrop non-allowlisted IPsProduction enforcement
allowNo enforcementNo enforcementExempted projects

Development

Build

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

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

# gRPC contract regeneration (edit contract/proto/**, then):
cd contract && buf generate proto/

The eBPF data plane is not in this repo — it lives in the leitwacht-agent (CE) module. Regenerate its BPF skeletons there (see that repo's Makefile: make ebpf-generate).

Test

# Unit tests (any platform)
go test ./...

# Integration / e2e tests requiring sidecars (ClickHouse + Postgres) live under
# internal/store, internal/api, internal/agentgrpc — bring those up first.

# Frontend
cd frontend && pnpm test

Lint

# Backend
golangci-lint run ./...

# Frontend
cd frontend && pnpm lint

Documentation

DocumentContents
docs/DEPLOY.mdFull Kubernetes deployment runbook (secrets, ClickHouse, migrations, license install, exposure)
docs/MULTI_ORG.mdMulti-org / multi-tenant setup
LICENSE, NOTICEBSL 1.1 terms (Change License: MPL-2.0) and the CE/EE license split
leitwacht-agentThe MPL-2.0 Community-Edition data-plane agent (eBPF / DNS proxy / nftables enforcement) — the engine behind the diagrams above

Read more

Categories


文章来源: https://kitploit.com/en/posts/gitlab-leitwacht-leitwacht-v1210
如有侵权请联系:admin#unsafe.sh