what it’s all about?

as part of efforts to protect BGP routes from “hijacking”, which means unauthorized announcement to redirect traffic, IETF came up with idea of running resource certification for some of BGP attributes. RPKI, which stands for Resource Public Key Infrastructure is a specialized framework that enables doing just that - by cryptologically signing information about BGP prefix (and allowed mask length) and BGP route origin AS.

in ideal world, you should run your own RPKI server that you control, and then feed your routers with current state of validation tables. for most part this is easy and quick, but people often complain that they need additional VMs or even hardware appliances to do that. here’s the solution to that problem.

RPKI route server

I’m running community route server, that’s available to everyone, just like [some](BGP blackholing) of my [other](AS 112) [projects](BGP Feeder).

if you want to start RPKI journey, first of all you should make sure to sign your own prefixes. there is a couple of good tutorials out there on how to do this.

then, you should make your own mind how you want to treat prefixes if they are invalid. when router receives BGP prefixes from neighbor and then RPKI table, it can perform validation process by tryign to compare those two.

prefix in BGP will contain prefix itself (let’s say 1.1.0.0/16) as well as some BGP attributes, like AS_PATH (AS path that as used to announce it to this point). RPKI table will contain ROA records, that will specify prefix along with allowed mask variation (let’s say 1.1.0.0/16-24) and origin AS (let’s say 1024).

after validation, prefix will end up in one of three states:

  • VALID - prefix in BGP table matches RPKI definition;
  • INVALID - prefix in BGP table doesn’t match RPKI/ROA definition, which means somebody is playing dirty tricks, or simply made an error while signing the prefix (it still happens)
  • NOT FOUND - prefix in BGP table can’t be matched to any RPKI/ROA entry, and likely was not yet signed; that’s unfortunately still the case, with about 65% of prefixes not yet signed by owners

if you’re running stub network (non-transit), connected to one upstream provider, even if you decide not to forward traffic towards INVALID prefixes, you’ll likely still send it as it matches default route (you can also choose to drop such traffic, but effectivness of such action will be likely limited).

if you have two upstreams, here where play begins. it may be, that INVALID prefix is received only via one neighbor, while the other is advertising proper prefix. then, decision is simple - you should ignore and never forward based on INVALID data.

config, show me the configuration

before you start, make a decision - do you want to drop traffic based on validation status, or just lower it’s preference vs others. it’s important, as with some topologies/traffic scenarios, dropping “INVALID” prefixes may lead to routing loops!

  • sessions are established over TCP with RTR protocol (not SSH!)
  • session IP addresses of RPKI route servers - remember RPKI records are sent for both IPv4 and IPv6 over any possible transport, so you don’t need to establish separate IPv4 and IPv6 sessions like you would typically do for normal BGP sessions:
    • IPv4 - 85.232.240.141 or/and 195.136.71.52
    • IPv6 - 2001:1a68:2c:2::141 or/and 2a00:4120:8000:a::10
  • timers - 3600 for refresh

some example configurations for Your routers:

Cisco IOS-XE configuration

for Cisco IOS XE, in releases 17+, the BGP path validation is already active and should be dropping INVALID paths from being selected as bestpaths; if therefore you want to configure the community BGP RPKI route server, just configure that:

router bgp X
 bgp rpki server tcp 85.232.240.141 port 3323 refresh 3600
 bgp rpki server tcp 195.136.71.52 port 3323 refresh 3600
 bgp rpki server tcp 2A00:4120:8000:A::10 port 3323 refresh 3600
 bgp rpki server tcp 2001:1A68:2C:2::141 port 3323 refresh 3600

once this is done, RPKI servers should feed you with data (amount of prefixes will equalize with time, once all sessions are synchronized):

ios-xe-rtr#sh bgp ipv4 unicast rpki servers | i SOVC|Prefixes
BGP SOVC neighbor is 195.136.71.52/3323 connected to port 3323
  Prefixes 316421
BGP SOVC neighbor is 2A00:4120:8000:A::10/3323 connected to port 3323
  Prefixes 316422
BGP SOVC neighbor is 2001:1A68:2C:2::141/3323 connected to port 3323
  Prefixes 316427
BGP SOVC neighbor is 85.232.240.141/3323 connected to port 3323
  Prefixes 316410

if for some reason you want to stop that and control prefixes based on policies, you could allow INVALID state prefixes into BGP:

router bgp X
 address family ipv4 unicast
  bgp bestpath prefix-validate allow-invalid
 address family ipv6 unicast
  bgp bestpath prefix-validate allow-invalid

You can then manipulate route attributes, and invalid routes can become bestpaths - but that would be less optimal in bigger scheme of things.

Cisco IOS XR configuration

for Cisco IOS XR, the same configuration would be:

