Patela: Una cantina piena di server con l’amnesia.

5 maggio 2025 - Infrastructure

L’Osservatorio ha finalmente acceso i primi nodi sperimentali su un’infrastruttura diskless, fisicamente ospitata nei nostri spazi e a basso consumo. In questo post spieghiamo i motivi che ci hanno spinto a lavorare su questo progetto e l’implementazione che abbiamo realizzato. Rilasciamo anche i sorgenti e la documentazione del software che abbiamo scritto, che continueremo a migliorare e che speriamo possa essere utile per replicare il nostro setup.

Motivazioni e Threat Model #

Come abbiamo spesso anticipato, gestire nodi Tor implica alcuni rischi e problemi abbastanza comuni, spesso legati al fatto che, in caso di indagini o altri problemi, non sempre chi di dovere è competente per capire come funziona Tor oppure, anche quando lo è, può scegliere di agire indiscriminatamente pur sapendo di non colpire la parte indagata. Esistono molti precedenti: in Austria, in Germania, negli Stati Uniti, in Russia e probabilmente molti altri. Alcuni dei nostri membri hanno sperimentato personalmente come anche in Italia questo possa essere il caso.

Nell’interesse di tutelare noi stessi, la nostra infrastruttura e l’anonimato e la privacy dei nostri utenti, dobbiamo quindi preoccuparci di una serie di scenari possibili, tra cui:

  • Tentativi di interrompere le nostre operazioni
  • Sequestro dei server e analisi dei dati
  • Compromissione fisica dei server
  • Compromissione remota dei server

Nel primo caso, il maggiore ostacolo è il costante invio di segnalazioni di abuse e lamentele per le attività della nostra rete. Per poter garantire la nostra operatività, come anticipato nei precedenti post, ora gestiamo direttamente la nostra rete, con indirizzi IP di nostra proprietà, instradati direttamente verso il nostro spazio fisico, riducendo al minimo tecnicamente possibile (per ora!) il numero di intermediari che hanno accesso o potere sulla nostra infrastruttura.

Fin dall’inizio del progetto abbiamo seguito due intuizioni principali: la prima è che, affrontando i problemi classici in modo meno convenzionale, avremmo potuto trovare soluzioni solide e aprire la strada anche per altre organizzazioni e progetti (come comprare una cantina!). La seconda è che, per mantenere vivo l’interesse, sia tra i nostri membri che all’esterno, le nostre attività devono essere divertenti, interessanti e innovative.

Infrastruttura di rete #

Come già raccontato, abbiamo un router nel datacenter di Milano che si occupa di annunciare il nostro AS e i nostri IP. Attualmente è collegato alla nostra cantina tramite un link XGS-PON 10G/2.5G, ma l’obiettivo è distribuirci maggiormente sul territorio e, dove possibile, riutilizzare le stesse risorse di rete (avremo presto aggiornamenti anche su questo fronte).

Schema dell’infrastruttura di rete.
Schema dell’infrastruttura di rete.

Uno degli elementi chiave di questa architettura è che ci fidiamo solo delle macchine su cui abbiamo accesso esclusivo. Questo significa che anche il nostro router principale al MIX di Milano è considerato potenzialmente malevolo. Per questo motivo, l’attenzione principale è rivolta al nostro datacenter a Torino.

Infrastruttura senza dischi e System Transparency #

System Transparency è un progetto originariamente finanziato da Mullvad per la loro infrastruttura VPN, e ora attivamente sviluppato e mantenuto da Glasklar Teknik. Lo scopo del progetto è quello di sviluppare un insieme di strumenti per poter eseguire e certificare sistemi trasparenti. L’idea è la seguente: per prima cosa, è necessario costruire immagini di sistema riproducibili, cioè produrre ISO o immagini simili che siano ricostruibili bit per bit da chiunque a partire dal sorgente, per poter dimostrare l’assenza di modifiche (o backdoor). In secondo luogo, è necessario che tutto il necessario per riprodurre queste immagini sia pubblico e documentato, così come le immagini stesse. Infine, è necessario garantire almeno altre due proprietà: la prima è che solo le immagini di sistema autorizzate possano essere utilizzate, la seconda è che esista un elenco pubblico e immutabile di tutte le immagini autorizzate (un cosiddetto transparency log).

Per riassumere, in sequenza, il concetto di system transparency richiede:

  • Di compilare il sistema in modo riproducibile
  • Di distribuire tutto il materiale e le istruzioni per la riproduzione
  • Di firmare le immagini di sistema con delle chiavi, tenute al sicuro
  • Di inviare a un transparency log tutte le firme effettuate

