シナプス技術者ブログ

シナプスの技術者公式ブログ。インターネットで、鹿児島の毎日を笑顔にします。

"FRRouting + GoBGP + Routinator" on DockerでROVを試してみた

こんにちは、中野です。

今回は、BGPにおけるネットワークセキュリティ技術である「ROV(Route origin validation)」について、Dockerコンテナで試す環境を作ってみましたので、記事にしてみました。

ROVの技術や仕組み等は、JPNICさんのWebサイトやJANOGの過去プログラム、その他の様々なWeb記事をご確認いただくとして、この記事では作った環境や使い方について解説します。

作った環境はこちらに置いてありますので、ご自由にお試しください。

github.com

構成

本環境は、以下のコンポーネントにて構成しています。

  • GoBGP
    • Goで書かれたオープンソースのBGP実装
    • GitHubのmasterブランチよりビルド
    • Route Views Archive Project Pageにて公開されているフルルートのRIBを注入し、BGPにてFRRoutingに対してフルルートを広告
  • Routinator
    • Rustで書かれたオープンソースのRPKI Relying Partyソフトウェア
    • 公式Dockerイメージのv0.12.1を使用
    • ROAの取得、BGPルータとのRPKI-RTRにも対応
  • FRRouting
    • Quaggaから派生したオープンソースのルーティングプロトコルスイート
    • 公式Dockerイメージの9.0.0を使用
    • Routinator、JPNAP ROAキャッシュBBIX ROAキャッシュから、RPKI-RTRにてVRP(Validate ROA Payload)を受信
    • GoBGPからフルルートを受信し、ROV(Route origin validation)を実施

ネットワーク構成は、以下のとおりです。

  • AS64513にgobgpを配置
    • gobgp 〜 frr1・frr2・frr3間でeBGPピアを設定
    • gobgpにフルルートのRIBをインポートし、BGPにてfrr1/frr2/frr3にベストパスを広告
  • AS64512にfrr1・frr2・frr3を配置
    • frr1・frr2・frr3はそれぞれ異なるROAキャッシュを参照
    • frr1・frr2・frr3は、受信したフルルートをROVの状態(valid/invalid/notfound)に応じてLocal Preferenceを設定

設定概要

docker-compose.yml

この環境は、Docker Composeを利用しています。

Routinator1つ、GoBGP1つ、FRRouting3つのコンテナと、これらのコンテナを接続する10.0.0.0/24のネットワークを作成します。

また、GoBGP、FRRoutingでは設定ファイルをコンテナから参照するため、ボリュームの設定をしています。

services:
  routinator:
    image: nlnetlabs/routinator:v0.12.1
    hostname: routinator
    networks:
      network-bgp:
        ipv4_address: 10.0.0.2
    ports:
      - 9556:9556
  gobgp:
    build:
      context: gobgp/docker
    hostname: gobgp
    networks:
      network-bgp:
        ipv4_address: 10.0.0.3
    volumes:
      - ./gobgp/gobgpd.conf:/gobgpd.conf
      - ./gobgp/ribs/:/ribs/
    command: /gobgpd -f /gobgpd.conf
  frr1:
    image: quay.io/frrouting/frr:9.0.0
    hostname: frr1
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
    networks:
      network-bgp:
        ipv4_address: 10.0.0.4
    volumes:
      - ./frr/daemons:/etc/frr/daemons
      - ./frr/frr1.conf:/etc/frr/frr.conf
  frr2:
    image: quay.io/frrouting/frr:9.0.0
    hostname: frr2
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
    networks:
      network-bgp:
        ipv4_address: 10.0.0.5
    volumes:
      - ./frr/daemons:/etc/frr/daemons
      - ./frr/frr2.conf:/etc/frr/frr.conf
  frr3:
    image: quay.io/frrouting/frr:9.0.0
    hostname: frr3
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
    networks:
      network-bgp:
        ipv4_address: 10.0.0.6
    volumes:
      - ./frr/daemons:/etc/frr/daemons
      - ./frr/frr3.conf:/etc/frr/frr.conf

