Programmazione

Come GitHub usa eBPF per rendere i deploy sicuri: architettura e implementazione

Dario Fadda Aprile 20, 2026

Quando si parla di deployment safety, pochi casi studio sono più istruttivi di quello di GitHub: un’azienda che ospita il proprio codice sorgente sulla piattaforma che sta cercando di aggiornare. Questo crea una dipendenza circolare potenzialmente devastante — durante un’interruzione del servizio, il deploy che dovrebbe ripristinarlo potrebbe fallire proprio perché si appoggia alla piattaforma non disponibile.

Un recente articolo del blog di ingegneria di GitHub descrive come il team abbia risolto questo problema usando eBPF (extended Berkeley Packet Filter), una tecnologia kernel Linux che permette di eseguire codice sandboxed direttamente nel kernel senza modificarlo.

Il problema delle dipendenze nei deploy

GitHub ha identificato tre categorie di dipendenze problematiche nei propri script di deploy:

  • Dipendenze dirette: script che scaricano binari da github.com durante il deploy
  • Dipendenze nascoste: tool che controllano aggiornamenti su GitHub senza una richiesta esplicita
  • Dipendenze transitive: servizi interni che chiamano dipendenze esterne in modo indiretto

Il rischio è evidente: se github.com non è disponibile e il deploy ne dipende, si entra in un loop da cui è difficile uscire. Serviva un meccanismo per rilevare — e bloccare — queste dipendenze prima che causassero problemi in produzione.

eBPF: filtraggio kernel-level senza modificare il kernel

eBPF è un framework che consente di iniettare programmi nel kernel Linux in modo sicuro e verificato. Originariamente nato per il filtraggio dei pacchetti di rete (da cui il nome “Berkeley Packet Filter”), si è evoluto in una piattaforma generale per osservabilità, sicurezza e networking a bassa latenza.

GitHub ha sfruttato due tipi specifici di programmi eBPF:

  • BPF_PROG_TYPE_CGROUP_SKB: monitora il traffico in uscita (egress) e applica regole di blocco IP basate sui risultati della risoluzione DNS
  • BPF_PROG_TYPE_CGROUP_SOCK_ADDR: intercetta le query DNS e le reindirizza a un proxy userspace che valuta le richieste rispetto a una lista di domini bloccati

I cgroup Linux vengono usati per isolare i processi di deploy. A questi cgroup vengono poi agganciate (attached) le mappe e i programmi eBPF, che possono così osservare e controllare il traffico di rete generato da quei processi specifici.

L’architettura del sistema

Il flusso di funzionamento è il seguente:

  1. Un processo di deploy tenta di risolvere un nome di dominio (es. github.com)
  2. Il programma eBPF intercetta la query DNS tramite BPF_PROG_TYPE_CGROUP_SOCK_ADDR
  3. La query viene reindirizzata a un proxy userspace
  4. Il proxy verifica il dominio rispetto alla policy attiva
  5. Se il dominio è nella lista bloccata, la risposta viene falsificata (restituendo un IP non raggiungibile)
  6. Il programma BPF_PROG_TYPE_CGROUP_SKB monitora il traffico IP per rafforzare il blocco
  7. Tutte le violazioni vengono loggate con PID, nome del processo, comando e transaction ID DNS

Particolarmente elegante è l’uso di mappe eBPF (BPF maps) per condividere stato tra i programmi kernel e il proxy userspace, consentendo aggiornamenti dinamici alla policy senza dover ricaricare i programmi.

Implementazione con cilium/ebpf e Go

Per semplificare lo sviluppo, il team ha usato la libreria Go cilium/ebpf, uno dei wrapper eBPF più maturi disponibili oggi. I programmi eBPF sono scritti in C e compilati con bpf2go, uno strumento che genera automaticamente le struct Go corrispondenti per interagire con le mappe e i programmi nel kernel.

Un esempio semplificato di come si carica e aggancia un programma eBPF con cilium/ebpf:

// Carica i programmi eBPF compilati
objs := bpfObjects{}
if err := loadBpfObjects(&objs, nil); err != nil {
    log.Fatalf("loading objects: %v", err)
}
defer objs.Close()

