RPKI ROA per BGP: creare ROA, validare le rotte in BIRD2 e FRR

13 min di lettura·Matthieu·rpkiroabgpbird2frrroutinatorripe-nccipv6|

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.

  1. Clicca su Create ROA (o + New ROA nella scheda ROA).
  2. Imposta Origin ASN con il tuo numero AS (ad esempio AS213279).
  3. Imposta Prefix con la tua allocazione IPv4 (ad esempio 192.0.2.0/24).
  4. Imposta Maximum Length uguale alla lunghezza del prefisso (/24). Non aumentarlo. Vedi la sezione maxLength più avanti.
  5. Clicca su Publish.
  6. Ripeti per il tuo prefisso IPv6 (ad esempio 2001:db8::/48 con 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