RPKI SelfLab
EN ES PT
Open source · Docker or VM · English, Español, Português

A hands-on lab for ROA, ROV and ASPA, running on your own computer

Real BGP routers, three RPKI validators, a CA and a simulated registry, all in containers. A guided story shows what origin validation catches, what slips past it, and what ASPA adds.

The lab's web panel: the guide on the left, the live topology in the middle, the observers' verdicts below, one tab per observer

What's inside

Everything is real software, not a simulation. Three observers receive the same announcements and RPKI objects, each pairing a router with a validator in its own way, so you can compare three implementations at every step.

  • BIRD and OpenBGPD routers: the origin, two providers, three validating observers, an attacker and a peer.
  • Routinator and FORT validators, feeding their observers over RTR version 2, which carries ASPA, and rpki-client, which runs on observer2's own host and hands OpenBGPD a file to include, the way OpenBSD does it.
  • Krill as the holder's CA, where the ROAs and the ASPA object are created.
  • A simulated registry (RIR/NIR) with its own trust anchor and repository. CA delegation and publication use the same XML exchanges as a real registry (RFC 8183, 6492 and 8181). The lab teaches the delegated model: you run your own CA, the registry certifies it, and, as RIRs and NIRs often do, it also offers the repository to publish in.
  • A web panel with the live topology, the guide, the routers' terminals and the web interfaces, in tabs.
  • Runs on Linux, macOS and Windows (WSL 2) with Docker, or as a ready-made virtual machine. No Internet needed once installed.
The lab's topology: the registry at the top; Routinator and FORT above observer1 and observer3; observer2, which validates on its own host, between them; the two providers and AS666; and, at the bottom, the origin, its CA and the peer

The story, in nine steps

The guide is one story: three attacks, and which check stops each one. AS64500 is multihomed and prefers Provider B; it prepends twice towards Provider A, its backup. Three observers receive its prefix over both providers. The screenshots below are the panel at each step.

Step 1

A clean baseline

All three observers receive 203.0.113.0/24 over both providers and pick Provider B's shorter path. Nobody validates anything yet: the RPKI pieces exist, but no router talks to a validator.

Step 1: topology and verdicts, no validation
Step 2

The naive hijack wins

AS666 announces the origin's prefix as its own. Its path, 666, is one hop long against two and four, and nothing else tells the routes apart. The attacker's links turn orange: the observers are using its route.

Without validation, BGP has no way to tell a hijack from the real thing.

Step 2: the hijack is the best route on the observers
Step 3

ROV enters, marking what looks wrong

The origin creates its ROAs in Krill, and the observers deploy origin validation in its safe first form: invalid routes are only marked and demoted. The hijack becomes Invalid with local_pref 10, and Provider B's path is selected again.

Deploying ROV takes three pieces on any router: an RTR session, a test on every route, and an action on the result.

Step 3: the hijack is marked ROV Invalid
Step 4

The forged path

AS666 now announces 666 64500, writing the real origin at the end of the path. ROV only checks the last AS, so it says Valid, and the forged route wins the tie with Provider B.

Origin validation can't tell two paths apart when the origin is the same.

Step 4: the forged path is ROV Valid
Step 5

ASPA enters, also marking first

The origin publishes an ASPA object listing only Provider A, and the observers deploy ASPA verification. The forged path becomes Invalid: the hop 64500→666 was never authorized. But so does Provider B's legitimate path, and the observers fall back to the backup.

An ASPA object must list every provider. Forgetting one diverts the origin's own traffic.

Step 5: the forged path and Provider B's path are ASPA Invalid
Step 6

You forgot a provider

Adding Provider B to the object fixes it: both legitimate paths are Valid again and Provider B is selected, while the forged path stays demoted. The fix reaches the routers through republication and revalidation alone.

Step 6: both legitimate paths ASPA Valid again
Step 7

The peer leaks

A legitimate peer passes the origin's routes, learned over private peering, on to Provider A. Nothing is forged: 64501 64499 64500 is Valid for ROV and Invalid for ASPA, because 64499 is not one of the origin's providers.

In a leak nobody lies about the origin; what's wrong is where the route went. ROV can't see it, ASPA can.

Step 7: the leaked path is ROV Valid and ASPA Invalid
Step 8

Deploying for real: drop

Both checks switch from marking to dropping, the way a production router is configured. The forged and the leaked routes disappear. Provider A's own path is still missing, though: Provider A keeps advertising the leak instead, and no policy on the observers can change that.

Marking only helps while a valid alternative exists. Dropping is what protects the network.

Step 8: invalid routes dropped
Step 9

Put it away

The peer fixes its export policy and Provider A's own path comes back. The observers stay fully deployed, with ROV and ASPA both dropping.

Step 9: the leak is gone and both legitimate paths are back

What caught what

AttackAS_PATHROVASPA
Naive hijack666catches itnothing to check
Forged path666 64500fooledcatches it
Route leak64501 64499 64500can't see itcatches it

Made for learning, and for teaching

Built for hands-on RPKI courses, and usable by anyone who wants to study on their own.

Guide in three languages

English, Spanish and Portuguese. Every command block says where it runs and opens the right terminal.

Challenges

Some steps hide their solution behind hints and a timer; "Check my lab" looks at the lab's real state.

Checkpoints

They tick themselves as your lab reaches each step, and any step command puts the lab back on track.

The preparation too

Create the CA in Krill and play both sides of the delegation with the simulated registry.

Your own configs

A work/ folder to write your own ROV and ASPA configuration and load it on the routers.

Extra exercises

Upstream vs downstream (and where BIRD and OpenBGPD disagree), maxLength, a look inside RTR, and rpki-client served over RTR.

A challenge in the guide, with hints, timer and Check my lab
The simulated registry's panel

Get started

  1. Install Docker with Compose v2 (Docker Desktop, OrbStack, or Docker Engine on Linux). On Windows, use WSL 2 and work inside its Ubuntu terminal.
  2. Get the lab:
    git clone https://github.com/moreiras/rpki-selflab.git
    cd rpki-selflab
    or download the source from the latest release.
  3. Bring it up and open http://localhost:8080:
    ./scripts/lab.sh up

Would rather not install Docker?

Each release also has a virtual machine with everything inside (amd64 and arm64), with its own desktop, browser and terminal. Details in vm/README.md.

The full guide is also readable on GitHub: guide/GUIDE.en.md.