RPKI ROA配置BGP:创建ROA,在BIRD2和FRR中验证路由

3 分钟阅读·Matthieu·rpkiroabgpbird2frrroutinatorripe-nccipv6|

在RIPE NCC门户中创建IPv4和IPv6 ROA,安装Routinator作为RTR缓存,在BIRD2和FRRouting中配置RPKI路由源验证,使用bgp.tools和RIPE Stat验证前缀状态。

没有RPKI,任何ASN都可以宣告任何前缀。Route Origin Authorization(ROA)以密码学方式将你的前缀绑定到你的ASN,而路由源验证(ROV)使路由器能够拒绝无效公告。本教程涵盖完整链路:在RIPE NCC门户创建ROA、运行Routinator作为本地RPKI缓存、在BIRD2和FRRouting中配置验证,以及确认一切正常。

前置条件:一个已注册的ASN、已分配的IP前缀(PA或PI)、一个在Linux VPS上正常运行的BGP会话(在VPS上使用自有IP进行BGP),以及已经运行的BIRD2(BIRD2 BGP配置)或FRR(FRR BGP配置)。

什么是RPKI?为什么你的BGP前缀需要ROA?

Resource Public Key Infrastructure(RPKI)是RFC 6480定义的密码学框架,通过区域互联网注册机构签发的X.509证书将互联网号码资源(IP前缀、ASN)与其合法持有者绑定。Route Origin Authorization(ROA)是一个签名对象,声明"ASN X被授权以最大前缀长度Z宣告前缀Y"。验证器获取这些ROA,并通过RPKI-to-Router(RTR)协议(RFC 8210)将结果传递给路由器。

当路由器收到BGP更新时,它会根据本地ROA表检查源ASN和前缀。每个前缀获得以下三种验证状态之一:

状态 含义 建议操作
Valid 存在ROA且与源ASN和前缀长度匹配 接受
Invalid 存在ROA但源ASN或前缀长度不匹配 拒绝
Not Found 没有ROA覆盖此前缀 接受(可选择降低local-pref)

没有ROA,你的前缀显示为"Not Found"。这比"Invalid"好,但执行ROV的网络在两者都可用时会优先选择对等方的"Valid"路由而非你的"Not Found"公告。创建ROA是第一步。验证入站路由可以保护你的网络免于接受被劫持的前缀。

如何在RIPE NCC门户中创建IPv4和IPv6 ROA?

登录RIPE NCC门户,导航到Resources,然后RPKI Dashboard。如果你还未初始化RPKI,选择"Hosted"证书颁发机构。RIPE NCC为你管理CA和签名。Hosted CA激活后,切换到BGP Announcements标签页。RIPE会根据你当前的BGP公告预填ROA建议。

  1. 点击Create ROA(或ROA标签页中的**+ New ROA**)。
  2. Origin ASN设置为你的AS号码(例如AS213279)。
  3. Prefix设置为你的IPv4分配(例如192.0.2.0/24)。
  4. Maximum Length设置为等于前缀长度(/24)。不要增大此值。参见下方maxLength部分。
  5. 点击Publish
  6. 为你的IPv6前缀重复操作(例如2001:db8::/48,最大长度/48)。

在RPKI Dashboard中确认ROA状态显示"Published"。向验证器的传播通常需要10到20分钟,取决于其刷新间隔。

双栈提醒: 每个前缀创建一个ROA。如果你宣告192.0.2.0/242001:db8::/48,需要两个ROA。如果你宣告额外的more-specific(从/24中划分的/25),每个都需要自己的ROA和ASN绑定。

如何在Linux上安装Routinator作为RPKI-RTR缓存?

Routinator是NLnet Labs开发的RPKI依赖方(验证器)。它从所有五个RIR信任锚获取并验证ROA,然后通过RTR协议向路由器提供Validated ROA Payloads(VRP)。当前稳定版本:0.15.1。

从NLnet Labs仓库安装

在Debian 12或Ubuntu 24.04上:

sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release

添加NLnet Labs签名密钥和仓库:

curl -fsSL https://packages.nlnetlabs.nl/aptkey.asc | sudo gpg --dearmor -o /usr/share/keyrings/nlnetlabs-archive-keyring.gpg

Debian:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nlnetlabs-archive-keyring.gpg] https://packages.nlnetlabs.nl/linux/debian $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/nlnetlabs.list > /dev/null

Ubuntu:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nlnetlabs-archive-keyring.gpg] https://packages.nlnetlabs.nl/linux/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/nlnetlabs.list > /dev/null

安装Routinator:

sudo apt update
sudo apt install -y routinator