Tra i vari tool messi a disposizione dal progetto System Transparency, stboot svolge la maggior parte del lavoro. Il server viene avviato con un’immagine minimale locale che, grazie a stboot, scarica e verifica lo stage successivo: l’immagine di sistema riproducibile, firmata e destinata a eseguire Tor (o in futuro anche altri servizi). Grazie alla verifica della firma, possiamo ospitare le immagini anche remotamente o nel cloud senza particolari rischi di sicurezza.

Screenshot dell’avvio con stboot.
Screenshot dell’avvio con stboot.

Siccome il sistema diskless è ancora sperimentale, e nonostante l’obiettivo sia rendere tutta l’infrastruttura velocemente sostituibile, per ora abbiamo ancora alcuni servizi e apparati gestiti in modo classico:

  • Server VPN di manutenzione con rete separata, per l’accesso remoto degli amministratori.
  • Server DHCP: solo gli IP interni vengono distribuiti in un range di rete privata ed utilizzati per debug e manutenzione.
  • Server DNS: le buone pratiche di Tor suggeriscono di avere un proprio server DNS locale per ridurre le possibilità di analisi del traffico attraverso la risoluzione dei domini. Durante una connessione con Tor, infatti, sono i nodi di uscita a risolvere i domini. Per questo abbiamo configurato un nostro DNS ricorsivo locale.
  • Server HTTP: per servire l’immagine del sistema operativo ai server.
  • Switch managed: abbiamo ricevuto in dono un bellissimo switch gestito! Grazie a chi ha scelto di sostenerci in questa forma!

Patela #

