RPKI ROA pour BGP : créer des ROAs, valider les routes dans BIRD2 et FRR
Créez des ROAs IPv4 et IPv6 dans le portail RIPE NCC, installez Routinator comme cache RTR, configurez la validation RPKI dans BIRD2 et FRRouting, et vérifiez le statut de vos préfixes avec bgp.tools et RIPE Stat.
Sans RPKI, n'importe quel ASN peut annoncer n'importe quel préfixe. Un Route Origin Authorization (ROA) lie votre préfixe à votre ASN de manière cryptographique, et la validation d'origine des routes (ROV) permet à votre routeur de rejeter les annonces invalides. Ce tutoriel couvre l'ensemble de la chaîne : créer des ROAs dans le portail RIPE NCC, exécuter Routinator comme cache RPKI local, configurer la validation dans BIRD2 et FRRouting, et vérifier que tout fonctionne.
Prérequis : un ASN enregistré, des préfixes IP alloués (PA ou PI), une session BGP fonctionnelle sur un VPS Linux (BGP avec votre propre IP sur un VPS), et BIRD2 (Configuration BGP BIRD2) ou FRR (Configuration BGP FRR) déjà en fonctionnement.
Qu'est-ce que RPKI et pourquoi votre préfixe BGP a-t-il besoin d'un ROA ?
Resource Public Key Infrastructure (RPKI) est un cadre cryptographique défini dans la RFC 6480 qui associe les ressources Internet (préfixes IP, ASN) à leurs détenteurs légitimes via des certificats X.509 émis par les Registres Internet Régionaux. Un Route Origin Authorization (ROA) est un objet signé qui déclare : « l'ASN X est autorisé à annoncer le préfixe Y avec une longueur maximale de Z ». Les validateurs récupèrent ces ROAs et transmettent le résultat aux routeurs via le protocole RPKI-to-Router (RTR) (RFC 8210).
Quand un routeur reçoit une mise à jour BGP, il vérifie l'ASN d'origine et le préfixe dans sa table ROA locale. Chaque préfixe obtient l'un des trois états de validation :
| État | Signification | Action recommandée |
|---|---|---|
| Valid | Un ROA existe et correspond à l'ASN d'origine et à la longueur du préfixe | Accepter |
| Invalid | Un ROA existe mais l'ASN d'origine ou la longueur du préfixe ne correspond pas | Rejeter |
| Not Found | Aucun ROA ne couvre ce préfixe | Accepter (éventuellement avec un local-pref plus bas) |
Sans ROA, vos préfixes apparaissent comme « Not Found ». C'est mieux que « Invalid », mais les réseaux qui font de la ROV préféreront les routes « Valid » de vos pairs à vos annonces « Not Found » quand les deux sont disponibles. Créer des ROAs est la première étape. Valider les routes entrantes protège votre réseau contre l'acceptation de préfixes détournés.
Comment créer des ROAs IPv4 et IPv6 dans le portail RIPE NCC ?
Connectez-vous au portail RIPE NCC, naviguez vers Resources, puis RPKI Dashboard. Si vous n'avez pas encore initialisé RPKI, sélectionnez « Hosted » certificate authority. RIPE NCC gère le CA et la signature pour vous. Une fois le Hosted CA actif, passez à l'onglet BGP Announcements. RIPE pré-remplit les suggestions de ROA en fonction de vos annonces BGP actuelles.
- Cliquez sur Create ROA (ou + New ROA dans l'onglet ROA).
- Définissez Origin ASN avec votre numéro AS (par exemple,
AS213279). - Définissez Prefix avec votre allocation IPv4 (par exemple,
192.0.2.0/24). - Définissez Maximum Length égal à la longueur du préfixe (
/24). Ne l'augmentez pas. Voir la section maxLength ci-dessous. - Cliquez sur Publish.
- Répétez pour votre préfixe IPv6 (par exemple,
2001:db8::/48avec longueur maximale/48).
Vérifiez dans le RPKI Dashboard que le statut du ROA affiche « Published ». La propagation vers les validateurs prend généralement 10 à 20 minutes, selon leur intervalle de rafraîchissement.
Rappel dual-stack : créez un ROA par préfixe. Si vous annoncez 192.0.2.0/24 et 2001:db8::/48, vous avez besoin de deux ROAs. Si vous annoncez des more-specifics supplémentaires (un /25 découpé dans le /24), chacun a besoin de son propre ROA avec sa propre liaison ASN.
Comment installer Routinator comme cache RPKI-RTR sur Linux ?
Routinator est un Relying Party RPKI (validateur) développé par NLnet Labs. Il récupère et valide les ROAs depuis les cinq trust anchors des RIR, puis sert les Validated ROA Payloads (VRPs) à votre routeur via le protocole RTR. Version stable actuelle : 0.15.1.
Installation depuis le dépôt NLnet Labs
Sur Debian 12 ou Ubuntu 24.04 :
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
Ajoutez la clé de signature et le dépôt NLnet Labs :
curl -fsSL https://packages.nlnetlabs.nl/aptkey.asc | sudo gpg --dearmor -o /usr/share/keyrings/nlnetlabs-archive-keyring.gpg
Pour 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
Pour 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
Installez Routinator :
sudo apt update
sudo apt install -y routinator
Le paquet installe un service systemd qui démarre automatiquement. Routinator s'exécute sous l'utilisateur routinator.
Vérifiez le service
sudo systemctl status routinator
Vous devriez voir active (running). La première synchronisation prend 2 à 5 minutes pendant que Routinator récupère tous les certificats des trust anchors et valide l'ensemble des ROAs mondiaux.
Vérifiez que la synchronisation initiale est terminée en interrogeant l'API HTTP (la version empaquetée envoie les logs à syslog avec peu de détails, l'API HTTP est la source fiable) :
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\"]}')"
Si la synchronisation est en cours, les compteurs seront à zéro. Attendez 2 à 5 minutes et réessayez. Quand vous voyez des compteurs non nuls (des centaines de milliers pour IPv4, des dizaines de milliers pour IPv6), la synchronisation initiale est terminée.
Configuration
La configuration du paquet se trouve dans /etc/routinator/routinator.conf. Les paramètres par défaut sont sécurisés : RTR écoute sur 127.0.0.1:3323 et HTTP sur 127.0.0.1:8323. Les deux ne sont liés qu'à localhost.
Paramètres importants :
| Option | Défaut | Objectif |
|---|---|---|
rtr-listen |
["127.0.0.1:3323"] |
Serveur RTR pour les routeurs |
http-listen |
["127.0.0.1:8323"] |
Interface HTTP et API |
refresh |
600 | Secondes entre les synchronisations RPKI |
retry |
600 | Secondes avant de réessayer après un échec de synchronisation |
expire |
7200 | Secondes avant que les VRPs en cache soient considérés comme périmés |
Si BIRD2 ou FRR tourne sur la même machine (configuration typique pour un VPS BGP), conservez le binding par défaut sur 127.0.0.1. Aucune modification de pare-feu nécessaire.
Si vous exécutez Routinator sur un serveur séparé, liez-le à une IP privée et restreignez l'accès :
sudo ufw allow from 10.0.0.0/24 to any port 3323 proto tcp comment "RTR from routers"
Vérifiez l'interface HTTP :
curl -s http://127.0.0.1:8323/api/v1/status | head -20
Cette commande renvoie du JSON avec le nombre de VRPs actuel, la date de dernière synchronisation et le statut du validateur.
Comment configurer la validation RPKI dans BIRD2 ?
BIRD2 intègre nativement RPKI via le protocole rpki (disponible depuis BIRD 2.0 ; Ubuntu 24.04 fournit BIRD 2.14). Il se connecte à Routinator via RTR, remplit les tables ROA et fournit la fonction roa_check() pour les filtres d'import. Aucune bibliothèque externe requise.
Ajoutez ce qui suit à votre configuration BIRD2 (typiquement /etc/bird/bird.conf) :
Définir les tables ROA
roa4 table roa_v4;
roa6 table roa_v6;
Configurer le protocole 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;
}
Le mot-clé keep indique à BIRD de préférer les valeurs de timers fournies par le serveur, avec un repli sur les valeurs spécifiées. retry 90 signifie que BIRD se reconnecte 90 secondes après la perte de la session RTR.
Ajouter la validation ROA à votre filtre d'import
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 est plus sûr que bgp_path.last car il ignore les entrées AS_SET issues de l'agrégation. Les routes invalides sont rejetées. Les routes valides obtiennent un local-pref plus élevé. Les routes Not Found passent avec le local-pref par défaut.
Appliquer le filtre à votre pair 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 directive import table est importante. Elle permet à BIRD de réévaluer les routes filtrées quand la table ROA change, sans nécessiter une réinitialisation complète de la session.
Recharger et vérifier
sudo birdc configure
Vérifiez la session RPKI :
sudo birdc show protocols all rpki_routinator
Cherchez Established dans la sortie. Puis vérifiez le contenu de la table ROA :
sudo birdc show route table roa_v4 count
Vous devriez voir des centaines de milliers d'entrées (la table ROA mondiale compte plus de 800 000 VRPs début 2026).
Vérifiez la validation d'un préfixe spécifique :
sudo birdc show route 192.0.2.0/24 all
La sortie inclut un champ ROA affichant valid, invalid ou unknown (not found).
Comment configurer la validation RPKI dans FRRouting ?
FRRouting gère RPKI via le module rpki, qui utilise librtr en interne (Ubuntu 24.04 fournit FRR 8.4.4 ; FRR 9.x+ et 10.x sont aussi supportés). Le module se connecte au serveur RTR de Routinator et s'intègre aux route-maps BGP.
Installer le module RPKI
Sur Debian/Ubuntu avec FRR déjà installé :
sudo apt install -y frr-rpki-rtrlib
Activer le module
Éditez /etc/frr/daemons et ajoutez -M rpki aux options bgpd :
bgpd_options=" -A 127.0.0.1 -M rpki"
Redémarrez FRR :
sudo systemctl restart frr
Vérifiez que bgpd a chargé le module :
sudo vtysh -c "show rpki cache-server"
Si la commande s'exécute sans erreur (la sortie peut être vide avant la configuration d'un cache), le module est chargé. Si vous obtenez % Unknown command, le flag -M rpki est manquant ou frr-rpki-rtrlib n'est pas installé.
Configurer le cache RTR
Entrez dans vtysh et configurez :
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
Note : FRR 9.x+ utilise la syntaxe rpki cache tcp 127.0.0.1 3323 preference 1 (avec le mot-clé tcp explicite). FRR 8.x utilise rpki cache 127.0.0.1 3323 preference 1 sans ce mot-clé. Vérifiez votre version avec vtysh -c "show version".
Créer les route-maps pour les états 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
Ceci accepte les routes valides avec un local-pref élevé, rejette les routes invalides, et accepte les routes not-found au local-pref par défaut.
Appliquer la route-map à votre voisin 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 est requis. Sans cette option, FRR ne peut pas réévaluer les routes existantes quand le cache RPKI se met à jour. FRR stocke les routes non modifiées reçues du pair et réapplique la route-map quand les VRPs changent.
Écrivez la configuration :
write memory
end
Vérification
Vérifiez la connexion RTR :
sudo vtysh -c "show rpki cache-connection"
Cherchez (connected) dans la sortie. Puis vérifiez la table de préfixes :
sudo vtysh -c "show rpki prefix-table" | head -20
Filtrez les routes BGP par état de validation :
sudo vtysh -c "show bgp ipv4 unicast rpki valid" | head -20
sudo vtysh -c "show bgp ipv4 unicast rpki invalid"
La sortie invalid devrait montrer les routes que vous rejetez activement.
BIRD2 vs FRR : configuration RPKI en un coup d'œil
| Fonctionnalité | BIRD2 | FRR |
|---|---|---|
| Installation du module | Intégré (pas de paquet supplémentaire) | Paquet frr-rpki-rtrlib + flag -M rpki |
| Configuration RTR | Bloc protocol rpki avec remote |
Commande rpki cache dans vtysh |
| Tables ROA | Tables roa4/roa6 explicites |
Interne, non directement exposé |
| Mécanisme de filtrage | roa_check() dans le filtre d'import |
match rpki dans la route-map |
| Réévaluation automatique | Directive import table |
soft-reconfiguration inbound |
| Afficher le nombre de ROAs | birdc show route table roa_v4 count |
vtysh show rpki prefix-table |
| Afficher la validation | birdc show route ... all (champ ROA) |
vtysh show bgp rpki valid/invalid/notfound |
Comment vérifier le statut RPKI de votre préfixe ?
Après avoir créé les ROAs et configuré la validation, vérifiez depuis plusieurs points de vue.
Vérification locale
Sur le routeur lui-même, vérifiez que votre propre préfixe apparaît comme valide :
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"
Les deux devraient montrer votre ASN comme origine autorisée.
API HTTP de Routinator
curl -s "http://127.0.0.1:8323/api/v1/validity/AS213279/192.0.2.0/24"
Renvoie du JSON avec l'état de validation, les VRPs correspondants et le trust anchor source.
bgp.tools
Ouvrez https://bgp.tools/prefix/192.0.2.0/24 dans un navigateur. La colonne RPKI affiche un bouclier vert pour Valid, rouge pour Invalid, ou gris pour Not Found. Comptez 15 à 30 minutes après la création du ROA pour que les outils externes prennent en compte le changement.
RIPE Stat
Interrogez l'API de validation RPKI :
curl -s "https://stat.ripe.net/data/rpki-validation/data.json?resource=AS213279&prefix=192.0.2.0/24" | python3 -m json.tool
Cherchez "status": "valid" dans la réponse. RIPE Stat montre aussi quels ROAs couvrent le préfixe et si le maxLength correspond.
Répétez pour IPv6
Exécutez les mêmes vérifications avec votre préfixe IPv6. Chaque commande ci-dessus accepte les préfixes IPv6. Remplacez 192.0.2.0/24 par 2001:db8::/48 et vérifiez que les deux familles d'adresses sont couvertes.
Pourquoi éviter un maxLength supérieur à la longueur de votre préfixe ?
Définissez maxLength égal à la longueur de votre préfixe. C'est la recommandation de la RFC 9319 (qui met à jour et étend la RFC 7115).
Quand vous définissez maxLength à /24 sur un ROA /20, vous autorisez votre ASN à annoncer le /20 et chaque more-specific jusqu'à /24. Cela signifie que 16 /24 sont couverts. Un attaquant qui détourne l'un de ces /24 avec votre ASN en origine passera la validation RPKI comme « Valid ». Le more-specific détourné gagne par longest-match routing, et le ROA ne peut pas vous aider parce que vous avez autorisé cette longueur.
C'est ce qu'on appelle un forged-origin sub-prefix hijack. Des mesures de 2017 citées dans la RFC 9319 ont montré que 84 % des ROAs utilisant maxLength étaient vulnérables à cette attaque.
Exemple concret :
| ROA | Ce qu'il autorise |
|---|---|
192.0.2.0/20, maxLength /20 |
Uniquement 192.0.2.0/20 depuis votre ASN. Sûr. |
192.0.2.0/20, maxLength /24 |
/20, /21, /22, /23, /24 depuis votre ASN. N'importe quel /24 peut être détourné en usurpant votre ASN d'origine. |
Quand maxLength > longueur du préfixe est-il acceptable ? Uniquement quand vous désagrégez réellement en production (par exemple, annonce d'un /20 et de /24 spécifiques pour du traffic engineering) et que chaque préfixe désagrégé doit être validé. Dans ce cas, créez des ROAs individuels pour chaque préfixe annoncé plutôt qu'un seul ROA avec un maxLength large. Un ROA par annonce est le schéma le plus sûr.
Exception pour la mitigation DDoS : si vous utilisez un service comme un centre de nettoyage qui réannonce vos more-specifics depuis votre ASN, vous pourriez avoir besoin de maxLength pour couvrir ces préfixes. Documentez cette exception et auditez-la régulièrement.
Que se passe-t-il quand le cache RPKI tombe en panne ?
Quand Routinator s'arrête ou devient inaccessible, le comportement de votre routeur dépend du timer d'expiration.
BIRD2 conserve la dernière table ROA connue en mémoire pendant la durée de expire (par défaut 7200 secondes / 2 heures). Pendant cette fenêtre, la validation continue normalement avec des données périmées. Après expiration, BIRD supprime toutes les entrées ROA et chaque route repasse en « Not Found ». Aucune route n'est rejetée pour invalidité, mais aucune route n'obtient le bonus de local-pref valide non plus.
FRR se comporte de manière similaire. Le rpki expire_interval contrôle la durée pendant laquelle les VRPs en cache restent utilisables après la coupure de la connexion RTR.
Réduire le risque
Exécutez une seconde instance de Routinator ou utilisez un validateur différent (StayRTR, Fort) sur une machine séparée. Configurez les deux comme sources RTR.
BIRD2 supporte plusieurs blocs 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 supporte plusieurs serveurs cache avec des préférences différentes :
rpki
rpki cache 127.0.0.1 3323 preference 1
rpki cache 10.0.0.2 3323 preference 2
exit
Les valeurs de préférence plus basses sont essayées en premier. FRR bascule sur le secondaire si le primaire tombe.
Supervisez la santé de Routinator. Vérifiez systemctl status routinator et l'endpoint de statut de l'API HTTP avec votre système de monitoring. Alertez sur les chutes du nombre de VRPs (une chute soudaine à zéro signifie un échec de synchronisation) et sur les pertes de connexion RTR visibles dans journalctl -u routinator.
Dépannage
Le ROA affiche « Not Found » après la création. La propagation prend 10 à 20 minutes. Routinator se synchronise toutes les 10 minutes par défaut (refresh = 600). Forcez un redémarrage de la synchronisation : sudo systemctl restart routinator, puis attendez que la synchronisation initiale se termine.
birdc affiche 0 entrées dans la table ROA. Vérifiez birdc show protocols all rpki_routinator. Si l'état n'est pas « Established », vérifiez que Routinator tourne et écoute sur le port 3323 : ss -tlnp | grep 3323.
FRR « Unknown command » pour rpki. Le flag -M rpki est manquant dans /etc/frr/daemons ou frr-rpki-rtrlib n'est pas installé. Installez le paquet, ajoutez le flag, redémarrez FRR.
Les routes ne sont pas réévaluées après un changement de ROA. Dans BIRD2, ajoutez import table; au canal BGP. Dans FRR, activez soft-reconfiguration inbound sur le voisin.
Toutes les routes affichent Invalid. Votre ROA a peut-être le mauvais ASN ou préfixe. Revérifiez dans le portail RIPE. Vérifiez aussi que l'ASN de votre routeur correspond à celui que vous avez mis dans le ROA.
Prochaines étapes : combinez la validation RPKI avec des prefix-lists et des filtres AS-path pour une défense en profondeur . Surveillez les alertes RPKI invalid pour vos préfixes avec BGPalerter .
Copyright 2026 Virtua.Cloud. Tous droits réservés. Ce contenu est une création originale de l'équipe Virtua.Cloud. Toute reproduction, republication ou redistribution sans autorisation écrite est interdite.
Prêt à essayer ?
Déployez votre serveur en quelques secondes. Linux, Windows ou FreeBSD.
Voir les offres VPS