软件包安装一个自动启动的systemd服务。Routinator以routinator用户身份运行。

验证服务

sudo systemctl status routinator

你应该看到active (running)。首次同步需要2到5分钟,期间Routinator获取所有信任锚证书并验证全球ROA集合。

通过查询HTTP API确认初始同步已完成(打包版本以syslog方式记录日志且细节较少,HTTP API是可靠来源):

curl -s http://127.0.0.1:8323/api/v1/status | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'IPv4 VRPs: {d[\"payload\"][\"routeOriginsIPv4\"][\"final\"]}, IPv6 VRPs: {d[\"payload\"][\"routeOriginsIPv6\"][\"final\"]}')"

如果同步仍在进行,计数器将为零。等待2到5分钟后重试。当你看到非零计数(IPv4数十万,IPv6数万),初始同步已完成。

配置

软件包配置位于/etc/routinator/routinator.conf。默认值是安全的:RTR监听127.0.0.1:3323,HTTP监听127.0.0.1:8323。两者都只绑定到localhost。

关键设置:

选项 默认值 用途
rtr-listen ["127.0.0.1:3323"] 路由器RTR服务器
http-listen ["127.0.0.1:8323"] HTTP界面和API
refresh 600 RPKI同步间隔(秒)
retry 600 同步失败后重试等待(秒)
expire 7200 缓存VRP过期时间(秒)

如果BIRD2或FRR运行在同一台机器上(VPS BGP设置的典型情况),保持默认的127.0.0.1绑定。无需修改防火墙。

如果你在单独的服务器上运行Routinator,绑定到私有IP并限制访问:

sudo ufw allow from 10.0.0.0/24 to any port 3323 proto tcp comment "RTR from routers"

检查HTTP界面:

curl -s http://127.0.0.1:8323/api/v1/status | head -20

返回包含当前VRP计数、上次同步时间和验证器状态的JSON。

如何在BIRD2中配置RPKI验证?

BIRD2通过rpki协议原生支持RPKI(自BIRD 2.0起可用;Ubuntu 24.04提供BIRD 2.14)。它通过RTR连接到Routinator,填充ROA表,并为导入过滤器提供roa_check()函数。无需外部库。

将以下内容添加到你的BIRD2配置中(通常是/etc/bird/bird.conf):

定义ROA表

roa4 table roa_v4;
roa6 table roa_v6;

配置RPKI协议

protocol rpki rpki_routinator {
    roa4 { table roa_v4; };
    roa6 { table roa_v6; };
    remote 127.0.0.1 port 3323;
    retry keep 90;
    refresh keep 600;
    expire keep 7200;
}

keep关键字告诉BIRD优先使用服务器提供的计时器值,回退到指定的默认值。retry 90表示BIRD在RTR会话断开后90秒重新连接。

向导入过滤器添加ROA验证

filter bgp_import_v4 {
    if (roa_check(roa_v4, net, bgp_path.last_nonaggregated) = ROA_INVALID) then {
        print "RPKI INVALID: ", net, " from AS", bgp_path.last;
        reject;
    }
    if (roa_check(roa_v4, net, bgp_path.last_nonaggregated) = ROA_VALID) then {
        bgp_local_pref = 200;
    }
    accept;
}

filter bgp_import_v6 {
    if (roa_check(roa_v6, net, bgp_path.last_nonaggregated) = ROA_INVALID) then {
        print "RPKI INVALID: ", net, " from AS", bgp_path.last;
        reject;
    }
    if (roa_check(roa_v6, net, bgp_path.last_nonaggregated) = ROA_VALID) then {
        bgp_local_pref = 200;
    }
    accept;
}

bgp_path.last_nonaggregatedbgp_path.last更安全,因为它跳过聚合产生的AS_SET条目。无效路由被拒绝。有效路由获得更高的local-pref。Not Found路由以默认local-pref通过。

将过滤器应用到BGP对等

protocol bgp upstream_v4 {
    local as 213279;
    neighbor 198.51.100.1 as 64500;
    ipv4 {
        import filter bgp_import_v4;
        import table;
        export where source ~ [RTS_STATIC, RTS_BGP];
    };
}

import table指令很重要。它使BIRD在ROA表变化时重新评估已过滤的路由,无需完全重置会话。

重新加载并验证

sudo birdc configure

检查RPKI会话:

sudo birdc show protocols all rpki_routinator

在输出中查找Established。然后检查ROA表内容:

sudo birdc show route table roa_v4 count

你应该看到数十万条目(2026年初全球ROA表超过800,000个VRP)。

检查特定前缀的验证:

sudo birdc show route 192.0.2.0/24 all