Il problema dei software senza persistenza su disco è che non ricordano niente, nemmeno quelle poche configurazioni o chiavi necessarie per poter funzionare correttamente. Nel nostro caso abbiamo poche configurazioni essenziali per un nodo Tor:

  • Il file di configurazione di Tor, /etc/torrc
  • Le chiavi di identità del nodo, /lib/tor/keys/*
  • Le varie configurazioni di rete (IP e NAT)

Inoltre, queste configurazioni devono essere generate direttamente sulla macchina e aggiornate successivamente. Ad esempio, è necessario poter modificare la lista dei nodi che compongono la nostra famiglia. Chiaramente, avere immagini del sistema operativo diverse per ogni macchina sarebbe insensato e molto difficile da mantenere.

Nonostante esistano soluzioni come ansible-relayor, in seguito a considerazioni pratiche e di sicurezza abbiamo deciso di adottare un approccio diverso. Preferiamo che sia il singolo nodo a generare le proprie chiavi e a gestire la propria configurazione, e che questa venga applicata in modalità pull invece che push. In pratica, vogliamo che sia il nodo stesso a verificare periodicamente la presenza di aggiornamenti di configurazione, e che solo il nodo abbia il controllo delle proprie chiavi. È una distinzione importante in termini di sicurezza: cambiamenti malevoli su un eventuale server di configurazione non devono poter compromettere la sicurezza del nodo o delle sue chiavi.

Ed è così che è nato patela.

Patela è un software minimale che scarica e carica configurazioni e file da un server. Il server comunica le configurazioni di rete (principalmente, assegna gli IP disponibili e il gateway tramite un’API) e il client le legge e le applica. Tutti gli altri file che normalmente servirebbe persistere a ogni avvio della macchina vengono prima cifrati localmente usando il TPM, e poi caricati in formato cifrato sul server di configurazione. In questo modo, il server di configurazione non ha mai accesso alle chiavi delle macchine, né può attaccarle direttamente, se non causando un Denial of Service, ad esempio distribuendo IP o backup invalidi.

Il sistema presenta quindi i seguenti vantaggi:

  • Resistenza ad alcuni attacchi fisici, grazie all’uso del TPM per le chiavi di cifratura
  • Anti-forensic di default, non avendo dischi o memorie persistenti
  • Possibilità di resettare i nodi reinizializzando il TPM
  • In futuro, possibilità di effettuare remote attestation e certificare che le immagini di sistema in esecuzione siano quelle pubblicate
  • Grazie al remote attestation, potremo fare unseal del TPM solo quando le immagini sono genuine, garantendo così una chain of trust

Diagramma logico di patela.
Diagramma logico di patela.

Rust e tooling #

Siccome è in corso la riscrittura di Tor in Rust, che nel giro di poco tempo offrirà tutto il necessario per sostituire il classico C-Tor anche sui relays, abbiamo deciso di adeguarci e di utilizzare lo stesso linguaggio per una migliore compatibilità futura.

Durante lo sviluppo è emersa la chiara necessità di avere una toolchain flessibile, soprattutto dovendo utilizzare librerie in C e compilare per diverse piattaforme. Anche se l’architettura di patela non è concettualmente molto complicata, mantenere nel tempo un software con componenti così diversi non è semplice. Tuttavia, l’ecosistema Rust e i tool associati sono cresciuti molto negli ultimi anni, fornendo quasi tutto il necessario. In pratica, vogliamo costruire un client e un server, e abbiamo bisogno di:

  • Un database, per il server
  • Una libreria per scaricare e caricare risorse, per il client
  • Librerie esterne (TPM, mTLS, crypto, ecc.)
  • Compatibilità con diverse architetture a 64 bit, per il client (arm64, x86_64)
  • Per il client, possibilità di cross-compilazione con le librerie del sistema di destinazione

Spesso i container vengono utilizzati per soddisfare alcuni di questi requisiti, come la consistenza dell’ecosistema. Tuttavia, il nostro obiettivo è avere un’architettura semplice, leggera, che funzioni anche su macchine a basso consumo e che possa modificare le configurazioni di rete globali.

Ci sono anche una serie di cose che vorremmo evitare — un po’ per preferenza, un po’ per via dei requisiti che ci siamo dati:

  • Suddivisione in molti componenti, librerie, sottoprogetti, con tutto il lavoro di manutenzione aggiuntivo che comporta
  • Client e server, pur avendo ruoli diversi, hanno bisogno quasi delle stesse librerie e strutture dati
  • Il binario compilato è l’unico file necessario per il funzionamento: niente pacchetti o archivi. Inoltre, con l’uso di System Transparency, un binario dinamico non sarebbe comunque utile, poiché per aggiornare librerie e dipendenze dovremmo comunque rigenerare l’intera immagine
  • Scrivere un Makefile per questi obiettivi potrebbe essere più lungo e complicato che scrivere il progetto stesso

Ed ecco i progetti che ci hanno permesso di ottenere tutto questo con poche righe di codice e relativamente poco impegno:

  • cargo: il package manager che semplicemente funziona
  • clap: una solida base per scrivere programmi da command line
  • sqlx: piccola, semplice ed elegante libreria SQL
  • actix web: un framework web noto e maturo
  • constgen: libreria per inserire costanti durante la compilazione, utile per evitare archivi esterni
  • cargo zigbuild: permette di usare il compilatore di Zig con cargo, rendendo la cross-compilazione molto più semplice
  • rustls: per la gioia di non dover comunicare con OpenSSL

Compilazione e configurazione #

Una volta compilato il binario di patela, contenente anche tutti gli altri asset necessari, è sufficiente copiarlo nell’immagine di sistema prima di firmarla e distribuirla.

Come anticipato, usiamo constgen, che permette di generare facilmente costanti valutate durante la compilazione, ad esempio inserendo certificati SSL del client e il template di configurazione di Tor.

let server_ca_file = env::var("PATELA_CA_CERT").unwrap_or(String::from("../certs/ca-cert.pem"));
let client_key_cert_file = env::var("PATELA_CLIENT_CERT").unwrap();

let server_ca = fs::read(server_ca_file).unwrap();
let client = fs::read(client_key_cert_file).unwrap();

let const_declarations = [
  const_declaration!(pub SERVER_CA = server_ca),
  const_declaration!(pub CLIENT_KEY_CERT = client),
]
.join("\n");

Nonostante cargo supporti la cross-compilazione, utilizzando dipendenze esterne in C come tpm2-tss dobbiamo assicurarci che la libc utilizzata in fase di compilazione sia compatibile con quella presente nelle immagini di sistema. Come anticipato, il compilatore Zig, integrato direttamente con cargo grazie a cargo-zigbuild, permette di specificare anche la libc di destinazione, oltre all’architettura e al kernel:

$ cargo zigbuild --target x86_64-unknown-linux-gnu.2.36

Rete #

Abbiamo già parlato di come far girare diversi server Tor sulla stessa interfaccia di rete con diversi IP utilizzando un firewall ad alto livello come Shorewall. Adesso abbiamo applicato le stesse regole ma con nftables, l’interfaccia nativa di Linux per scrivere regole di rete.

Le regole da definire sono due: una per identificare i pacchetti in base allo user ID, e una per configurare il source NAT.

$ nft 'add rule ip filter OUTPUT skuid <process id> counter meta mark set <mark id>'
$ nft 'add rule ip filter <interface> mark and 0xff == <mark id> counter snat to <source ip>'

Le regole sono quindi direttamente applicate da patela, utilizzando la libreria nftl.

Biscotti, mTLS e TPM #

Uno dei nostri requisiti fondamentali è poter identificare i client, autenticarli e, se necessario, revocarli singolarmente. Inoltre, non abbiamo garanzie sulla sicurezza della rete tra client e server, che è tendenzialmente remoto (per evitare che ci siano macchine con memoria persistente nei nostri spazi fisici).

Utilizziamo Mutual TLS (mTLS) per la comunicazione. Rispetto al TLS tradizionale, dove solo il client verifica l’identità del server mTLS prevede un’autenticazione reciproca. Questo approccio ci offre un duplice vantaggio e rappresenta una soluzione unica a diversi problemi. Da un lato, TLS garantisce nativamente la sicurezza del trasporto e la gestione della revoca dei certificati; dall’altro, l’autenticazione del client tramite certificato ci consente di identificarlo in modo univoco rispetto agli altri nodi o macchine.
In questo modo possiamo registrare e mantenere nel database del server informazioni specifiche come l’IP assegnato, il nome e altri dati correlati.

Lo svantaggio principale dell’uso di mTLS è la gestione dei certificati e del loro rinnovo. Ognuno ha diritto a una scelta azzardata per progetto — altrimenti che gusto c’è! La nostra è stata Biscuit, un token di autenticazione simile a JWT. L’unico motivo per cui ci serve un token di sessione è evitare di dover autenticare ogni singolo endpoint dell’API del server.

Per quanto riguarda il client, la magia sta tutta nel TPM. Le librerie e gli esempi spesso non sono esaustivi, e lavorare con i TPM può essere un’esperienza frustrante. Nel nostro caso, abbiamo la necessità di far sopravvivere una chiave al riavvio della macchina, poiché quella chiave è l’unico elemento persistente all’interno della singola macchina.

Utilizziamo un approccio Trust On First Use (TOFU): al primo avvio, il client genera una chiave primaria nel TPM e con essa cifra una seconda chiave AES-GCM, che verrà usata per cifrare i backup reali. Questa chiave AES-GCM viene poi salvata sul server, dopo essere stata cifrata con il TPM. Questo significa che solo il nodo fisico è in grado di decifrare i backup delle sue configurazioni, e che eliminare un nodo compromesso equivale a rimuovere dal server il suo backup cifrato. La logica per determinare se un TPM è già stato inizializzato o meno avviene completamente sul client, ed è implementata dentro patela.

In futuro, integrare nativamente le chiavi a lungo termine dei relay con arti potrebbe essere una soluzione migliore e più efficiente, soprattutto se accompagnata da un sistema di measured boot che ne gestisca l’unseal.

Sviluppi futuri #

Questo post riassume quella che vuole essere solo la fase iniziale del nostro progetto. Sappiamo che c’è ancora molto da fare e da migliorare, e vogliamo condividere con voi la nostra lista dei prossimi desideri:

  • Stack di rete open source: sia al punto di scambio di Milano che nel nostro datacenter utilizziamo router con software proprietario (Mikrotik CCR2004-1G-12S+2XS e Zyxel XGS1250-12). Ci piacerebbe poterli convertire entrambi per usare software open source su hardware open source.
  • Cantina-OS open source: per ora abbiamo pubblicato solo il codice di patela, ma presto rilasceremo anche le nostre configurazioni per l’immagine del sistema operativo.
  • Migliorare la gestione dei certificati: attualmente ricompiliamo patela per ogni nodo fisico per inserire il certificato TLS corretto. Vorremmo passare a un singolo certificato per tutti i client, spostando l’autenticazione sulla TPM tramite attestazione remota dell’hardware. Questo semplificherebbe la gestione degli aggiornamenti e renderebbe possibile l’attestazione anche per macchine virtuali.

In pratica #

Abbiamo acceso quattro exit node, usando patela e System Transparency:

Sono tutti in esecuzione su un singolo Protectli con coreboot, superando più di 1 Gbps di banda totale effettiva.

Foto della macchina Protectli in cantina.
Foto della macchina Protectli in cantina.

Hai letto un articolo della sezione Infrastruttura, dove raccontiamo il nostro impegno, sia materiale che digitale, per un’infrastruttura costruita come atto politico di riappropriazione delle risorse digitali.

Siamo un’organizzazione no-profit gestita interamente da volontari. Se apprezzi il nostro lavoro, puoi aiutarci con una donazione: accettiamo contributi economici, ma anche materiale e banda per sostenere le nostre attività. Per sapere come supportarci, visita la pagina delle donazioni.

Articoli recenti