// Aggancia il programma al cgroup del processo di deploy
l, err := link.AttachCgroup(link.CgroupOptions{
    Path:    "/sys/fs/cgroup/deploy",
    Attach:  ebpf.AttachCGroupInetEgress,
    Program: objs.FilterEgress,
})
if err != nil {
    log.Fatalf("attaching cgroup: %v", err)
}
defer l.Close()

log.Println("eBPF program attached, monitoring egress traffic...")

La policy viene aggiornata dinamicamente scrivendo nelle mappe eBPF, senza necessità di riavviare nulla:

// Blocca un dominio aggiungendolo alla mappa eBPF
key := []byte("github.com")
value := uint32(1) // 1 = blocked
if err := objs.BlockedDomains.Put(key, value); err != nil {
    log.Fatalf("updating map: %v", err)
}

Questo approccio consente di modificare le policy a runtime, ad esempio durante un incidente, aggiungendo o rimuovendo domini dalla blocklist senza interrompere i processi in esecuzione.

Correlazione PID e DNS transaction ID

Uno degli aspetti più sofisticati dell’implementazione è la capacità di correlare le query DNS bloccate al processo specifico che le ha generate. Il sistema usa una mappa eBPF per tenere traccia della coppia (PID, DNS transaction ID): quando il proxy userspace vede una query, può risalire al processo che l’ha originata e loggare il percorso completo dell’esecuzione, incluso il comando invocato.

Questo livello di visibilità è fondamentale per il debugging: anziché sapere solo che “qualcosa ha chiamato github.com”, gli ingegneri possono vedere esattamente quale script, a quale riga, stava tentando di accedere alla risorsa bloccata.

Risultati dopo sei mesi di rollout

Dopo sei mesi di utilizzo in produzione, il sistema ha permesso a GitHub di:

  • Rilevare dipendenze problematiche prima che causino guasti durante i deploy
  • Identificare tool e script che accedevano silenziosamente a github.com durante le operazioni di deploy
  • Migliorare la velocità di recovery dagli incidenti, eliminando la circolarità delle dipendenze
  • Costruire un inventario delle dipendenze esterne degli script di deploy, utile per la pianificazione della resilienza

Perché eBPF è la scelta giusta per questo caso d’uso

Soluzioni alternative avrebbero avuto limitazioni significative: un firewall a livello di rete avrebbe bloccato il traffico in modo troppo grossolano, impedendo anche il normale funzionamento dei servizi. Proxy applicativi avrebbero richiesto modifiche agli script di deploy. eBPF consente invece di applicare policy granulari, per-processo e dinamiche, senza modificare gli script esistenti né aggiungere overhead significativo alle operazioni normali.

Il fatto che sia una tecnologia kernel-level la rende anche difficile da aggirare accidentalmente: non è sufficiente usare una libreria di networking alternativa o bypassare il resolver DNS del sistema per evadere i controlli.

Conclusioni

L’approccio di GitHub dimostra come eBPF stia trasformando la sicurezza e l’osservabilità delle infrastrutture moderne. Non più solo strumento per profiling di rete, eBPF diventa un componente architetturale per l’enforcement di policy a runtime, invisibile alle applicazioni e aggiornabile senza downtime.

Per chi gestisce infrastrutture critiche o pipeline CI/CD complesse, questo caso studio offre un modello replicabile: usare eBPF per imporre vincoli ai processi di deploy e garantire che il sistema possa sempre ripristinarsi indipendentemente dallo stato dei servizi che ospita.

Fonte: How GitHub uses eBPF to improve deployment safety — GitHub Engineering Blog

💬 Unisciti alla discussione!


Questo è un blog del Fediverso: puoi trovare quindi questo articolo ovunque con @blog@spcnet.it e ogni commento/risposta apparirà qui sotto.

Se vuoi commentare su Come GitHub usa eBPF per rendere i deploy sicuri: architettura e implementazione, utilizza la discussione sul Forum.
Condividi la tua esperienza, confrontati con altri professionisti e approfondisci i dettagli tecnici nel nostro 👉 forum community