networks:
  network-bgp:
    driver: bridge
    ipam:
      config:
        - subnet: 10.0.0.0/24

GoBGPのDockerfile

GoBGPは公式のコンテナイメージがあるようですが、数年前のイメージと古かったため、GitHubのmasterブランチをビルドしています。

FROM golang:1.20.6-alpine3.18 AS builder
RUN apk update && apk add git \
  && git clone https://github.com/osrg/gobgp.git /go/src/github.com/osrg/gobgp \
  && cd /go/src/github.com/osrg/gobgp \
  && go mod download \
  && cd /go/src/github.com/osrg/gobgp/cmd/gobgp \
  && go build \
  && cd /go/src/github.com/osrg/gobgp/cmd/gobgpd \
  && go build \
  && mkdir /ribs

FROM scratch
COPY --from=builder /go/src/github.com/osrg/gobgp/cmd/gobgp/gobgp /gobgp
COPY --from=builder /go/src/github.com/osrg/gobgp/cmd/gobgpd/gobgpd /gobgpd
COPY --from=builder /ribs /ribs
CMD ["/gobgpd"]

frr1の設定

FRRoutingは、IPアドレス、BGPピア、ルートマップ、RPKIの設定と必要最低限のみを設定をしています。

また、ROVの結果に応じて、Local Preferenceを以下のように変えています。

ROV結果 Local Preference
valid 200
notfound 100
invalid 10
frr version 9.0_git
frr defaults traditional
hostname frr1
no ipv6 forwarding
bgp no-rib
!
interface eth0
 ip address 10.0.0.4/24
exit
!
router bgp 64512
 neighbor 10.0.0.3 remote-as external
 !
 address-family ipv4 unicast
  neighbor 10.0.0.3 soft-reconfiguration inbound
  neighbor 10.0.0.3 route-map ebgp-in in
  neighbor 10.0.0.3 route-map ebgp-out out
 exit-address-family
exit
!
route-map ebgp-in permit 10
 match rpki invalid
 set local-preference 10
exit
!
route-map ebgp-in permit 100
 match rpki valid
 set local-preference 200
exit
!
route-map ebgp-in permit 200
 match rpki notfound
 set local-preference 100
exit
!
route-map ebgp-out permit 10
exit
!
rpki
 rpki polling_period 300
 rpki retry_interval 30
 rpki expire_interval 3600
 rpki cache 10.0.0.2 3323 preference 1
exit
!

実行方法

フルルートのRIBのダウンロード

GoBGPへフルルートを注入するために、事前にダウンロードします。

Docker Composeの起動

Docker Composeを、以下のコマンドにて起動します。

