RPKI (Resource Public Key Infrastructure) is the internet's answer to BGP prefix hijacking. It allows prefix owners to create digitally signed Route Origin Authorizations (ROAs) that declare "AS X is authorized to originate prefix Y/Z." Routers performing Route Origin Validation (ROV) can then reject or deprioritize routes with invalid origins — routes where the AS claiming to originate a prefix doesn't match any ROA.
How RPKI Works
- Prefix owner creates ROA: Through their RIR (ARIN, RIPE, APNIC), the prefix holder signs a ROA: "AS 65001 is authorized to originate 10.1.0.0/16 with maximum prefix length /24"
- RPKI validator collects ROAs: A local RPKI validator (Routinator, Fort, OctoRPKI) downloads and validates all ROAs from the five RIR trust anchors
- Router queries validator: The router connects to the validator using the RTR (RPKI-To-Router) protocol and downloads the validated ROA cache
- Route Origin Validation: For each BGP prefix, the router checks the origin AS against the ROA cache and assigns a validation state
Validation States
| State | Meaning | Action |
|---|---|---|
| Valid | Origin AS and prefix match a ROA | Prefer this route |
| Invalid | A ROA exists for this prefix but the origin AS doesn't match, or the prefix length exceeds the ROA's maxLength | Reject or deprioritize |
| Not Found | No ROA exists for this prefix | Accept normally (most prefixes are still here) |
As of 2025, approximately 50% of IPv4 prefixes and 60% of IPv6 prefixes have ROAs. "Not Found" is still the majority state for many routes, so you can't simply reject everything without a ROA.
Configuration on IOS XE
Step 1: Configure the RTR Connection
R1-HQ(config)# router bgp 65001
R1-HQ(config-router)# bgp rpki server tcp 10.1.1.100 port 8282 refresh 300
This connects to an RPKI validator (like Routinator) running on 10.1.1.100 port 8282, refreshing the cache every 300 seconds. For redundancy, configure multiple validators:
R1-HQ(config-router)# bgp rpki server tcp 10.1.1.100 port 8282 refresh 300 preference 1
R1-HQ(config-router)# bgp rpki server tcp 10.1.1.101 port 8282 refresh 300 preference 2Step 2: Create Route-Map Policy
! Drop RPKI Invalid routes
route-map RPKI-POLICY deny 10
match rpki invalid
!
! Prefer RPKI Valid routes (boost local-pref)
route-map RPKI-POLICY permit 20
match rpki valid
set local-preference 200
!
! Accept Not Found at normal preference
route-map RPKI-POLICY permit 30
match rpki not-found
!
router bgp 65001
neighbor 172.16.0.2 route-map RPKI-POLICY in
neighbor 172.16.0.6 route-map RPKI-POLICY inThis is the standard three-tier approach: reject Invalid, prefer Valid, accept Not Found normally. Over time, as ROA coverage increases, you can consider rejecting Not Found for specific prefix ranges.
Setting Up a Validator
The router doesn't validate ROAs itself — it relies on an external validator. Popular options:
- Routinator (NLnet Labs): Rust-based, lightweight, widely deployed. Available as a package or Docker container.
- Fort Validator: C-based, NIC Mexico. Low resource usage.
- OctoRPKI (Cloudflare): Go-based, with JSON output for monitoring.
Deploy at least two validators for redundancy. They should be on your management network, accessible from all BGP routers.
Verification
R1-HQ# show bgp rpki servers
BGP RPKI Server:
10.1.1.100 port 8282
Transport: TCP
State: Established
Serial: 42
Refresh interval: 300
Prefixes (IPv4/IPv6): 452831/124567
R1-HQ# show bgp rpki table
RPKI/RTR entry count: 577398
IPv4: 452831
IPv6: 124567
R1-HQ# show ip bgp rpki validity 100.64.0.0/18
BGP routing table entry for 100.64.0.0/18
Origin AS: 65010
RPKI validation state: Valid
Covering ROA: 100.64.0.0/16, maxlen /24, origin AS 65010! Count routes by validation state
R1-HQ# show ip bgp rpki validity summary
Valid: 245,000
Invalid: 12,300
Not Found: 692,700Creating ROAs for Your Prefixes
Protecting your own prefixes requires creating ROAs through your RIR:
- ARIN: RPKI Dashboard in the ARIN Online portal
- RIPE: RPKI Dashboard in RIPE NCC LIR Portal
- APNIC: MyAPNIC portal
When creating a ROA:
- Set the origin AS to your BGP ASN
- Set maxLength to the most-specific prefix you actually advertise. If you hold 10.1.0.0/16 and only advertise the /16, set maxLength to /16. If you also advertise /24s for traffic engineering, set maxLength to /24.
- Setting maxLength too broadly (e.g., /32) weakens protection — it allows anyone who hijacks your AS to advertise arbitrarily specific routes.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| RPKI server state: Connect (not Established) | Validator unreachable or not running, firewall blocking RTR port | Verify validator is running. Test TCP connectivity: telnet 10.1.1.100 8282. Check ACLs. |
| All routes showing "Not Found" | RTR session up but cache empty, or validator hasn't completed initial sync | Check show bgp rpki table for prefix count. Validator initial sync can take 5-15 minutes. |
| Legitimate routes marked Invalid | ROA misconfigured (wrong origin AS or maxLength too short) | Check the ROA with show ip bgp rpki validity [prefix]. Fix the ROA at the RIR portal. |
Key Takeaways
- RPKI with Route Origin Validation is the strongest defense against BGP prefix hijacking — it cryptographically verifies origin AS authorization.
- Deploy at least two RPKI validators and connect all BGP routers via the RTR protocol.
- The standard policy is: reject Invalid, prefer Valid, accept Not Found. This is safe because most prefixes still lack ROAs.
- Create ROAs for all your prefixes through your RIR — this protects you even if your peers don't do ROV, because other networks that do will reject hijacked versions of your routes.
- Set maxLength carefully — too broad weakens protection, too narrow causes your legitimate more-specific advertisements to be marked Invalid.