RPKI ROA per BGP: creare ROA, validare le rotte in BIRD2 e FRR
Crea ROA IPv4 e IPv6 nel portale RIPE NCC, installa Routinator come cache RTR, configura la validazione RPKI in BIRD2 e FRRouting e verifica lo stato dei prefissi con bgp.tools e RIPE Stat.
Senza RPKI, qualsiasi ASN può originare qualsiasi prefisso. Un Route Origin Authorization (ROA) lega il tuo prefisso al tuo ASN in modo crittografico, e la Route Origin Validation (ROV) permette al tuo router di rifiutare gli annunci non validi. Questo tutorial copre l'intera catena: creare ROA nel portale RIPE NCC, eseguire Routinator come cache RPKI locale, configurare la validazione in BIRD2 e FRRouting e verificare che tutto funzioni.
Prerequisiti: un ASN registrato, prefissi IP assegnati (PA o PI), una sessione BGP funzionante su un VPS Linux (BGP con IP proprio su un VPS) e BIRD2 (Configurazione BGP BIRD2) o FRR (Configurazione BGP FRR) già in esecuzione.
Cos'è RPKI e perché il tuo prefisso BGP ha bisogno di un ROA?
Resource Public Key Infrastructure (RPKI) è un framework crittografico definito nella RFC 6480 che lega le risorse numeriche Internet (prefissi IP, ASN) ai loro legittimi titolari tramite certificati X.509 emessi dai Regional Internet Registry. Un Route Origin Authorization (ROA) è un oggetto firmato che dichiara: "l'ASN X è autorizzato a originare il prefisso Y con una lunghezza massima di Z." I validatori recuperano questi ROA e trasmettono il risultato ai router tramite il protocollo RPKI-to-Router (RTR) (RFC 8210).
Quando un router riceve un aggiornamento BGP, verifica l'ASN di origine e il prefisso nella propria tabella ROA locale. Ogni prefisso ottiene uno dei tre stati di validazione:
| Stato | Significato | Azione raccomandata |
|---|---|---|
| Valid | Esiste un ROA che corrisponde all'ASN di origine e alla lunghezza del prefisso | Accettare |
| Invalid | Esiste un ROA ma l'ASN di origine o la lunghezza del prefisso non corrispondono | Rifiutare |
| Not Found | Nessun ROA copre questo prefisso | Accettare (opzionalmente con local-pref più basso) |
Senza un ROA, i tuoi prefissi appaiono come "Not Found." Meglio di "Invalid", ma le reti che eseguono ROV preferiranno le rotte "Valid" dei tuoi peer rispetto ai tuoi annunci "Not Found" quando entrambi sono disponibili. Creare ROA è il primo passo. Validare le rotte in ingresso protegge la tua rete dall'accettare prefissi dirottati.
Come creare ROA IPv4 e IPv6 nel portale RIPE NCC?
Accedi al portale RIPE NCC, naviga su Resources, poi RPKI Dashboard. Se non hai ancora inizializzato RPKI, seleziona "Hosted" certificate authority. RIPE NCC gestisce la CA e la firma per te. Una volta attiva la Hosted CA, passa alla scheda BGP Announcements. RIPE precompila i suggerimenti ROA in base ai tuoi annunci BGP attuali.
- Clicca su Create ROA (o + New ROA nella scheda ROA).
- Imposta Origin ASN con il tuo numero AS (ad esempio
AS213279). - Imposta Prefix con la tua allocazione IPv4 (ad esempio
192.0.2.0/24). - Imposta Maximum Length uguale alla lunghezza del prefisso (
/24). Non aumentarlo. Vedi la sezione maxLength più avanti. - Clicca su Publish.
- Ripeti per il tuo prefisso IPv6 (ad esempio
2001:db8::/48con lunghezza massima/48).
Verifica nel RPKI Dashboard che lo stato del ROA mostri "Published." La propagazione ai validatori richiede tipicamente da 10 a 20 minuti, a seconda del loro intervallo di aggiornamento.
Promemoria dual-stack: crea un ROA per prefisso. Se annunci 192.0.2.0/24 e 2001:db8::/48, servono due ROA. Se annunci more-specific aggiuntivi (un /25 ricavato dal /24), ognuno necessita del proprio ROA con il proprio binding ASN.
Come installare Routinator come cache RPKI-RTR su Linux?
Routinator è un RPKI Relying Party (validatore) sviluppato da NLnet Labs. Recupera e valida i ROA da tutti e cinque i trust anchor dei RIR, poi serve i Validated ROA Payloads (VRP) al router tramite il protocollo RTR. Versione stabile attuale: 0.15.1.
Installazione dal repository NLnet Labs
Su Debian 12 o Ubuntu 24.04:
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
Aggiungi la chiave di firma e il repository NLnet Labs:
curl -fsSL https://packages.nlnetlabs.nl/aptkey.asc | sudo gpg --dearmor -o /usr/share/keyrings/nlnetlabs-archive-keyring.gpg
Per Debian:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nlnetlabs-archive-keyring.gpg] https://packages.nlnetlabs.nl/linux/debian $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/nlnetlabs.list > /dev/null
Per Ubuntu:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nlnetlabs-archive-keyring.gpg] https://packages.nlnetlabs.nl/linux/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/nlnetlabs.list > /dev/null
Installa Routinator:
sudo apt update
sudo apt install -y routinator
Il pacchetto installa un servizio systemd che si avvia automaticamente. Routinator gira con l'utente routinator.
Verifica del servizio
sudo systemctl status routinator
Dovresti vedere active (running). La prima sincronizzazione richiede da 2 a 5 minuti mentre Routinator recupera tutti i certificati dei trust anchor e valida l'insieme globale dei ROA.
Verifica che la sincronizzazione iniziale sia completata interrogando l'API HTTP (la versione pacchettizzata invia i log a syslog con pochi dettagli; l'API HTTP è la fonte affidabile):
curl -s http://127.0.0.1:8323/api/v1/status | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'IPv4 VRPs: {d[\"payload\"][\"routeOriginsIPv4\"][\"final\"]}, IPv6 VRPs: {d[\"payload\"][\"routeOriginsIPv6\"][\"final\"]}')"
Se la sincronizzazione è ancora in corso, i contatori saranno zero. Attendi da 2 a 5 minuti e riprova. Quando vedi contatori diversi da zero (centinaia di migliaia per IPv4, decine di migliaia per IPv6), la sincronizzazione iniziale è completata.
Configurazione
La configurazione del pacchetto si trova in /etc/routinator/routinator.conf. I valori predefiniti sono sicuri: RTR ascolta su 127.0.0.1:3323 e HTTP su 127.0.0.1:8323. Entrambi sono vincolati solo a localhost.
Impostazioni principali:
| Opzione | Predefinito | Scopo |
|---|---|---|
rtr-listen |
["127.0.0.1:3323"] |
Server RTR per i router |
http-listen |
["127.0.0.1:8323"] |
Interfaccia HTTP e API |
refresh |
600 | Secondi tra le sincronizzazioni RPKI |
retry |
600 | Secondi prima di riprovare dopo una sincronizzazione fallita |
expire |
7200 | Secondi prima che i VRP in cache siano considerati scaduti |
Se BIRD2 o FRR gira sulla stessa macchina (configurazione tipica per un VPS BGP), mantieni il binding predefinito su 127.0.0.1. Nessuna modifica al firewall necessaria.
Se esegui Routinator su un server separato, vincolalo a un IP privato e limita l'accesso:
sudo ufw allow from 10.0.0.0/24 to any port 3323 proto tcp comment "RTR from routers"
Verifica l'interfaccia HTTP:
curl -s http://127.0.0.1:8323/api/v1/status | head -20
Restituisce JSON con il conteggio VRP attuale, l'ora dell'ultima sincronizzazione e lo stato del validatore.
Come configurare la validazione RPKI in BIRD2?
BIRD2 supporta nativamente RPKI tramite il protocollo rpki (disponibile da BIRD 2.0; Ubuntu 24.04 fornisce BIRD 2.14). Si connette a Routinator via RTR, popola le tabelle ROA e fornisce la funzione roa_check() per i filtri di importazione. Nessuna libreria esterna necessaria.
Aggiungi quanto segue alla tua configurazione BIRD2 (tipicamente /etc/bird/bird.conf):
Definire le tabelle ROA
roa4 table roa_v4;
roa6 table roa_v6;
Configurare il protocollo RPKI
protocol rpki rpki_routinator {
roa4 { table roa_v4; };
roa6 { table roa_v6; };
remote 127.0.0.1 port 3323;
retry keep 90;
refresh keep 600;
expire keep 7200;
}
La parola chiave keep dice a BIRD di preferire i valori dei timer forniti dal server, con fallback sui valori specificati. retry 90 significa che BIRD si riconnette 90 secondi dopo la perdita della sessione RTR.
Aggiungere la validazione ROA al filtro di importazione
filter bgp_import_v4 {
if (roa_check(roa_v4, net, bgp_path.last_nonaggregated) = ROA_INVALID) then {
print "RPKI INVALID: ", net, " from AS", bgp_path.last;
reject;
}
if (roa_check(roa_v4, net, bgp_path.last_nonaggregated) = ROA_VALID) then {
bgp_local_pref = 200;
}
accept;
}
filter bgp_import_v6 {
if (roa_check(roa_v6, net, bgp_path.last_nonaggregated) = ROA_INVALID) then {
print "RPKI INVALID: ", net, " from AS", bgp_path.last;
reject;
}
if (roa_check(roa_v6, net, bgp_path.last_nonaggregated) = ROA_VALID) then {
bgp_local_pref = 200;
}
accept;
}
bgp_path.last_nonaggregated è più sicuro di bgp_path.last perché salta le voci AS_SET dall'aggregazione. Le rotte non valide vengono rifiutate. Le rotte valide ottengono un local-pref più alto. Le rotte Not Found passano con il local-pref predefinito.
Applicare il filtro al peer BGP
protocol bgp upstream_v4 {
local as 213279;
neighbor 198.51.100.1 as 64500;
ipv4 {
import filter bgp_import_v4;
import table;
export where source ~ [RTS_STATIC, RTS_BGP];
};
}
La direttiva import table è importante. Permette a BIRD di rivalutare le rotte filtrate quando la tabella ROA cambia, senza bisogno di un reset completo della sessione.
Ricaricare e verificare
sudo birdc configure
Controlla la sessione RPKI:
sudo birdc show protocols all rpki_routinator
Cerca Established nell'output. Poi controlla il contenuto della tabella ROA:
sudo birdc show route table roa_v4 count
Dovresti vedere centinaia di migliaia di voci (la tabella ROA globale conta oltre 800.000 VRP a inizio 2026).
Controlla la validazione di un prefisso specifico:
sudo birdc show route 192.0.2.0/24 all
L'output include un campo ROA che mostra valid, invalid o unknown (not found).
Come configurare la validazione RPKI in FRRouting?
FRRouting supporta RPKI tramite il modulo rpki, che usa librtr internamente (Ubuntu 24.04 fornisce FRR 8.4.4; FRR 9.x+ e 10.x sono supportati). Il modulo si connette al server RTR di Routinator e si integra con le route-map BGP.
Installare il modulo RPKI
Su Debian/Ubuntu con FRR già installato:
sudo apt install -y frr-rpki-rtrlib
Abilitare il modulo
Modifica /etc/frr/daemons e aggiungi -M rpki alle opzioni di bgpd:
bgpd_options=" -A 127.0.0.1 -M rpki"
Riavvia FRR:
sudo systemctl restart frr
Verifica che bgpd abbia caricato il modulo:
sudo vtysh -c "show rpki cache-server"
Se il comando viene eseguito senza errori (l'output potrebbe essere vuoto prima di configurare un cache), il modulo è caricato. Se ottieni % Unknown command, manca il flag -M rpki oppure frr-rpki-rtrlib non è installato.
Configurare il cache RTR
Entra in vtysh e configura:
sudo vtysh
configure terminal
rpki
rpki cache 127.0.0.1 3323 preference 1
rpki polling_period 300
rpki expire_interval 7200
rpki retry_interval 600
exit
Nota: FRR 9.x+ usa la sintassi rpki cache tcp 127.0.0.1 3323 preference 1 (con la parola chiave tcp esplicita). FRR 8.x usa rpki cache 127.0.0.1 3323 preference 1 senza. Verifica la tua versione con vtysh -c "show version".
Creare le route-map per gli stati RPKI
route-map rpki-filter permit 10
match rpki valid
set local-preference 200
exit
route-map rpki-filter deny 20
match rpki invalid
exit
route-map rpki-filter permit 30
match rpki notfound
exit
Questo accetta le rotte valide con local-pref elevato, rifiuta le rotte non valide e accetta le rotte not-found con il local-pref predefinito.
Applicare la route-map al vicino BGP
router bgp 213279
neighbor 198.51.100.1 remote-as 64500
address-family ipv4 unicast
neighbor 198.51.100.1 route-map rpki-filter in
neighbor 198.51.100.1 soft-reconfiguration inbound
exit-address-family
address-family ipv6 unicast
neighbor 2001:db8::1 route-map rpki-filter in
neighbor 2001:db8::1 soft-reconfiguration inbound
exit-address-family
exit
soft-reconfiguration inbound è obbligatorio. Senza, FRR non può rivalutare le rotte esistenti quando il cache RPKI si aggiorna. FRR conserva le rotte non modificate ricevute dal peer e riapplica la route-map quando i VRP cambiano.
Salva la configurazione:
write memory
end
Verifica
Controlla la connessione RTR:
sudo vtysh -c "show rpki cache-connection"
Cerca (connected) nell'output. Poi controlla la tabella dei prefissi:
sudo vtysh -c "show rpki prefix-table" | head -20
Filtra le rotte BGP per stato di validazione:
sudo vtysh -c "show bgp ipv4 unicast rpki valid" | head -20
sudo vtysh -c "show bgp ipv4 unicast rpki invalid"
L'output invalid dovrebbe mostrare le rotte che stai rifiutando attivamente.
BIRD2 vs FRR: configurazione RPKI a colpo d'occhio
| Caratteristica | BIRD2 | FRR |
|---|---|---|
| Installazione modulo | Integrato (nessun pacchetto extra) | Pacchetto frr-rpki-rtrlib + flag -M rpki |
| Configurazione RTR | Blocco protocol rpki con remote |
Comando rpki cache in vtysh |
| Tabelle ROA | Tabelle roa4/roa6 esplicite |
Interne, non direttamente esposte |
| Meccanismo di filtraggio | roa_check() nel filtro di importazione |
match rpki nella route-map |
| Rivalutazione automatica | Direttiva import table |
soft-reconfiguration inbound |
| Mostrare conteggio ROA | birdc show route table roa_v4 count |
vtysh show rpki prefix-table |
| Mostrare validazione | birdc show route ... all (campo ROA) |
vtysh show bgp rpki valid/invalid/notfound |
Come verificare lo stato RPKI del tuo prefisso?
Dopo aver creato i ROA e configurato la validazione, verifica da più punti di osservazione.
Verifica locale
Sul router stesso, controlla che il tuo prefisso risulti valido:
BIRD2:
sudo birdc show route 192.0.2.0/24 all | grep -i roa
FRR:
sudo vtysh -c "show rpki prefix-table 192.0.2.0/24"
Entrambi dovrebbero mostrare il tuo ASN come origine autorizzata.
API HTTP di Routinator
curl -s "http://127.0.0.1:8323/api/v1/validity/AS213279/192.0.2.0/24"
Restituisce JSON con lo stato di validazione, i VRP corrispondenti e il trust anchor di origine.
bgp.tools
Apri https://bgp.tools/prefix/192.0.2.0/24 nel browser. La colonna RPKI mostra uno scudo verde per Valid, rosso per Invalid o grigio per Not Found. Prevedi da 15 a 30 minuti dopo la creazione del ROA perché gli strumenti esterni rilevino il cambiamento.
RIPE Stat
Interroga l'API di validazione RPKI:
curl -s "https://stat.ripe.net/data/rpki-validation/data.json?resource=AS213279&prefix=192.0.2.0/24" | python3 -m json.tool
Cerca "status": "valid" nella risposta. RIPE Stat mostra anche quali ROA coprono il prefisso e se il maxLength corrisponde.
Ripeti per IPv6
Esegui gli stessi controlli con il tuo prefisso IPv6. Ogni comando sopra accetta prefissi IPv6. Sostituisci 192.0.2.0/24 con 2001:db8::/48 e verifica che entrambe le famiglie di indirizzi siano coperte.
Perché evitare un maxLength superiore alla lunghezza del prefisso?
Imposta maxLength uguale alla lunghezza del tuo prefisso. Questa è la raccomandazione della RFC 9319 (che aggiorna ed estende la RFC 7115).
Quando imposti maxLength a /24 su un ROA /20, autorizzi il tuo ASN a originare il /20 e ogni more-specific fino a /24. Questo significa che 16 /24 sono coperti. Un attaccante che dirotta uno di questi /24 con il tuo ASN come origine supererà la validazione RPKI come "Valid." Il more-specific dirottato vince per longest-match routing, e il ROA non può aiutarti perché hai autorizzato quella lunghezza.
Questo si chiama forged-origin sub-prefix hijack. Misurazioni del 2017 citate nella RFC 9319 hanno rilevato che l'84% dei ROA che usavano maxLength erano vulnerabili a questo attacco.
Esempio concreto:
| ROA | Cosa autorizza |
|---|---|
192.0.2.0/20, maxLength /20 |
Solo 192.0.2.0/20 dal tuo ASN. Sicuro. |
192.0.2.0/20, maxLength /24 |
/20, /21, /22, /23, /24 dal tuo ASN. Qualsiasi /24 può essere dirottato falsificando il tuo ASN di origine. |
Quando maxLength > lunghezza del prefisso è accettabile? Solo quando effettivamente deaggreghi in produzione (ad esempio annunciando un /20 e specifici /24 per traffic engineering) e ogni prefisso deaggregato deve essere validato. In quel caso, crea ROA individuali per ogni prefisso annunciato invece di un ROA con maxLength ampio. Un ROA per annuncio è il modello più sicuro.
Eccezione per mitigazione DDoS: se usi un servizio come un centro di scrubbing che riannuncia i tuoi more-specific dal tuo ASN, potresti aver bisogno di maxLength per coprire quei prefissi. Documenta questa eccezione e controllala regolarmente.
Cosa succede quando il cache RPKI va in down?
Quando Routinator si ferma o diventa irraggiungibile, il comportamento del router dipende dal timer di scadenza.
BIRD2 mantiene l'ultima tabella ROA nota in memoria per la durata di expire (predefinito 7200 secondi / 2 ore). Durante questa finestra, la validazione continua normalmente con dati obsoleti. Dopo la scadenza, BIRD rimuove tutte le voci ROA e ogni rotta torna a "Not Found." Nessuna rotta viene rifiutata per invalidità, ma nessuna rotta ottiene il bonus di local-pref valido.
FRR si comporta in modo simile. Il rpki expire_interval controlla per quanto tempo i VRP in cache rimangono utilizzabili dopo la caduta della connessione RTR.
Ridurre il rischio
Esegui una seconda istanza di Routinator o usa un validatore diverso (StayRTR, Fort) su una macchina separata. Configura entrambi come sorgenti RTR.
BIRD2 supporta più blocchi protocol rpki:
protocol rpki rpki_backup {
roa4 { table roa_v4; };
roa6 { table roa_v6; };
remote 10.0.0.2 port 3323;
retry keep 90;
refresh keep 600;
expire keep 7200;
}
FRR supporta più server cache con preferenze diverse:
rpki
rpki cache 127.0.0.1 3323 preference 1
rpki cache 10.0.0.2 3323 preference 2
exit
I valori di preferenza più bassi vengono tentati per primi. FRR passa al secondario se il primario va in down.
Monitora lo stato di Routinator. Controlla systemctl status routinator e l'endpoint di stato dell'API HTTP con il tuo sistema di monitoraggio. Imposta alert per cali nel conteggio VRP (un calo improvviso a zero indica un errore di sincronizzazione) e per perdite di connessione RTR visibili in journalctl -u routinator.
Risoluzione dei problemi
Il ROA mostra "Not Found" dopo la creazione. La propagazione richiede da 10 a 20 minuti. Routinator si sincronizza ogni 10 minuti per impostazione predefinita (refresh = 600). Forza un riavvio della sincronizzazione: sudo systemctl restart routinator, poi attendi che la sincronizzazione iniziale si completi.
birdc mostra 0 voci nella tabella ROA. Controlla birdc show protocols all rpki_routinator. Se lo stato non è "Established", verifica che Routinator sia in esecuzione e in ascolto sulla porta 3323: ss -tlnp | grep 3323.
FRR "Unknown command" per rpki. Il flag -M rpki manca in /etc/frr/daemons oppure frr-rpki-rtrlib non è installato. Installa il pacchetto, aggiungi il flag, riavvia FRR.
Le rotte non vengono rivalutate dopo un cambio di ROA. In BIRD2, aggiungi import table; al canale BGP. In FRR, abilita soft-reconfiguration inbound sul vicino.
Tutte le rotte mostrano Invalid. Il tuo ROA potrebbe avere l'ASN o il prefisso sbagliato. Ricontrolla nel portale RIPE. Verifica anche che l'ASN del tuo router corrisponda a quello inserito nel ROA.
Prossimi passi: combina la validazione RPKI con prefix-list e filtri AS-path per una difesa in profondità . Monitora gli alert RPKI invalid per i tuoi prefissi con BGPalerter .
Copyright 2026 Virtua.Cloud. Tutti i diritti riservati. Questo contenuto è un'opera originale del team Virtua.Cloud. La riproduzione, ripubblicazione o redistribuzione senza autorizzazione scritta è vietata.
Pronto a provare?
Distribuisci il tuo server in pochi secondi. Linux, Windows o FreeBSD.
Vedi piani VPS