输出包含ROA字段,显示validinvalidunknown(not found)。

如何在FRRouting中配置RPKI验证?

FRRouting通过rpki模块支持RPKI,底层使用librtr(Ubuntu 24.04提供FRR 8.4.4;FRR 9.x+和10.x也受支持)。该模块连接到Routinator的RTR服务器并与BGP route-map集成。

安装RPKI模块

在已安装FRR的Debian/Ubuntu上:

sudo apt install -y frr-rpki-rtrlib

启用模块

编辑/etc/frr/daemons,在bgpd选项中添加-M rpki

bgpd_options="  -A 127.0.0.1 -M rpki"

重启FRR:

sudo systemctl restart frr

验证bgpd加载了模块:

sudo vtysh -c "show rpki cache-server"

如果命令无错误执行(配置缓存之前输出可能为空),模块已加载。如果你得到% Unknown command-M rpki标志缺失或frr-rpki-rtrlib未安装。

配置RTR缓存

进入vtysh并配置:

sudo vtysh
configure terminal
rpki
 rpki cache 127.0.0.1 3323 preference 1
 rpki polling_period 300
 rpki expire_interval 7200
 rpki retry_interval 600
 exit

注意:FRR 9.x+使用语法rpki cache tcp 127.0.0.1 3323 preference 1(带有显式tcp关键字)。FRR 8.x使用rpki cache 127.0.0.1 3323 preference 1,不带该关键字。使用vtysh -c "show version"检查你的版本。

为RPKI状态创建route-map

route-map rpki-filter permit 10
 match rpki valid
 set local-preference 200
exit

route-map rpki-filter deny 20
 match rpki invalid
exit

route-map rpki-filter permit 30
 match rpki notfound
exit

这接受有效路由并提升local-pref,拒绝无效路由,以默认local-pref接受not-found路由。

将route-map应用到BGP邻居

router bgp 213279
 neighbor 198.51.100.1 remote-as 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 route-map rpki-filter in
  neighbor 198.51.100.1 soft-reconfiguration inbound
 exit-address-family
 address-family ipv6 unicast
  neighbor 2001:db8::1 route-map rpki-filter in
  neighbor 2001:db8::1 soft-reconfiguration inbound
 exit-address-family
exit

soft-reconfiguration inbound是必需的。没有它,FRR无法在RPKI缓存更新时重新评估现有路由。FRR存储从对等方收到的未修改路由,并在VRP变化时重新应用route-map。

保存配置:

write memory
end

验证

检查RTR连接:

sudo vtysh -c "show rpki cache-connection"

在输出中查找(connected)。然后检查前缀表:

sudo vtysh -c "show rpki prefix-table" | head -20

按验证状态过滤BGP路由:

sudo vtysh -c "show bgp ipv4 unicast rpki valid" | head -20
sudo vtysh -c "show bgp ipv4 unicast rpki invalid"

invalid输出应显示你正在拒绝的路由。

BIRD2与FRR RPKI配置对比

特性 BIRD2 FRR
模块安装 内置(无需额外包) frr-rpki-rtrlib包 + -M rpki标志
RTR配置 remoteprotocol rpki vtysh中的rpki cache命令
ROA表 显式roa4/roa6 内部,不直接暴露
过滤机制 导入过滤器中的roa_check() route-map中的match rpki
自动重新评估 import table指令 soft-reconfiguration inbound
显示ROA计数 birdc show route table roa_v4 count vtysh show rpki prefix-table
显示验证 birdc show route ... all(ROA字段) vtysh show bgp rpki valid/invalid/notfound

如何验证前缀的RPKI状态?

创建ROA并配置验证后,从多个角度进行验证。

本地验证

在路由器上确认你自己的前缀显示为有效:

BIRD2:

sudo birdc show route 192.0.2.0/24 all | grep -i roa

FRR:

sudo vtysh -c "show rpki prefix-table 192.0.2.0/24"

两者都应显示你的ASN为授权源。

Routinator HTTP API

curl -s "http://127.0.0.1:8323/api/v1/validity/AS213279/192.0.2.0/24"

返回包含验证状态、匹配VRP和源信任锚的JSON。

bgp.tools

在浏览器中打开https://bgp.tools/prefix/192.0.2.0/24。RPKI列显示绿色盾牌表示Valid,红色表示Invalid,灰色表示Not Found。ROA创建后15到30分钟外部工具才能检测到变化。

RIPE Stat

查询RPKI验证API:

curl -s "https://stat.ripe.net/data/rpki-validation/data.json?resource=AS213279&prefix=192.0.2.0/24" | python3 -m json.tool

