BGP fait confiance. C'est sa faiblesse de naissance. Quand un routeur reçoit une annonce qui dit « le préfixe 203.0.113.0/24 est originé par l'AS 64500 », il n'a aucun moyen natif de vérifier que l'AS 64500 a le droit d'annoncer ce préfixe. Le protocole croit ce qu'on lui raconte. Résultat : une mis-origination, volontaire ou accidentelle, et le trafic d'un préfixe part chez le mauvais opérateur. Des fuites de ce type, il y en a tous les mois sur la table globale.
RPKI répond à un seul de ces problèmes, mais le plus fréquent : prouver qui a le droit d'originer un préfixe. Pas le chemin complet (ça, c'est le boulot d'ASPA et de BGPsec, autre sujet), juste l'origine. Concrètement, deux chantiers distincts côté ops : valider les annonces que vous recevez, et signer les vôtres pour que les autres puissent les valider. Routinator fait le premier, Krill le second. Les deux viennent de NLnet Labs, écrits en Rust, et tournent en prod sans drame.
Ce que RPKI signe vraiment
Le modèle, posé par la RFC 6480, calque la hiérarchie d'allocation des ressources Internet. L'IANA délègue aux RIR (RIPE, ARIN, APNIC), qui délèguent aux LIR. Chaque niveau émet un certificat ressource qui atteste la détention d'un bloc d'adresses ou d'un ASN. Au bout de la chaîne, l'objet qui nous intéresse : le ROA, Route Origin Authorization.
Un ROA, défini par la RFC 6482, c'est un objet signé qui dit trois choses : un préfixe, l'ASN autorisé à l'originer, et un maxLength. Le maxLength borne la longueur du préfixe couvert. Exemple : ROA pour 203.0.113.0/24, ASN 64500, maxLength 24. Ça autorise l'AS 64500 à originer ce /24, et rien de plus spécifique. Si vous mettez maxLength 26, vous autorisez aussi tous les /25 et /26 contenus dedans. On verra plus loin pourquoi ce détail est un piège.
La validation d'une annonce contre l'ensemble des ROA donne trois états, formalisés par la RFC 6483 :
- Valid : l'annonce correspond à un ROA (préfixe couvert, bon ASN d'origine, longueur dans le maxLength).
- Invalid : un ROA couvre ce préfixe mais l'origine ne colle pas, ou le préfixe est plus spécifique que le maxLength autorisé. C'est le cas du détournement ou de l'erreur de config.
- NotFound : aucun ROA ne couvre ce préfixe. La majorité de la table globale est encore là.
Valider, ce n'est rien si on ne fait rien des Invalid. ROV (Route Origin Validation), c'est la décision politique : rejeter les annonces Invalid. Pas les déprioriser, les jeter. Un préfixe Invalid ne doit pas entrer dans la RIB.
Routinator : le validateur côté entrée
Routinator est un relying party. Son job : aller chercher tous les certificats et ROA dans les dépôts des RIR via RRDP et rsync, vérifier les signatures et la chaîne de confiance, et produire la liste des VRP (Validated ROA Payloads). Un VRP, c'est un triplet préfixe + ASN + maxLength qui a passé la validation cryptographique.
Cette liste de VRP, le routeur en a besoin pour trancher Valid/Invalid/NotFound sur chaque annonce. Le transport, c'est RTR, RPKI-to-Router, normalisé par la RFC 8210. Le routeur ouvre une session RTR vers Routinator, récupère le jeu complet de VRP, puis reçoit les deltas au fil de l'eau. Pas de re-téléchargement complet à chaque changement, juste les serial query incrémentaux. La RFC prévoit que le cache accepte l'authentification SSH (transport rpki-rtr) pour éviter qu'un attaquant injecte de faux VRP entre le validateur et le routeur. Sur un lien interne maîtrisé, beaucoup tournent en clair ; dès que le validateur n'est pas sur le même segment de confiance que le routeur, on chiffre.
L'install est directe. Le démon expose deux services qu'il faut activer explicitement : RTR pour les routeurs, HTTP pour l'interface, l'API et les métriques Prometheus.
# Debian/Ubuntu, depuis le dépôt NLnet Labs
sudo apt install routinator
# Lancer le démon avec RTR et HTTP
routinator server --rtr 192.0.2.10:3323 --http 192.0.2.10:8323
Depuis Routinator 0.12, le TAL ARIN est embarqué dans le paquet et l'acceptation manuelle de la Relying Party Agreement (l'ancienne étape routinator init --accept-arin-rpa) n'est plus nécessaire. On installe, on lance le serveur, il récupère les cinq trust anchors RIR au démarrage.
Côté routeur, la session RTR pointe vers le validateur. Avec FRRouting, ça donne ça :
rpki
rpki cache 192.0.2.10 3323 preference 1
exit
!
router bgp 64500
address-family ipv4 unicast
neighbor 198.51.100.1 route-map RPKI-IN in
exit-address-family
!
route-map RPKI-IN deny 10
match rpki invalid
route-map RPKI-IN permit 20
La route-map rejette tout ce qui est Invalid et laisse passer Valid et NotFound. C'est ROV en trois lignes. Pour la mécanique BGP complète, la configuration des voisins et le filtrage par prefix-list, l'article sur le déploiement d'un routeur BGP avec FRRouting couvre les bases que ce filtre vient compléter. Sur VyOS, la logique est identique mais la syntaxe diffère, voir le routeur de datacenter sous VyOS.
Un principe non négociable : un seul validateur, c'est un point de défaillance. On en déploie deux minimum, avec deux sessions RTR de préférences différentes sur chaque routeur. Si le primaire tombe, le routeur bascule sur le secondaire sans perdre ses VRP. Et on supervise le nombre de VRP : une chute brutale (passage de 400 000 à 50 000 VRP) signale un dépôt RIR injoignable ou un trust anchor cassé, pas une bonne nouvelle.
Krill : publier ses propres ROA
Valider, c'est la moitié du travail. L'autre moitié, c'est signer vos préfixes pour que les autres rejettent les annonces frauduleuses qui les concernent. Deux options.
La première, la plus simple : le RPKI hébergé du RIR. Le dashboard RIPE NCC, l'interface ARIN ou APNIC vous laissent créer vos ROA en quelques clics. Le RIR détient la clé, héberge le dépôt, gère la publication. Pour la plupart des réseaux, c'est suffisant et c'est ce qu'on recommande par défaut. Moins de pièces mobiles, moins de choses à casser.
La seconde, delegated RPKI : vous opérez votre propre CA. C'est le rôle de Krill. Vous tenez votre clé, vous publiez vos ROA, et le RIR ne fait que pointer vers votre dépôt via un certificat délégué. Pourquoi se compliquer la vie ? Trois cas le justifient vraiment : vous avez des ressources réparties sur plusieurs RIR et vous voulez une CA unique ; vous voulez déléguer la gestion des ROA à vos propres clients ou business units, façon RIR ; ou vous tenez à ne pas dépendre de l'interface web d'un RIR pour une opération critique et automatisable.
Krill est un démon CA plus serveur de publication. Le CLI gère les ROA un par un ou par delta atomique, et il sait analyser vos annonces BGP réelles pour suggérer les ROA manquants. En prod, ça donne ça :
# Créer une CA enfant rattachée au parent RIR
krillc add --ca shpv-ca
# Ajouter un ROA : préfixe, origine, maxLength explicite
krillc roas update --ca shpv-ca \
--add "203.0.113.0/24 => 64500"
# Vérifier l'état des ROA et leur publication
krillc roas list --ca shpv-ca
Le rattachement au parent (le RIR) se fait par échange d'un fichier d'identité enfant et d'une réponse parent, puis Krill récupère son certificat ressource et publie. RIPE NCC, APNIC et ARIN offrent la publication comme service, donc on peut faire tourner sa CA Krill et déléguer juste le stockage du dépôt au RIR. Bon compromis : on garde la main sur les ROA, on n'a pas à exposer un serveur de publication à Internet.
Le piège du maxLength
Le maxLength est l'erreur de débutant la plus coûteuse. La tentation : signer 203.0.113.0/24 avec maxLength 24 paraît restrictif, alors on « anticipe » en mettant maxLength 32, pour ne pas avoir à retoucher le ROA si on désagrège un jour. Mauvais réflexe.
La RFC 9319 tranche : un maxLength trop permissif rouvre la porte qu'on essayait de fermer. Un attaquant qui forge l'origine légitime (il met votre ASN comme origine dans l'AS_PATH) peut annoncer un sous-préfixe plus spécifique. S'il existe un ROA pour votre /24 avec maxLength 32, l'annonce d'un /25 forgé par l'attaquant passe en Valid, parce qu'elle respecte le ROA. Et un /25 bat un /24 sur la longest-prefix-match. Le trafic part chez l'attaquant, en toute « validité » RPKI. Les mesures historiques de la RFC montraient que 84 % des préfixes utilisant un maxLength étaient vulnérables à ce forged-origin sub-prefix hijack.
La règle qu'on applique : des ROA minimaux. On signe exactement les préfixes qu'on annonce, avec maxLength égal à la longueur du préfixe. Pas de maxLength large « au cas où ». Si on désagrège un /24 en deux /25 plus tard, on ajoute deux ROA pour les /25. Krill rend ça trivial avec son delta atomique, donc l'argument du confort ne tient pas.
Où en est l'adoption
Ça avance, mais c'est loin d'être fini. Selon les mesures regroupées par MANRS et les RIR, plus de la moitié des préfixes de la table globale sont couverts par un ROA fin 2025. La bascule décisive vient des transitaires Tier-1 : d'après les mesures MANRS et Cloudflare, tous sauf un des grands transitaires Tier-1 rejettent les annonces RPKI-invalid. Concrètement, un préfixe Invalid devient injoignable depuis une grande partie d'Internet. Signer ses ROA n'est plus optionnel : un ROA mal foutu, et c'est vous qui vous coupez du réseau.
Pour vérifier votre propre statut, le test de Cloudflare sur isbgpsafeyet.com dit en une page si votre opérateur de transit fait du ROV et si vos préfixes sont valides. Test grandeur nature en trente secondes.
Côté ops, RPKI ne corrige pas tout. Il ne protège que l'origine, pas l'intégrité du chemin. Un détournement par insertion de chemin (path hijack) où l'attaquant forge votre ASN en origine passe au travers si votre maxLength est trop large, d'où le point précédent. Et la validation dépend de la disponibilité des dépôts RIR, donc de votre validateur et de sa redondance. C'est une couche, pas une cuirasse.
Par où commencer, concrètement
Faites ROV à l'entrée, point. Rejeter les Invalid coûte trois lignes de route-map et ferme la classe d'incidents la plus fréquente sur BGP. Pour le validateur, Routinator en double, supervisé sur le nombre de VRP, avec bascule RTR. Pour signer, commencez par le RPKI hébergé de votre RIR : c'est suffisant pour 90 % des réseaux et ça ne casse pas. Ne passez à Krill que si vous avez un vrai besoin de délégation ou de ressources multi-RIR. Et dans tous les cas, des ROA minimaux, maxLength égal à la longueur du préfixe, jamais de marge « au cas où ».
Refuser un Invalid pour ne pas propager la fuite d'un autre, c'est la ligne qu'on tient sur l'AS41652 : ROA signés sur nos préfixes et ROV à l'entrée. Si vous montez du transit IP et que vous voulez une session BGP avec validation RPKI sérieuse en face, on opère du transit avec ROV à l'entrée.
Une fois le routage signé, la même logique de chaîne de confiance s'applique à la résolution de noms. La configuration DNSSEC signe vos zones comme RPKI signe vos routes. Et quand une session BGP se comporte mal malgré tout, les méthodes du debug réseau restent la première ligne.
Sources
- RFC 6480, An Infrastructure to Support Secure Internet Routing : architecture RPKI et hiérarchie des certificats ressource.
- RFC 6482, A Profile for Route Origin Authorizations (ROAs) : structure d'un ROA (préfixe, ASN, maxLength).
- RFC 6483, Validation of Route Origination Using RPKI and ROAs : définition des états Valid, Invalid, NotFound.
- RFC 8210, The RPKI to Router Protocol, Version 1 : protocole RTR, PDU, transport et authentification.
- RFC 9319, The Use of maxLength in the RPKI : pourquoi éviter maxLength et le risque de forged-origin sub-prefix hijack.
- Documentation Routinator, NLnet Labs : relying party, serveurs RTR et HTTP, configuration.
- Documentation Krill, NLnet Labs : CA delegated RPKI, publication, gestion des ROA.
- RPKI ROV Deployment Reaches Major Milestone, MANRS : état de l'adoption ROV et rejet des Invalid par les Tier-1.
- RPKI best practices and lessons learned, APNIC Blog : pièges de déploiement et bonnes pratiques opérationnelles.