router bgp X
 rpki server 195.136.71.52
  transport tcp port 3323
  refresh-time 3600
 !
 rpki server 85.232.240.141
  transport tcp port 3323
  refresh-time 3600
 !
 rpki server 2001:1a68:2c:2::141
  transport tcp port 3323
  refresh-time 3600
 !
 rpki server 2a00:4120:8000:a::10
  transport tcp port 3323
  refresh-time 3600
 !
 address-family ipv4 unicast
  bgp origin-as validation enable
  bgp bestpath origin-as use validity
 !
 address-family ipv6 unicast
  bgp origin-as validation enable
  bgp bestpath origin-as use validity
 !

once you established connections properly, you should see something like that:

RP/0/RP0/CPU0:xr-router#sh bgp rpki server summary 

Hostname/Address        Transport       State           Time            ROAs (IPv4/IPv6)
195.136.71.52           TCP:3323        ESTAB           00:00:14        263152/53269
2001:1a68:2c:2::141     TCP:3323        ESTAB           00:00:14        263156/53271
2a00:4120:8000:a::10    TCP:3323        ESTAB           00:00:14        263152/53269
85.232.240.141          TCP:3323        ESTAB           00:04:14        263197/53285

and:

RP/0/RP0/CPU0:xr-router#sh bgp rpki summary        

RPKI cache-servers configured: 4
RPKI database
  Total IPv4 net/path: 238761/263197
   Table Version: 4100272
   Scanner Version: 4100272
  Total IPv6 net/path: 49812/53286
   Table Version: 804305
   Scanner Version: 804305

Juniper JunOS configuration

basic configuration (again, you need two of those, don’t need to configure separate IPv4 and IPv6 unless you’re really crazy about redundancy):

set routing-options validation group LUKE-RPKI-SERVERS session 85.232.240.141 port 3323
set routing-options validation group LUKE-RPKI-SERVERS session 195.136.71.52 port 3323
set routing-options validation group LUKE-RPKI-SERVERS session 2001:1a68:2c:2::141 port 3323
set routing-options validation group LUKE-RPKI-SERVERS session 2a00:4120:8000:a::10 port 3323

which should give you:

root@vmx1> show validation session             
Session                                  State   Flaps     Uptime #IPv4/IPv6 records
85.232.240.141                           Up          0   00:00:43 263156/53271
195.136.71.52                            Up          0   00:00:43 263156/53271
2001:1a68:2c:2::141                      Up          0   00:00:43 263156/53271
2a00:4120:8000:a::10                     Up          0   00:00:43 263156/53271

then you need to attach RPKI validation policy into your BGP peers, and put it somewhere in your BGP import policies to execute before you accept anything:

set policy-options community origin-validation-state-invalid members 0x4300:0.0.0.0:2
set policy-options community origin-validation-state-unknown members 0x4300:0.0.0.0:1
set policy-options community origin-validation-state-valid members 0x4300:0.0.0.0:0

set policy-options policy-statement RPKI-POLICY term valid from protocol bgp
set policy-options policy-statement RPKI-POLICY term valid from validation-database valid
set policy-options policy-statement RPKI-POLICY term valid then validation-state valid
set policy-options policy-statement RPKI-POLICY term valid then community add origin-validation-state-valid
set policy-options policy-statement RPKI-POLICY term valid then next policy
set policy-options policy-statement RPKI-POLICY term unknown from protocol bgp
set policy-options policy-statement RPKI-POLICY term unknown from validation-database unknown
set policy-options policy-statement RPKI-POLICY term unknown then validation-state unknown
set policy-options policy-statement RPKI-POLICY term unknown then community add origin-validation-state-unknown
set policy-options policy-statement RPKI-POLICY term unknown then next policy
set policy-options policy-statement RPKI-POLICY term invalid from protocol bgp
set policy-options policy-statement RPKI-POLICY term invalid from validation-database invalid
set policy-options policy-statement RPKI-POLICY term invalid then validation-state invalid
set policy-options policy-statement RPKI-POLICY term invalid then community add origin-validation-state-invalid
set policy-options policy-statement RPKI-POLICY term invalid then reject

and your example BGP import policy should be looking like this:

root@mx> show configuration protocols bgp 
group FULL-v4 {
[...]
    import [ RPKI-POLICY ACCEPT-ALL ];
    export DROP-ALL;

FAQ

can I pass the data from your route server?

Yes, iBGP peers can exchange prefix validation using extended communities. it’s up to you to configure your devices if you want to take advantage of that, as it will cause additional churn in BGP due to validation updates and may increase your CPU and memory load.

can you make the RPKI server using SSH transport instead of TCP RTR?

Not right now, but if enough people will ask for that, I can consider doing just that.

what’s next?

have a good time validating!