
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.
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:
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.
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).
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.
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:
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.
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:
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:
/etc/torrc
/lib/tor/keys/*
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:
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:
arm64
, x86_64
)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:
Makefile
per questi obiettivi potrebbe essere più lungo e complicato che scrivere il progetto stessoEd ecco i progetti che ci hanno permesso di ottenere tutto questo con poche righe di codice e relativamente poco impegno:
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
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.
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.
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:
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.
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.