% docker compose up -d
[+] Running 16/16
 ✔ routinator 5 layers [⣿⣿⣿⣿⣿]      0B/0B      Pulled                                            6.0s
   ✔ 6875df1f5354 Already exists                                                                  0.0s
   ✔ 160d0347c010 Already exists                                                                  0.0s
   ✔ 6eed1cee6d09 Already exists                                                                  0.0s
   ✔ 9d6980578a97 Already exists                                                                  0.0s
   ✔ 14c5217b1cfb Already exists                                                                  0.0s
 ✔ frr2 Pulled                                                                                   10.3s
 ✔ frr3 Pulled                                                                                   10.3s
 ✔ frr1 7 layers [⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled                                              10.3s
   ✔ 8c6d1654570f Already exists                                                                  0.0s
   ✔ 7d0afa75b38d Pull complete                                                                   1.0s
   ✔ b53793227860 Pull complete                                                                   2.0s
   ✔ 0ac198d11877 Pull complete                                                                   4.5s
   ✔ 4f4fb700ef54 Pull complete                                                                   4.5s
   ✔ 83f241f7a471 Pull complete                                                                   4.5s
   ✔ ecb4523afdab Pull complete                                                                   4.5s
[+] Building 1.0s (9/9) FINISHED
 => [gobgp internal] load build definition from Dockerfile                                         0.0s
 => => transferring dockerfile: 617B                                                               0.0s
 => [gobgp internal] load .dockerignore                                                            0.0s
 => => transferring context: 2B                                                                    0.0s
 => [gobgp internal] load metadata for docker.io/library/golang:1.20.6-alpine3.18                  0.9s
 => [gobgp builder 1/2] FROM docker.io/library/golang:1.20.6-alpine3.18@sha256:7839c9f01b5502d7c   0.0s
 => CACHED [gobgp builder 2/2] RUN apk update && apk add git   && git clone https://github.com/o   0.0s
 => CACHED [gobgp stage-1 1/3] COPY --from=builder /go/src/github.com/osrg/gobgp/cmd/gobgp/gobgp   0.0s
 => CACHED [gobgp stage-1 2/3] COPY --from=builder /go/src/github.com/osrg/gobgp/cmd/gobgpd/gobg   0.0s
 => CACHED [gobgp stage-1 3/3] COPY --from=builder /ribs /ribs                                     0.0s
 => [gobgp] exporting to image                                                                     0.0s
 => => exporting layers                                                                            0.0s
 => => writing image sha256:ddab0141cc075ce7da75dedbb7374e1f4ff08fe9ce49a2c57ebe929b99b9b52c       0.0s
 => => naming to docker.io/library/try_rov_frrouting_gobgp_routinator_on_docker-gobgp              0.0s
[+] Running 6/6
 ✔ Network try_rov_frrouting_gobgp_routinator_on_docker_network-bgp     Created                   0.0s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-gobgp-1       Started                   0.8s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-frr1-1        Started                   0.7s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-frr3-1        Started                   0.7s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-frr2-1        Started                   0.8s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-routinator-1  Started                   0.9s
 %

Routinatorのコンテナは、ROAを取得・VRP(Validate ROA Payload)の生成完了まで数分かかります(手元の環境では4分程度かかりました)。

GoBGPにフルルートをインポート

GoBGPのMRT Formatの経路注入の機能を利用して、ダウンロードしたMRTからフルルートをインポートします。

% docker compose exec gobgp /gobgp mrt inject --only-best global /ribs/rib.20230830.0000
%

BGPピアやROAキャッシュの状態確認

FRRoutingにログインして、ROAキャッシュサーバの設定や接続状態を確認します。

% docker compose exec frr1 vtysh
% Can't open configuration file /etc/frr/vtysh.conf due to 'No such file or directory'.
Configuration file[/etc/frr/frr.conf] processing failure: 11

Hello, this is FRRouting (version 9.0_git).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

frr1# show bgp summary

IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.4, local AS number 64512 vrf-id 0
BGP table version 0
RIB entries 1796247, using 329 MiB of memory
Peers 1, using 13 KiB of memory

Neighbor        V         AS   MsgRcvd   MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd   PfxSnt Desc
10.0.0.3        4      64513    986261        32        0    0    0 00:15:14       986216        0 N/A

Total number of neighbors 1

frr1# show rpki cache-server
host: 10.0.0.2 port: 3323, preference: 1

frr1# show rpki cache-connection
Connected to group 1
rpki tcp cache 10.0.0.2 3323 pref 1 (connected)

frr1# 

ROAキャッシュから受信したVRP(Validate ROA Payload)の確認

ROAキャッシュから受信したVRP(Validate ROA Payload)を確認するには、以下のコマンドを実行します。

frr1# show rpki prefix-table
RPKI/RTR prefix table
Prefix                                   Prefix Length  Origin-AS
1.128.0.0                                   11 -  11   1221
1.0.0.0                                     24 -  24   13335

  <中略>

2a01:c000::                                 19 -  48   5511
2003::                                      19 -  19   3320
Number of IPv4 Prefixes: 377013
Number of IPv6 Prefixes: 82276

個別経路のROVの状態の確認

個別経路のROVの状態を確認するには、以下のコマンドを実行します。

以下の例では、 rpki validation-state: valid と ROVが valid となっている事が分かります。

frr1# show bgp ipv4 unicast 8.8.8.0/24
BGP routing table entry for 8.8.8.0/24, version 0
Paths: (1 available, no best path)
  Not advertised to any peer
  64513 23673 15169
    203.189.128.233 (inaccessible, import-check enabled) from 10.0.0.3 (10.0.0.3)
      Origin IGP, localpref 200, invalid, external, rpki validation-state: valid
      Community: 23673:10 23673:15169 23673:65101
      Last update: Sat Sep  2 01:40:14 2023

ROVによる経路判定の確認

FRRoutingでは、GoBGPから受信した経路に対してROVを行いますが、その判定結果(valid, invalid, notfound)毎の経路全体を見るには、以下のコマンドを実行します。

validと判定された経路

frr1# show bgp ipv4 unicast rpki valid
BGP table version is 0, local router ID is 10.0.0.4, vrf id 0
Default local pref 100, local AS 64512
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

    Network          Next Hop            Metric LocPrf Weight Path
V   1.0.0.0/24       203.189.128.233               200      0 64513 23673 13335 i
V   1.0.4.0/22       203.189.128.233               200      0 64513 23673 6939 7545 2764 38803 i

  <中略>

V   223.233.36.0/22  203.189.128.233               200      0 64513 23673 9498 45609 ?
V   223.233.40.0/22  203.189.128.233               200      0 64513 23673 9498 45609 ?

Displayed  449355 routes and 986216 total paths

notfoundと判定された経路

frr1# show bgp ipv4 unicast rpki notfound
BGP table version is 0, local router ID is 10.0.0.4, vrf id 0
Default local pref 100, local AS 64512
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

    Network          Next Hop            Metric LocPrf Weight Path
N   0.0.0.0/0        94.156.252.18            0    100      0 64513 34224 3356 i
V   1.0.0.0/24       203.189.128.233               200      0 64513 23673 13335 i

  <中略>

V   223.233.36.0/22  203.189.128.233               200      0 64513 23673 9498 45609 ?
V   223.233.40.0/22  203.189.128.233               200      0 64513 23673 9498 45609 ?

Displayed  986216 routes and 986216 total paths

本来であれば先頭に N とROVがnot foundとなった経路のみ表示されるはずですが、バグによりnot foundの経路だけでなくvalid・invalidの経路も表示されてしまっています。

こちらは、正しく表示されるよう修正し、Pull Requestを送り無事にマージされましたので、次のFRRoutingのリリースより正常に表示されそうです。

github.com

invalidと判定された経路

frr1# show bgp ipv4 unicast rpki invalid
BGP table version is 0, local router ID is 10.0.0.4, vrf id 0
Default local pref 100, local AS 64512
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found

    Network          Next Hop            Metric LocPrf Weight Path
I   1.6.219.0/24     203.189.128.233                10      0 64513 23673 23764 6453 4755 9583 137130 i
I   1.6.230.0/24     203.189.128.233                10      0 64513 23673 23764 6453 4755 i

  <中略>

I   223.123.103.0/24 203.189.128.233                10      0 64513 23673 17557 138423 i
I   223.224.38.0/24  203.189.128.233                10      0 64513 23673 9498 i

Displayed  5482 routes and 986216 total paths

Docker Composeの停止

ROVの動作確認等が終わり、コンテナ環境が不要となった場合は、以下のコマンドにてDocker Composeを停止します。

% docker compose down
[+] Running 6/6
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-frr3-1        Removed                   1.1s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-routinator-1  Removed                   3.6s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-frr2-1        Removed                   1.1s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-gobgp-1       Removed                   1.1s
 ✔ Container try_rov_frrouting_gobgp_routinator_on_docker-frr1-1        Removed                   1.1s
 ✔ Network try_rov_frrouting_gobgp_routinator_on_docker_network-bgp     Removed                   0.0s
%

まとめ

実際にBGPのフルルートを受ける事ができない環境でも、Route Views Archive Project Pageにて公開されているMRTデータや、ROAキャッシュなどを活用することで、ROV(Route origin validation)を試すことができました。

現在、シナプスのネットワークではROVの本番導入ができていませんので、ROAキャッシュの運用検証などを進めた後に、ネットワークにROVを導入し、より安定した安全なネットワークを作っていきたいと思います。