在响应中查找"status": "valid"。RIPE Stat还会显示哪些ROA覆盖了该前缀以及maxLength是否匹配。

对IPv6重复

使用你的IPv6前缀运行相同的检查。上述每个命令都接受IPv6前缀。将192.0.2.0/24替换为2001:db8::/48,验证两个地址族都被覆盖。

为什么应避免将maxLength设置为大于前缀长度?

将maxLength设置为等于你的前缀长度。这是RFC 9319(更新并扩展了RFC 7115)的建议。

当你在/20的ROA上将maxLength设置为/24时,你授权你的ASN宣告/20以及到/24的每个more-specific。这意味着16个/24被覆盖。攻击者以你的ASN为源劫持其中一个/24将通过RPKI验证为"Valid"。被劫持的more-specific通过最长匹配路由获胜,ROA无法帮助你,因为你授权了该长度。

这被称为伪造源子前缀劫持(forged-origin sub-prefix hijack)。RFC 9319引用的2017年测量发现,使用maxLength的ROA中84%容易受到此攻击。

具体示例:

ROA 授权内容
192.0.2.0/20, maxLength /20 仅你的ASN的192.0.2.0/20。安全。
192.0.2.0/20, maxLength /24 你的ASN的/20/21/22/23/24。任何/24都可以通过伪造你的源ASN被劫持。

何时maxLength > 前缀长度可接受? 仅当你在生产中确实进行去聚合时(例如宣告/20和特定/24用于流量工程),且每个去聚合的前缀需要验证。在这种情况下,为每个宣告的前缀创建单独的ROA,而不是一个宽maxLength的ROA。每个公告一个ROA是最安全的模式。

DDoS缓解例外: 如果你使用清洗中心等服务,该服务从你的ASN重新宣告你的more-specific,你可能需要maxLength来覆盖这些前缀。记录此例外并定期审计。

RPKI缓存宕机时会发生什么?

当Routinator停止或不可达时,路由器的行为取决于过期计时器。

BIRD2将最后已知的ROA表保留在内存中,持续时间为expire(默认7200秒/2小时)。在此窗口内,验证使用过期数据正常继续。过期后,BIRD删除所有ROA条目,每条路由回退为"Not Found"。不会因无效而拒绝路由,但也不会获得有效的local-pref加成。

FRR行为类似。rpki expire_interval控制RTR连接断开后缓存VRP保持可用的时间。

降低风险

运行第二个Routinator实例或在单独的机器上使用不同的验证器(StayRTR、Fort)。将两者都配置为RTR源。

BIRD2支持多个protocol rpki块:

protocol rpki rpki_backup {
    roa4 { table roa_v4; };
    roa6 { table roa_v6; };
    remote 10.0.0.2 port 3323;
    retry keep 90;
    refresh keep 600;
    expire keep 7200;
}

FRR支持多个具有不同偏好的缓存服务器:

rpki
 rpki cache 127.0.0.1 3323 preference 1
 rpki cache 10.0.0.2 3323 preference 2
exit

偏好值较低的优先尝试。主服务器宕机时FRR回退到备用服务器。

监控Routinator健康状态。 使用你的监控系统检查systemctl status routinator和HTTP API状态端点。VRP计数骤降(突然降至零意味着同步失败)和RTR连接丢失(在journalctl -u routinator中可见)时发出告警。

故障排除

创建后ROA显示"Not Found"。 传播需要10到20分钟。Routinator默认每10分钟同步一次(refresh = 600)。强制重启同步:sudo systemctl restart routinator,然后等待初始同步完成。

birdc显示ROA表中有0条目。 检查birdc show protocols all rpki_routinator。如果状态不是"Established",验证Routinator正在运行并监听3323端口:ss -tlnp | grep 3323

FRR的rpki显示"Unknown command"。 /etc/frr/daemons中缺少-M rpki标志或frr-rpki-rtrlib未安装。安装软件包,添加标志,重启FRR。

ROA变更后路由未重新评估。 在BIRD2中,向BGP通道添加import table;。在FRR中,在邻居上启用soft-reconfiguration inbound

所有路由显示Invalid。 你的ROA可能有错误的ASN或前缀。在RIPE门户中仔细检查。同时确认路由器的ASN与ROA中填写的一致。

后续步骤:将RPKI验证与prefix-list和AS-path过滤器结合以实现纵深防御 。使用BGPalerter监控前缀的RPKI invalid告警 。


Copyright 2026 Virtua.Cloud. All rights reserved.

准备好亲自尝试了吗?

几秒内部署您自己的服务器。支持 Linux、Windows 或 FreeBSD。

查看 VPS 方案