What’s RPKI?
Although sounding complicated, Resource Public Key Infrastructure is just a way to secure the internet against IPv4/v6 prefix hijacks and leaks. To achieve that, RPKI will serve your router the trusted information so it can check if eBGP learned prefixes are originating from where they are allowed to (first AS in path) and in the format they are allowed to (subnetmask or subnetmask range). It’s first described in RFC6480.
An ROA (Route Origin Authorization) is kind of a signed IRR and basically has following structure:
ASN | IPv4/v6 Prefix | Mask | (Optional) Max. Mask | signature
These are usually stored on specific servers managed by your responsible IRR org.
2-way implementation
There are 2 independent aspects when you implement RPKI:
- generate ROAs to protect your prefixes. This is usually made on your RIR platform who will act like a “Certification Authority” for it’s managed prefixes.
- implement RPKI Validation to protect your routing-table. Setup your own Validator server who will download and verify the ROAs from the RIRs. A RTR Server (RPKI-to-Router protocol) is needed to send the ROA lists to your routers.
You can run RPKI on your routers and take routing decisions based on it without having ROAs. You can also create ROAs for your prefixes without having RPKI implemented in your routing logic or network. Implement both is best.
While the title may refer to a very simple and quick process to implement RPKI, you might want to plan this carefully and study the impact on your routing. Best is to go trough the whole process with a /24 that isn’t used for prod.
Here you can see the Cloudflare RPKI diagram neatly describing the whole setup:

Source: https://blog.cloudflare.com/rpki/
Before we start
Well, yes, deploying it could be relatively quick & easy in a small AS but make sure you take time to fully understand the implications before taking any productive steps. Read through the tutorial and make your own opinion about how you will benefit from it and what risks it involves for your network.
Step 1: Generate your ROAs
Note: We start with generating ROAs because they are only pushed to update every 8 hours, which means others may see your prefix as Valid (or invalid) only by then. In the meantime it will stay Unkown/NotFound.
Our AS is administrated by RIPE so we’ll generate our ROAs on their infrastructure. This is mostly quick and painless as RIPE is already hosting your IRRs (ASN:IPADDR entries) and monitoring what prefixes/CIDR your AS announces. In the RIPE RPKI dash, you can click on the little magic stick and auto-generate ROAs equal to the actual announcements, also don’t forget to “review & publish” the changes or nothing will happen (ask me how I know that):

Note: Full procedure is best described here: https://www.ripe.net/manage-ips-and-asns/resource-management/certification/resource-certification-roa-management
You can check your ROAs from different tools. Here some:
- Hurricane: https://bgp.he.net/AS6939#_prefixes
- Cloudflare: https://rpki.cloudflare.com/?view=validator
Step 2: Deploy Validator3 & RTR-Server
To get the signed ROA Entries from the RIRs you need to install a specific Service. RIPE develops their own tool called Validator Server, which is the one we are using here. There are approx. half a dozen other tools and while I’m sure they’re just as good I am going to stick with what worked painlessly for me.
Install
We got ourselves the 3.1 version on Ubuntu 20.04 LTS. We tried to run the Docker files from toomscj7 in version 3.0 but it was not running smoothly and a bit slow. As the setup is a no-brainer you can just install the Deb packages:
https://github.com/RIPE-NCC/rpki-validator-3/wiki/RIPE-NCC-RPKI-Validator-3-Production
wget https://ftp.ripe.net/tools/rpki/validator3/prod/deb/rpki-validator-3-latest.deb wget https://ftp.ripe.net/tools/rpki/validator3/prod/deb/rpki-rtr-server-latest.deb dpkg -i rpki-validator-3-latest.deb dpkg -i rpki-rtr-server-latest.deb sudo systemctl enable rpki-validator-3 sudo systemctl start rpki-validator-3 sudo systemctl enable rpki-rtr-server sudo systemctl start rpki-rtr-server journalctl -f -u rpki-validator-3 journalctl -f -u rpki-rtr-server
Change the Listening IPaddr to 0.0.0.0 from localhost so your routers can access the RTR-service on port 8323:
vim /etc/rpki-rtr-server/application.properties
If you’re not running the service as “rpki” user you’ll have to change it to your current user in:
vim /etc/systemd/system/multi-user.target.wants/rpki-validator-3.service vim /etc/systemd/system/multi-user.target.wants/rpki-rtr-server.service systemctl daemon-reload
Add the ARIN database
The ARIN RPKI data is not shipped with the Validators default install. We can include that pretty simply.
Download the ARIN file preformatted for the RIPE Validator:
cd /var/lib/rpki-validator/preconfigured-tals/ wget https://www.arin.net/resources/manage/rpki/arin-ripevalidator.tal
The Validator should add the ARIN repo in the list and download files for it.
Check services
Last quickly check if both are listening to the correct ports/IPs:
apt install net-tools netstat -tulpen Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 101 20444 877/systemd-resolve tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 0 23156 1075/sshd: /usr/sbi tcp 0 0 127.0.0.1:39843 0.0.0.0:* LISTEN 0 24688 924/containerd tcp6 0 0 :::22 :::* LISTEN 0 23167 1075/sshd: /usr/sbi tcp6 0 0 :::8323 :::* LISTEN 0 4129723 579092/java tcp6 0 0 :::80 :::* LISTEN 0 4120270 578326/apache2 tcp6 0 0 127.0.0.1:8080 :::* LISTEN 0 4116673 577266/java tcp6 0 0 :::8081 :::* LISTEN 0 4129735 579092/java udp 0 0 127.0.0.53:53 0.0.0.0:* 101 20443 877/systemd-resolve
Security
Apache http_proxy
To secure the Validator3 webinterface running on port 8080, instead of changing listening interface from localhost to any, it’s probably smarter to just deploy an apache2 proxy.
apt install apache2
Create a new file (you might have to ‘a2dissite 000-default’):
vim /etc/apache2/sites-available/rproxy-rpki-validator.conf
<VirtualHost _default_:*> <Location "/"> AllowOverride AuthConfig AuthType Basic AuthBasicProvider file AuthUserFile "/etc/httpd/passwd/passwords" AuthName "Only known users are allowed to make updates" <LimitExcept GET> Require valid-user </LimitExcept> ProxyPass "http://localhost:8080/" ProxyPassReverse "http://localhost:8080/" </Location> </VirtualHost>
Add a htpasswd file to add authentification when a POST request gets sent to the webserver:
htpasswd -c /etc/httpd/passwd/passwords rpkiadmin
Restart apache and check http://serveripaddress/
systemctl restart apache2
Firewall
Also don’t forget adequate Firewall rules (you might want to restrict that further down):
ufw allow from 192.168.0.0/24 to any port 8323 ufw allow from 10.10.10.0/24 to any port 80 ufw enable ufw status
Validator3 GUI
Give the server a bit of time to start up, then get to http://IPADDRESS
Now that you are running your own Validator Server you can check the Trust Anchors status and manipulate (validate/invalidate/ignore) all the ROAs. You see that the ARIN anchor you added earlier manually is also in the list:

