Voltar às atualizações
New releaseAug 20, 2026

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

Compartilhar

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

ComponenteDescriçã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.

PacotePropósito
internal/agentgrpcServidor gRPC: ingere relatórios de violação do agente, serve streams de políticas e regras
internal/apiHandlers da API REST, middleware de autenticação, escopo RBAC
internal/authAutenticação OIDC (GitLab), sessões, CSRF
internal/storeAcesso a dados GORM (projetos, violações, baselines) + ClickHouse
internal/license, internal/licensemgrVerificação de licença EE (Ed25519 JWS) + ciclo de vida e gate de configuração (veja LICENSE)
internal/notifyEntrega de alertas (email/SES, Slack) + templates
internal/retentionRetenção/poda de dados
internal/mcp, internal/mcpauthServidor MCP + autenticação
ee/reporterCliente gRPC do agente EE para enviar violações e avisos ao backend
ee/policycache, ee/rulewatcher, ee/rulestoreCache 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=true nos 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

ModoPolítica DNSFiltro eBPFCaso de Uso
auditEncaminhar tudo, registrar violaçõesPermitir tudo, registrar descartesConstrução de baseline, implantação inicial
blockNXDOMAIN para não listadosDescartar IPs não listadosImposição em produção
allowSem imposiçãoSem imposiçãoProjetos 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

DocumentoConteúdo
docs/DEPLOY.mdRunbook completo de implantação no Kubernetes (secrets, ClickHouse, migrações, instalação de licença, exposição)
docs/MULTI_ORG.mdConfiguração multi-org / multi-tenant
LICENSE, NOTICETermos BSL 1.1 (Licença de Alteração: MPL-2.0) e a divisão de licença CE/EE
leitwacht-agentO 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

Categorias