7 minutes
RPKI in the Lab
Introduction
I recently finished the last chapters of Optimal Routing Design (great read). One of the chapters covered routing protocol security with protocols such as BGP, EIGRP, and OSPF. This echoed something in my head regarding Resource Public Key Infrastructure (RPKI). I knew the book’s printing was around 2003 and figured RPKI wouldn’t be in the book. This led me to wonder if I could get RPKI running in the lab, and the following blog post details some of that journey.
I knew very little about RPKI when I started down this road (arguably still know very little). However, I knew it was essential to set up to protect networks from the fate of route hijacks (someone advertising your network space without permission by accident or on purpose).
By default, peering over BGP isn’t secure. The workflow is usually Autonomous systems (AS) peering together and start advertising networks. There’s a default trust put in place that each peer will advertise the correct routes. Over time, we’ve developed filtering or route policies to ensure we receive and advertise the proper routes. However, time has shown that these options alone aren’t enough to prevent route hijacking or leaks.
RPKI overview
RPKI provides a way to connect an AS number to IP addresses in its simplest form. The beauty is that this pairing is associated with something we trust. For example, this could be one of the regional internet registries (RIR).
The local internet registries (LIR) can create Route Origination Authorizations (ROA). The ROAs is the piece that states what AS can advertise a specific prefix. Once we have valid ROAs, we can determine if a route is valid, invalid, or unknown. You may wonder, “okay, but where do these ROAs get stored?” The ROAs are actually stored in multiple repositories. For example, the RIRs are the trusted source for RPKI information, including ROAs.
If I want to validate IP space given out by APNIC, then I’ll subscribe to their repository and trust that the information is accurate and up-to-date. There is so much more involved in RPKI, but I’d like to keep a blog short for once. I’ll include some helpful links at the end if you want to learn more.
Getting RPKI in the lab with Routinator
In this lab, we’ll leverage a local Validator of routes. This Validator can pull the latest ROA information from the defined repositories. The Validator we will use is NLnetLabs Routinator. The Validator will use RPKI to Router (RTR) protocol to signal if a route is valid, invalid, or unknown. This has the benefit of reducing control plane impact on our routers. All the validation and checks are done by the Validator.
Containerlab to simplify the deployment
NLnetLabs is very kind to include a container image of their Routinator software. Adding this to Containerlab is relatively easy. The example below is our lab file.
name: rpki
prefix: ""
mgmt:
network: statics
ipv4_subnet: 172.100.100.0/24
topology:
kinds:
ceos:
image: ceos:4.29.0.2F
linux:
image: nlnetlabs/routinator
nodes:
R1:
kind: ceos
mgmt_ipv4: 172.100.100.11
startup-config: startup/R1.conf
R2:
kind: ceos
mgmt_ipv4: 172.100.100.12
startup-config: startup/R2.conf
RPKI:
kind: linux
mgmt_ipv4: 172.100.100.13
ports:
- 80:8323
links:
- endpoints: ["R1:eth1", "R2:eth1"]
I kept the topology file as simple and small as possible. We will use two Arista EOS containers to form a BGP relationship and advertise routes. We will then implement RPKI to check the validity of those advertisements. The lab’s startup configurations and GitHub repository will be linked at the end of this post.
Simple BGP config and advertising routes
We will simulate Google and Cloudflare as our two peering AS in our lab. We will advertise a network from each AS and another random network used for testing.
Below is a simple BGP configuration from R1’s perspective.
router bgp 15169
router-id 192.168.100.1
neighbor 172.16.0.2 remote-as 13335
network 8.8.8.0/24
network 192.168.100.1/32
R1#show ip bgp | b Net
Network Next Hop Metric AIGP LocPref Weight Path
* > 1.1.1.0/24 172.16.0.2 0 - 100 0 13335 i
* > 8.8.8.0/24 - - - - 0 i
* > 192.168.100.1/32 - - - - 0 i
* > 192.168.100.2/32 172.16.0.2 0 - 100 0 13335 i
R1#
Next, we’ll add Routinator to our BGP configuration.
Connecting to Routinator
Setting up our environment with Routinator is relatively simple. Since all nodes in this topology share a management network, we’ll use that in our RPKI configuration. Below is the configuration from R1’s perspective.
router bgp 15169
router-id 192.168.100.1
neighbor 172.16.0.2 remote-as 13335
network 8.8.8.0/24
network 192.168.100.1/32
!
rpki cache routinator
host 172.100.100.13 port 3323
!
transport tcp
!
rpki origin-validation
ebgp local
Once this is implemented, we can check if our router is communicating with our Validator.
R1#show bgp rpki cache
routinator:
Host: 172.100.100.13 port 3323
VRF: default
Refresh interval: 326 seconds
Retry interval: 600 seconds
Expire interval: 7200 seconds
Preference: 5
Protocol version: 1
State: synced
Session ID: 23300
Serial number: 18
Last update sync: never
Last full sync: 0:00:10 ago
Last serial query: never
Last reset query: 0:00:41 ago
Entries: 390484
Connection: Active (0:00:41)
Transport information:
Protocol: TCP
ROA tables: default
R1#
If we check our routes now, we will see two new codes.
V
: Valid RPKI routesU
: Unknown RPKI routes
R1#show ip bgp | b Net
Network Next Hop Metric AIGP LocPref Weight Path
* > V 1.1.1.0/24 172.16.0.2 0 - 100 0 13335 i
* > 8.8.8.0/24 - - - - 0 i
* > 192.168.100.1/32 - - - - 0 i
* > U 192.168.100.2/32 172.16.0.2 0 - 100 0 13335 i
R1#
Putting policy and filtering in place
At this point, we can see that our router is correctly communicating with Routinator and labeling routes as valid or unknown. However, you may notice that the routes are still in our routing table, even if they are unknown or invalid. In this case, we are simulating the 192.168.100.0
routes as bad. We can correct this by implementing some simple filtering.
!
ip as-path access-list 1 permit ^$ any
!
route-map local-only permit 10
description Only export local routes
match as-path 1
!
route-map rpki-reject-non-valid deny 10
description Reject non valid routes
match origin-as validity invalid
!
route-map rpki-reject-non-valid deny 20
description Reject not found routes
match origin-as validity not-found
!
route-map rpki-reject-non-valid permit 100
!
router bgp 15169
router-id 192.168.100.1
neighbor 172.16.0.2 remote-as 13335
neighbor 172.16.0.2 route-map rpki-reject-non-valid in
neighbor 172.16.0.2 route-map local-only out
Below we can see the updates after filtering and compare that with all routes received from our neighbor.
R1#show ip bgp | b Net
Network Next Hop Metric AIGP LocPref Weight Path
* > V 1.1.1.0/24 172.16.0.2 0 - 100 0 13335 i
* > 8.8.8.0/24 - - - - 0 i
* > 192.168.100.1/32 - - - - 0 i
R1#
R1#show bgp neighbors 172.16.0.2 received-routes | b AS Path
AS Path Attributes: Or-ID - Originator ID, C-LST - Cluster List, LL Nexthop - Link Local Nexthop
Network Next Hop Metric AIGP LocPref Weight Path
* > V 1.1.1.0/24 172.16.0.2 - - - - 13335 i
U 192.168.100.2/32 172.16.0.2 - - - - 13335 i
R1#
If you’d like, you can also check out the Routinator GUI at http://<Containerlab host>
. Feel free to check out the number of RTR connections or the source for all the repositories.
Outro and links
That’s about it. I hope you learned a little about RPKI and got to play with it in the lab. Please check out the GitHub repository and modify it for other AS and network combos you may want to learn with. Happy new year, and I wish you all the best. Thank you for reading this far. It really means a lot!
- Featured image by lexica.art
- APNIC lab used as inspiration
- BGP Origin Validation with RPKI by Kenneth Finnegan
- Routinator GitHub
- RPKI - The required cryptographic upgrade to BGP routing by Martin J Levy
- RFC 6480 - An Infrastructure to Support Secure Internet Routing
- RPKI on Wikipedia
- GitHub repository