Last but not least you can browse all the existing ROAs and check their state thanks to an up to date routing table dump so you know what data your routers will get:

Step 3: configure routers
Configure RPKI
Let’s assume following IP addressing:
- rpki/rtr server IP: 10.10.10.1 – RTR port 8323
- RT1 IP: 192.168.0.255 – is an iBGP router
- RT2 IP: 192.168.0.254 – is connected to an eBGP Upstream and sends those routes to RT1 via iBGP
Huawei VRP
Configure the router to get ROAs from your RTR-server:
system-view rpki session 10.10.10.1 tcp port 8323
Configure the BGP process to import RPKI information into the BGP routing table:
bgp 65000 prefix origin-validation enable bestroute origin-as-validation allow-invalid
Commit, then check the session is established:
display rpki session 10.10.10.1 verbose RPKI server is 10.10.10.1, port 8323 RPKI current state: Established, Age: 04m08s VPN-instance name: _public_ Local host: 192.168.0.255, Local port: 49616 Remote host: 10.10.10.1, Remote port: 8323 Refresh time : 1800 Aging time : 3600 Session ID : 4686 Serial number : 7 Session Statistics: IPv4 record : 150836 IPv6 record : 24919
Finally check the database:
display rpki table
Total number of RPKI record entry : 150845
Network Maxlen OriginAS Session VPN
1.0.0.0/24 24 13335 10.10.10.1 _public_
1.1.1.0/24 24 13335 10.10.10.1 _public_
1.6.0.0/22 24 9583 10.10.10.1 _public_
1.6.100.0/22 24 9583 10.10.10.1 _public_
...
You can see the routes getting a RPKI status now:
disp bgp routing-table BGP Local router ID is 192.168.0.255 Status codes: * - valid, > - best, d - damped, x - best external, a - add path, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete RPKI validation codes: V - valid, I - invalid, N - not-found Total Number of Routes: 2470702 Network NextHop MED LocPrf PrefVal Path/Ogn *>i V 1.0.0.0/24 192.168.0.254 0 60 0 13335i * i V 192.168.0.254 0 60 0 13335i * i V 192.168.0.254 0 29 0 13335i * i V 192.168.0.254 0 29 0 13335i *>i V 1.0.4.0/22 192.168.0.254 0 60 0 15412 4826 38803 56203i ...
Cisco IOS
Configure the router to get ROAs from your RTR-server:
router bgp 65000 bgp rpki server tcp 10.10.10.1 port 8323 refresh 180
Configure the BGP process to import RPKI information into the BGP routing table:
address-family ipv4 unicast bgp bestpath prefix-validate allow-invalid
If you want to get the information without altering the usual route-selection process:
bgp bestpath prefix-validate disable
Finally check the database:
show ip bgp rpki table
Juniper JUNOS
Juniper supports RPKI. I couldn’t test the configuration by myself so I’ll refer to the Juniper RPKI config guide here, it’s pretty detailed and should answer all settings we also covered in this how-to: https://www.juniper.net/documentation/en_US/junos/topics/topic-map/bgp-origin-as-validation.html#jd0e658
Extreme SLX-OS
Unfortunatly, Extreme doesn’t support RPKI – for now. I would add the configuration part in this tutorial once this has changed (because it has to be in the pipeline). UPDATE: it has been confirmed under development and will be available in a SLX-OS 20.2.x version, which I reckon could be next month or in 2 years).
Configure route-maps
Best pratice is not the implemented default behavior of dropping all RPKI invalid marked routes but to accept all of them, even invalids but prioritize the Valid routes, then the Unknown and as a last resort, the Invalid routes.
Huawei VRP
Set the route-map to allow all routes but to implement that logic:
route-policy RPKI-IN permit node 10 if-match rpki origin-as-validation invalid apply local-preference 50 ! route-policy RPKI-IN permit node 20 if-match rpki origin-as-validation not-found apply local-preference 100 ! route-policy RPKI-IN permit node 30 if-match rpki origin-as-validation valid apply local-preference 200 ! route-policy RPKI-IN permit node 40 !
Apply the route-map to your incoming eBGP sessions:
peer 1.2.3.4 route-policy RPKI-IN import
Cisco IOS
Set the route-map to allow all routes but to implement that logic:
route-map RPKI-IN permit 10 match rpki invalid set local-preference 50 ! route-map RPKI-IN permit 20 match rpki not-found set local-preference 100 ! route-map RPKI-IN permit 30 match rpki valid set local-preference 200 ! route-map RPKI-IN permit 40 !
Apply the route-map to your incoming eBGP sessions:
neighbor 1.2.3.4 route-map RPKI-IN in
Sending the validation-state to iBGP peers
Depending on your network stucture you may want to share the validation-state along with the eBGP learned routes to your iBGP peers. This has been implemented through well known communities (extended) that are sent with the route.
Huawei VRP
bgp 65000
peer 192.168.0.254 as-number 65000
peer 192.168.0.254 description "iBGP peering to RouterX"
ipv4-family unicast
peer 192.168.0.254 advertise-ext-community
peer 192.168.0.254 advertise origin-as-validation
Cisco IOS
router bgp 65000 neighbor 192.168.0.254 remote-as 65000 neighbor 192.168.0.254 description "iBGP peering to RouterX" address-family ipv4 unicast neighbor 192.168.0.254 send-community extended neighbor 192.168.0.254 announce rpki state
Consolidating your RPKI infrastructure
Restrict Validator3 WebGUI access
While it’s obvious firewall rules are important to protect access to the Validator, the proxy + .htaccess login on the Validator’s webinterface is a first step. Ideally upgrade that access via HTTPS 443 instead of plain HTTP 80, even if the certificates are self-signed.
NGINX Proxy: https://github.com/RIPE-NCC/rpki-validator-3/wiki/Run-the-RPKI-Validator-UI-and-API-behind-an-nginx-proxy
Apache2 Proxy: https://github.com/RIPE-NCC/rpki-validator-3/wiki/Running-the-RPKI-Validator-UI-and-API-behind-an-apache-proxy
Self-signed Apache2 SSL config: https://www.linux.com/training-tutorials/creating-self-signed-ssl-certificates-apache-linux/
Run multiple instances of Validator3+RTR-Server
Connecting your routers to multiple geo-spreaded RTR-servers seems like a wise thing to do to enforce redondancy and avoid altered RPKI table which might lead to at least suboptimal iBGP routing, depending on how strict your routing policy is about invalid and NotFound/Unkown routes.
RTR-Protocol security
You might have already noted that this way of transfering roa’s doesn’t come with any kind of native secure data transmission mecanism. There is an MD5 encrypting mecanism but my guess is it’s been implemented to give some network engineer a year spare for ISO 27001. I’ll explore this subject in another post as I didn’t went through all the options available in 2020.
Links:
Thanks RIPE for the tools & well documented Validator: https://github.com/RIPE-NCC/rpki-validator-3
https://github.com/RIPE-NCC/rpki-validator-3/wiki/RIPE-NCC-RPKI-Validator-3-Production
Cisco RPKI Config document: https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/iproute_bgp/configuration/15-s/irg-15-s-book/irg-origin-as.html
Huawei Improve BGP security: https://support.huawei.com/enterprise/en/doc/EDOC1100028526?section=j062&topicName=improving-bgp-security#dc_vrp_bgp_cfg_3099
BGP-RPKI was delivered in SLXOS 20.3.1 (Raphael) image. Release date for Raphael was March 31, 2021…
Great! Thanks for the info Kasper!