RPKI in Practice: Securing Your BGP Routes Against Hijacking
BGP was designed in 1989 with an implicit assumption: every network operator is trustworthy. That assumption hasn't aged well. Route hijacking — where someone announces your prefixes as their own — remains one of the Internet's most persistent security problems.
RPKI (Resource Public Key Infrastructure) fixes this by cryptographically binding IP prefixes to the ASNs authorized to originate them. If you operate your own AS, deploying RPKI is no longer optional — it's table stakes.
How RPKI Works
The chain of trust starts at the five Regional Internet Registries (RIRs): ARIN, RIPE NCC, APNIC, AFRINIC, and LACNIC. Each RIR operates a Certificate Authority (CA) that issues certificates to resource holders.
RIR (Trust Anchor)
└── LIR / Resource Holder (Certificate)
└── ROA (Route Origin Authorization)
└── "AS215000 is authorized to announce 2001:db8:abcd::/48"
When you create a ROA, you're signing a statement: "This ASN is allowed to announce this prefix with this maximum prefix length." Validators fetch these ROAs, verify the signatures, and provide the validation results to your BGP router.
Your router then classifies every received BGP route as:
| State | Meaning | Action |
|---|---|---|
| Valid | A ROA exists and matches | Accept |
| Invalid | A ROA exists but doesn't match (wrong ASN or too specific) | Reject |
| NotFound | No ROA exists for this prefix | Accept (but flag) |
The critical part: Invalid routes get dropped. This is what prevents hijacking.
Step 1: Create Your ROAs
RIPE NCC
If your resources are in the RIPE region, log into the RIPE NCC portal and navigate to RPKI → ROAs.
Create a ROA for each prefix you announce:
Prefix: 2001:db8:abcd::/48
Origin AS: AS215000
Max Length: 48
Max Length matters: Setting max length to /48 means only a /48 announcement is valid. If you sometimes announce more specifics (like /64s for traffic engineering), set max length accordingly. But be conservative — a wider max length increases your attack surface.
For IPv4:
Prefix: 203.0.113.0/24
Origin AS: AS215000
Max Length: 24
ARIN
ARIN uses their RPKI Dashboard. The process is similar but requires you to first create a Resource Certificate, then create ROAs under it.
Hosted vs Delegated
- Hosted RPKI (recommended for most): The RIR hosts your certificates and ROAs. You manage them through a web portal. Simpler, no infrastructure to maintain.
- Delegated RPKI: You run your own CA. More control, but you're responsible for uptime and key management. Only worth it if you're a large LIR.
Step 2: Run an RPKI Validator
Your BGP router needs a local source of validated ROA data. This is provided by an RPKI validator — software that fetches ROAs from all five RIRs, validates the cryptographic chain, and serves the results via the RTR (RPKI-to-Router) protocol.
Routinator (Recommended)
Routinator by NLnet Labs is the most widely deployed validator.
# Install on Debian/Ubuntu
sudo apt install routinator
# Or via cargo
cargo install routinator
# Initialize (downloads Trust Anchor Locators)
routinator init --accept-arin-rpa
# Run with RTR server on port 3323 and HTTP API on 8323
routinator server --rtr 0.0.0.0:3323 --http 0.0.0.0:8323
Set up as a systemd service:
# /etc/systemd/system/routinator.service
[Unit]
Description=Routinator RPKI Validator
After=network.target
[Service]
Type=simple
User=routinator
ExecStart=/usr/bin/routinator server --rtr 0.0.0.0:3323 --http 0.0.0.0:8323
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo useradd -r -s /usr/sbin/nologin routinator
sudo systemctl enable --now routinator
Verify It's Working
# Check HTTP status
curl http://localhost:8323/api/v1/status
# Count validated ROAs
curl -s http://localhost:8323/api/v1/validity/AS215000/2001:db8:abcd::/48
Other Validators
- Fort: Lightweight alternative by LACNIC
- OctoRPKI: By Cloudflare, used in their production infrastructure
- rpki-client: OpenBSD-native, also runs on Linux
For redundancy, consider running two different validator implementations.
Step 3: Configure BIRD 2 for RPKI
Add the RPKI protocol and ROA tables to your BIRD configuration:
# /etc/bird/bird.conf
# ROA tables
roa4 table roa_v4;
roa6 table roa_v6;
# RPKI connection to Routinator
protocol rpki rpki1 {
roa4 { table roa_v4; };
roa6 { table roa_v6; };
remote "127.0.0.1" port 3323;
retry keep 5;
refresh keep 30;
expire 600;
}
# Optional: redundant validator
protocol rpki rpki2 {
roa4 { table roa_v4; };
roa6 { table roa_v6; };
remote "10.0.0.2" port 3323;
retry keep 5;
refresh keep 30;
expire 600;
}
Update Your Import Filters
filter import_rpki {
# Reject bogons first
if net ~ [ ::/8+, fe80::/10+, fc00::/7+, 2001:db8::/32+ ] then reject;
if net.len > 48 then reject;
# RPKI validation
if (roa_check(roa_v6, net, bgp_path.last) = ROA_INVALID) then {
print "RPKI INVALID: ", net, " via AS", bgp_path.last;
reject;
}
# Optionally tag valid/unknown for monitoring
if (roa_check(roa_v6, net, bgp_path.last) = ROA_VALID) then {
bgp_large_community.add((MY_ASN, 1000, 1)); # Mark as RPKI valid
}
accept;
}
Apply to your BGP sessions:
protocol bgp upstream_a from upstream {
neighbor 2001:db8:1::1 as 64500;
ipv6 {
import filter import_rpki;
export filter export_upstream;
};
}
Reload Without Disruption
sudo birdc configure
# BIRD reloads config without dropping BGP sessions
Step 4: Monitor Your RPKI Status
Check Your Own ROAs
# Via Routinator HTTP API
curl -s http://localhost:8323/api/v1/validity/AS215000/2001:db8:abcd::/48 | jq
# Via external services
# https://rpki-validator.ripe.net/
# https://bgp.tools/prefix/2001:db8:abcd::/48#rpki
Monitor for Invalid Routes
Set up alerting for RPKI invalid routes in your network:
#!/bin/bash
# /usr/local/bin/rpki-monitor.sh
INVALID_COUNT=$(birdc 'show route where roa_check(roa_v6, net, bgp_path.last) = ROA_INVALID' | grep -c "via")
if [ "$INVALID_COUNT" -gt 0 ]; then
echo "$INVALID_COUNT RPKI-invalid routes detected" | \
mail -s "RPKI Alert: Invalid Routes" noc@example.com
fi
ROA Expiry Monitoring
ROAs have an expiry date. If your ROAs expire, your routes become "NotFound" — which is less secure than "Valid."
# Check ROA expiry via RIPE NCC portal
# Or use the Routinator API:
curl -s http://localhost:8323/api/v1/status | jq '.roas'
RPKI Adoption in 2026
As of 2026, RPKI adoption has reached critical mass:
- 70%+ of IPv4 routes and 60%+ of IPv6 routes have ROAs
- Major networks (Cloudflare, Google, Amazon, Microsoft) reject RPKI-invalid routes
- RIPE NCC, APNIC, and ARIN all support hosted RPKI
- Most IX route servers perform RPKI validation by default
If you don't have ROAs, your routes are increasingly at a disadvantage — some networks may deprioritize "NotFound" routes, and you have zero protection against hijacking.
Common RPKI Mistakes
Creating ROAs with wrong max length: A /24 ROA with max length /28 means anyone who hijacks a /28 of your space will have a "Valid" route. Keep max length tight.
Forgetting to update ROAs when changing providers: If you move your prefix to a new ASN, update the ROA before the BGP change. Otherwise you'll create an invalid route for yourself.
Not monitoring ROA expiry: Expired ROAs = no protection. Set calendar reminders or automated alerts.
Running only one validator: If your single validator goes down, BIRD's ROA table expires and all routes become "NotFound." Run at least two validators for redundancy.
Not deploying on all border routers: RPKI validation on one router but not another creates inconsistent behavior. Deploy everywhere.
Beyond Origin Validation: BGPsec and ASPA
RPKI origin validation (what we've covered here) prevents prefix hijacking — someone announcing your prefix from their ASN. It doesn't prevent path manipulation — someone inserting your ASN into a fabricated path.
Two emerging standards address this:
- ASPA (Autonomous System Provider Authorization): Validates the AS path by checking that each AS-to-AS hop is authorized. Draft standard, gaining support.
- BGPsec: Cryptographic path validation. More complete but higher overhead. Limited deployment.
For now, RPKI origin validation with ROAs covers the most common attack scenarios and is straightforward to deploy.
Already running RPKI? What validator are you using, and have you caught any invalid routes? Share your experience in the comments.
Top comments (0)