
LeitWacht v1.21.0
Leitwacht plano de controle — segurança em tempo de execução para GitLab Runner CI/CD: criação de políticas, multi-inquilino, auditoria, integração com GitLab
GitLab Runner Leitwacht
Imposição de saída de rede para contêineres CI/CD do GitLab Runner. O Leitwacht previne ataques à cadeia de suprimentos que exfiltram segredos, controlando o que cada contêiner de job pode acessar na rede.
Como Funciona
O Leitwacht é um agente independente que é executado junto com o GitLab Runner em cada nó. Ele intercepta eventos de inicialização de contêineres, anexa primitivas de imposição e reporta toda atividade de rede a um backend central. Nenhuma modificação no GitLab Runner é necessária.
Pilha de Imposição (por contêiner)
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)
Compartilhamento em Nível de Pod (Kubernetes)
Todos os contêineres em um pod do K8s compartilham um namespace de rede. O Leitwacht cria um único NetnsContext por pod que detém o estado compartilhado (proxy DNS, regras nftables, mapas eBPF). Cada contêiner recebe sua própria ligação cgroup-skb para que nenhum irmão possa contornar o 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
Comunicação 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. |
+------------------+ +------------------+
Arquitetura
Componentes
| Componente | Descrição |
|---|---|
Agente (cmd/agent) | DaemonSet nos nós de runner. Monitora o containerd para contêineres de job, anexa eBPF + proxy DNS, reporta violações. Requer root + Linux. |
Servidor (cmd/server) | Backend central. API REST para o frontend, gRPC para agentes. Armazena políticas, violações, baselines. Postgres ou SQLite. |
Frontend (frontend/) | SPA SvelteKit. Gerenciamento de políticas, visualizador de violações, gerenciamento de baselines, detecção de anomalias, log de auditoria. |
Pacotes Principais
Este repositório é o servidor EE + o agente licenciado EE. O plano de dados de imposição de rede mostrado nos diagramas acima (eBPF, proxy DNS, nftables, o monitor containerd) reside no módulo separado, Edição Comunitária MPL-2.0
leitwacht-agent, que este repo consome como dependência;cmd/agent+ee/são a compilação EE que o reutiliza e o conecta ao backend.
| Pacote | Propósito |
|---|---|
internal/agentgrpc | Servidor gRPC: ingere relatórios de violação do agente, serve streams de políticas e regras |
internal/api | Handlers da API REST, middleware de autenticação, escopo RBAC |
internal/auth | Autenticação OIDC (GitLab), sessões, CSRF |
internal/store | Acesso a dados GORM (projetos, violações, baselines) + ClickHouse |
internal/license, internal/licensemgr | Verificação de licença EE (Ed25519 JWS) + ciclo de vida e gate de configuração (veja LICENSE) |
internal/notify | Entrega de alertas (email/SES, Slack) + templates |
internal/retention | Retenção/poda de dados |
internal/mcp, internal/mcpauth | Servidor MCP + autenticação |
ee/reporter | Cliente gRPC do agente EE para enviar violações e avisos ao backend |
ee/policycache, ee/rulewatcher, ee/rulestore | Cache de política do agente EE + observação/armazenamento de regras (BBolt) |
contract/ | Módulo Go compartilhado: fontes .proto + tipos wire gerados agentpb |
Implantação
Pré-requisitos
- Cluster Kubernetes com runtime containerd
- GitLab Runner usando o executor Kubernetes
FF_NETWORK_PER_BUILD=truenos runners (cada job obtém seu próprio namespace de rede)
Helm Charts
Servidor (helm/) — publicado como um chart OCI. Precisa de Postgres + ClickHouse e alguns secrets pré-criados (DSN do banco, chaves de autenticação). Veja docs/DEPLOY.md para o 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 Imposição
| Modo | Política DNS | Filtro eBPF | Caso de Uso |
|---|---|---|---|
| audit | Encaminhar tudo, registrar violações | Permitir tudo, registrar descartes | Construção de baseline, implantação inicial |
| block | NXDOMAIN para não listados | Descartar IPs não listados | Imposição em produção |
| allow | Sem imposição | Sem imposição | Projetos isentos |
Desenvolvimento
Compilação
# 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/
O plano de dados eBPF não está neste repo — ele reside no módulo
leitwacht-agent(CE). Regere seus esqueletos BPF lá (veja o Makefile desse repo:make ebpf-generate).
Teste
# 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
Documentação
| Documento | Conteúdo |
|---|---|
| docs/DEPLOY.md | Runbook completo de implantação no Kubernetes (secrets, ClickHouse, migrações, instalação de licença, exposição) |
| docs/MULTI_ORG.md | Configuração multi-org / multi-tenant |
| LICENSE, NOTICE | Termos BSL 1.1 (Licença de Alteração: MPL-2.0) e a divisão de licença CE/EE |
leitwacht-agent | O agente de plano de dados da Edição Comunitária MPL-2.0 (imposição eBPF / proxy DNS / nftables) — o motor por trás dos diagramas acima |