Volver a actualizaciones
Nuevo releaseAug 20, 2026

LeitWacht v1.21.0

Leitwacht control plane — seguridad en tiempo de ejecución para GitLab Runner CI/CD: creación de políticas, multi-inquilino, auditoría, integración con GitLab

Compartir

GitLab Runner Leitwacht

Control de salida de red para contenedores CI/CD de GitLab Runner. Leitwacht previene ataques a la cadena de suministro que exfiltran secretos, controlando lo que cada contenedor de trabajo puede acceder en la red.

Cómo Funciona

Leitwacht es un agente independiente que se ejecuta junto a GitLab Runner en cada nodo. Intercepta eventos de inicio de contenedores, adjunta primitivas de control e informa toda la actividad de red a un backend central. No se requieren modificaciones en GitLab Runner.

Pila de Control (por contenedor)

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)

Compartición a Nivel de Pod (Kubernetes)

Todos los contenedores en un pod de K8s comparten un único espacio de nombres de red. Leitwacht crea un solo NetnsContext por pod que posee el estado compartido (proxy DNS, reglas nftables, mapas eBPF). Cada contenedor obtiene su propio adjunto cgroup-skb para que ningún hermano pueda eludir el filtro.

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

Comunicación Agente-Backend

+------------------+          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.  |
+------------------+                         +------------------+

Arquitectura

Componentes

ComponenteDescripción
Agente (cmd/agent)DaemonSet en nodos runner. Observa containerd en busca de contenedores de trabajo, adjunta eBPF + proxy DNS, reporta violaciones. Requiere root + Linux.
Servidor (cmd/server)Backend central. API REST para el frontend, gRPC para agentes. Almacena políticas, violaciones, líneas base. Postgres o SQLite.
Frontend (frontend/)SPA en SvelteKit. Gestión de políticas, visor de violaciones, gestión de líneas base, detección de anomalías, registro de auditoría.

Paquetes Clave

Este repositorio es el servidor EE + el agente con licencia EE. El plano de datos de control de red mostrado en los diagramas anteriores (eBPF, proxy DNS, nftables, el observador de containerd) reside en el módulo separado de Community Edition con licencia MPL-2.0 leitwacht-agent, que este repositorio consume como dependencia; cmd/agent + ee/ son la compilación EE que lo reutiliza y lo conecta al backend.

PaquetePropósito
internal/agentgrpcServidor gRPC: recibe informes de violaciones de agentes, sirve flujos de políticas y reglas
internal/apiManejadores de API REST, middleware de autenticación, ámbito RBAC
internal/authAutenticación OIDC (GitLab), sesiones, CSRF
internal/storeAcceso a datos GORM (proyectos, violaciones, líneas base) + ClickHouse
internal/license, internal/licensemgrVerificación de licencia EE (Ed25519 JWS) + ciclo de vida y puerta de configuración (ver LICENSE)
internal/notifyEntrega de alertas (correo/SES, Slack) + plantillas
internal/retentionRetención/poda de datos
internal/mcp, internal/mcpauthServidor MCP + autenticación
ee/reporterCliente gRPC del agente EE que envía violaciones y avisos al backend
ee/policycache, ee/rulewatcher, ee/rulestoreCaché de políticas del agente EE + observación/almacenamiento de reglas (BBolt)
contract/Módulo Go compartido: fuentes .proto + tipos de cable agentpb generados

Despliegue

Requisitos Previos

  • Clúster Kubernetes con runtime containerd
  • GitLab Runner usando el ejecutor Kubernetes
  • FF_NETWORK_PER_BUILD=true en los runners (cada trabajo obtiene su propio espacio de nombres de red)

Helm Charts

Servidor (helm/) — publicado como un chart OCI. Necesita Postgres + ClickHouse y algunos secretos precreados (DSN DB, claves de autenticación). Consulte docs/DEPLOY.md para el runbook completo.

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>

Agente (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"

Modos de Control

ModoPolítica DNSFiltro eBPFCaso de Uso
auditReenviar todo, registrar violacionesPermitir todo, registrar descartesConstrucción de línea base, despliegue inicial
blockNXDOMAIN para no permitidosDescartar IPs no permitidasControl en producción
allowSin controlSin controlProyectos exentos

Desarrollo

Compilación

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

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

# Regeneración de contrato gRPC (editar contract/proto/**, luego):
cd contract && buf generate proto/

El plano de datos eBPF no está en este repositorio — reside en el módulo leitwacht-agent (CE). Regenerar sus esqueletos BPF allí (ver Makefile de ese repo: make ebpf-generate).

Pruebas

# Pruebas unitarias (cualquier plataforma)
go test ./...

# Pruebas de integración / e2e que requieren sidecars (ClickHouse + Postgres) viven en
# internal/store, internal/api, internal/agentgrpc — iniciarlos primero.

# Frontend
cd frontend && pnpm test

Linting

# Backend
golangci-lint run ./...

# Frontend
cd frontend && pnpm lint

Documentación

DocumentoContenido
docs/DEPLOY.mdRunbook completo de despliegue en Kubernetes (secretos, ClickHouse, migraciones, instalación de licencia, exposición)
docs/MULTI_ORG.mdConfiguración multi-org / multi-tenant
LICENSE, NOTICETérminos BSL 1.1 (Licencia de Cambio: MPL-2.0) y la división de licencias CE/EE
leitwacht-agentEl agente de plano de datos de Community Edition MPL-2.0 (control eBPF / proxy DNS / nftables) — el motor detrás de los diagramas anteriores

Categorías