eBPF: observabilidade e segurança em nível de kernel sem modificar aplicações
1. O que é eBPF e por que ele transforma a observabilidade
1.1. Definição e origem: do BPF clássico ao eBPF moderno
O eBPF (extended Berkeley Packet Filter) é uma tecnologia que permite executar programas sandboxed no kernel Linux sem a necessidade de modificar o código-fonte do kernel ou carregar módulos. Originalmente, o BPF clássico foi criado para filtrar pacotes de rede com eficiência. O eBPF moderno expandiu drasticamente esse conceito, tornando-se uma máquina virtual dentro do kernel capaz de executar programas em resposta a eventos de sistema, rede, segurança e rastreamento.
1.2. Arquitetura básica: programas sandboxed no kernel
Programas eBPF são escritos em uma linguagem de alto nível (geralmente C) e compilados para bytecode. Esse bytecode é então carregado no kernel, onde passa por um verificador rigoroso (verifier) que garante que o programa não entre em loops infinitos, não acesse memória inválida e termine em tempo finito. Após a verificação, o bytecode é compilado para código nativo via JIT (Just-In-Time) compiler, garantindo desempenho próximo ao de código kernel nativo.
// Exemplo conceitual de programa eBPF em C
// (compilado com clang -target bpf)
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
SEC("kprobe/sys_execve")
int trace_execve(struct pt_regs *ctx) {
char comm[16];
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk("Executando: %s\n", comm);
return 0;
}
char LICENSE[] SEC("license") = "GPL";
1.3. Casos de uso disruptivos
eBPF permite observabilidade, segurança e profiling sem instrumentação de aplicações. Isso significa que você pode monitorar sistemas legados, containers e ambientes de produção sem reiniciar serviços, recompilar código ou adicionar agentes pesados. Os principais casos de uso incluem: rastreamento de syscalls, monitoramento de rede, profiling de CPU, detecção de anomalias e políticas de segurança dinâmicas.
2. Mecanismos fundamentais: hooks, maps e verificação
2.1. Tipos de hooks
eBPF pode ser anexado a diversos pontos do kernel:
- kprobes: intercepção de funções do kernel (dinâmico)
- tracepoints: pontos de rastreamento estáveis e documentados
- uprobes: intercepção de funções em espaço do usuário
- XDP: processamento de pacotes no driver de rede, antes do kernel
- sockets: filtragem e monitoramento de tráfego de rede
2.2. Estruturas de dados compartilhadas: eBPF maps
Maps são estruturas de dados que permitem comunicação entre programas eBPF e espaço do usuário. Os tipos mais comuns incluem:
// Exemplo de criação de hash map em BCC (Python)
from bcc import BPF
bpf = BPF(src_file="trace_execve.c")
bpf.attach_kprobe(event=bpf.get_syscall_fnname("execve"), fn_name="trace_execve")
# Map do tipo hash para contar execuções por comando
counts = bpf.get_table("execve_counts")
for key, value in counts.items():
print(f"{key.comm.decode()}: {value.value}")
2.3. Verificador e JIT compiler
O verificador (verifier) analisa cada programa eBPF antes da execução, garantindo:
- Ausência de loops não limitados
- Acesso seguro à memória
- Terminação garantida em tempo finito
- Compatibilidade com a versão do kernel
O JIT compiler traduz o bytecode verificado para instruções nativas da CPU, resultando em desempenho comparável a código kernel escrito à mão.
3. eBPF para observabilidade profunda sem modificar código
3.1. Rastreamento de chamadas de sistema
Com tracepoints, é possível monitorar todas as syscalls sem modificar aplicações:
# bpftrace: rastrear todas as chamadas open()
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
3.2. Profiling contínuo de CPU
kprobes permitem amostrar a pilha de chamadas do kernel e espaço do usuário:
# bpftrace: amostragem de CPU a cada 99 Hz
bpftrace -e 'profile:hz:99 { @[kstack, ustack] = count(); }'
3.3. Métricas personalizadas
É possível criar contadores específicos para monitorar vazamento de memória, I/O de disco ou erros de aplicação:
# BCC: contagem de erros de alocação de memória
from bcc import BPF
bpf = BPF(text="""
#include <linux/sched.h>
BPF_HASH(alloc_errors, u32, u64);
TRACEPOINT_PROBE(syscalls, sys_enter_brk) {
u32 pid = bpf_get_current_pid_tgid();
u64 *count = alloc_errors.lookup(&pid);
if (count) {
(*count)++;
} else {
u64 init = 1;
alloc_errors.update(&pid, &init);
}
return 0;
}
""")
4. Segurança em nível de kernel com eBPF
4.1. Detecção de anomalias em tempo real
Programas eBPF podem monitorar execução de binários e acesso a arquivos sensíveis:
# Falco (baseado em eBPF): detectar execução de shell em container
- rule: Shell in Container
desc: Detecta execução de shell interativo em container
condition: evt.type=execve and container.id != host and proc.name in (bash, sh, zsh)
output: "Shell executado em container (user=%user.name command=%proc.cmdline container=%container.id)"
priority: WARNING
4.2. Implementação de políticas de segurança dinâmicas
eBPF pode ser usado com seccomp-bpf para criar filtros de syscalls granulares:
// Exemplo de filtro seccomp-bpf que bloqueia execve
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
};
4.3. Casos práticos
- Bloqueio de syscalls perigosos: uso de eBPF para bloquear
ptrace,mounterebootem containers - Detecção de rootkits: monitoramento de alterações em arquivos críticos do sistema
- Contenção de containers: políticas de rede baseadas em identidade com Cilium
5. Ferramentas e ecossistema prático
5.1. Principais frameworks
- BCC (BPF Compiler Collection): ferramenta madura com exemplos prontos para rastreamento
- bpftrace: linguagem de alto nível para one-liners de observabilidade
- libbpf: biblioteca C para desenvolvimento de programas eBPF portáveis (CO-RE)
5.2. Integração com stacks de observabilidade
eBPF pode exportar métricas e traces para Prometheus, Grafana e OpenTelemetry:
# Exemplo de exportação de métricas eBPF para Prometheus via node_exporter
# (usando bpf_exporter do iovisor)
bpf_exporter --config=syscalls.yaml --port=9435
5.3. Exemplo prático: rastreamento de latência HTTP
Sem modificar o servidor web (Nginx, Apache), podemos medir latência de requisições:
# bpftrace: medir tempo entre accept() e close() em servidor web
bpftrace -e '
kprobe:accept {
@start[tid] = nsecs;
}
kretprobe:close /@start[tid]/ {
$delta = nsecs - @start[tid];
@latency_hist = hist($delta / 1000);
delete(@start[tid]);
}
'
6. Desafios e boas práticas para times pequenos
6.1. Limitações
- Compatibilidade de kernel: recursos mais novos exigem kernel 5.x ou superior
- Overhead de coleta: programas mal escritos podem impactar desempenho
- Complexidade de debugging: programas eBPF são difíceis de depurar sem ferramentas adequadas
6.2. Estratégias de implantação
- Uso de sidecars (como Cilium) para ambientes Kubernetes
- Agentes leves (Falco, Tetragon) que já incluem programas eBPF otimizados
- Pipelines de dados com bufferização para evitar perda de eventos
6.3. Segurança do próprio eBPF
- Restringir quem pode carregar programas eBPF via
CAP_BPFeCAP_SYS_ADMIN - Usar assinatura de programas eBPF para evitar carregamento de código malicioso
- Monitorar logs de carregamento de programas eBPF
7. Casos de uso reais e tendências futuras
7.1. Exemplos em produção
- Netflix: profiling de CPU e memória em produção com eBPF
- Facebook: otimização de rede e roteamento com XDP
- Cilium: segurança de rede para Kubernetes baseada em eBPF
7.2. eBPF como base para Service Mesh
Projetos como Cilium e Istio (com eBPF) estão substituindo sidecars tradicionais por programas eBPF que oferecem observabilidade e segurança com menor latência.
7.3. O futuro
- eBPF no Windows: Microsoft está portando eBPF para Windows
- CO-RE (Compile Once – Run Everywhere): programas eBPF portáveis entre versões de kernel
- Adoção em edge computing: dispositivos com recursos limitados se beneficiam da leveza do eBPF
Referências
- Documentação oficial do eBPF (ebpf.io) — Visão geral completa da tecnologia, casos de uso e projetos do ecossistema
- BCC - BPF Compiler Collection (GitHub) — Repositório oficial com ferramentas, exemplos e documentação para desenvolvimento com BCC
- bpftrace - Guia de one-liners — Tutorial prático com exemplos de comandos bpftrace para observabilidade
- Cilium - eBPF para Kubernetes — Documentação do projeto Cilium que usa eBPF para segurança e observabilidade de rede em containers
- Falco - Runtime Security — Ferramenta de segurança baseada em eBPF para detecção de anomalias em tempo real
- eBPF no Windows - Microsoft — Projeto de portabilidade do eBPF para o ecossistema Windows