dockerを使ってRPKI Validationを試してみる
はじめに
2017年8月25日のインターネット障害は、特に日本にとって大変なインパクトがあったと認識しています。様々な方が事象の分析や対策案の考案をされているのを見ていると、何か一つでも試してみたい気持ちになるものです。 提示される対策案の一つにRPKIが挙げられます。
リソースPKI(RPKI)は、 アドレス資源の割り振りや割り当てを証明するためのPKI(Public-Key Infrastructure:公開鍵基盤)で、 IPアドレスが正しく割り振られたものであるかどうかを確認できるほか、 BGPルータにおける誤ったインターネットの経路情報(Mis-Origination)を見つけるために使えます。
リソースPKI (RPKI; Resource Public Key Infrastructure) - JPNIC より
今回の事象に対する効果の程は議論の真っ最中であると認識していますが、まずは勉強しつつ簡単にできそうなところから手元で動かしてみようと思いました。
今回の目的
- 楽してローカル環境にRPKIのValidator (= RPKIで言うところのRelying Party) を構築する
- RPKIを使ってBGPの経路フィルタリングをやってみる
以下は次回以降の課題
- 検証環境のASやPrefixを認証基盤(= RPKIで言うところのCertificate Authority)に登録し、オレオレRPKIをやってみる
Relying Partyってなに
Relying parties run local RPKI validation tools, which are pointed at the different RPKI trust anchors and using rsync gather all cryptographic objects from the different repositories used for publication. This creates a local validated cache which can be used for making BGP routing decisions.
Wikipedia: Resource Public Key Infrastructure, Validationの項 より
訳すとRelying PartyにはRPKIのValidationツールを動作させ、BGPルーティングに影響するValidationキャッシュを生成する役目があるそうです。"Validationキャッシュ"とは多少抽象的な表現のような気もします。具体的にはROA (Route Origin Authorization) のようなデータのことを指すと理解しています。
OSSでもいくつかツールはあるようですが、今回はValidationツールとしてRIPE-NCCのRPKI-Validatorを試してみます。
RPKI-Validatorを動かす
前置きが長くなりました。RPKI-Validatorは大変親切なことにDockerfileを用意してくれているので、ビルドして実行するだけでよさそう。有り難し。
環境
rpki-validatorコンテナ起動
% git clone git@github.com:RIPE-NCC/rpki-validator.git % cd rpki-validator/rpki-validator-app/docker % wget http://central02.maven.org/maven2/net/ripe/rpki/rpki-validator-app/2.22/rpki-validator-app-2.22-dist.tar.gz % docker build -t rpki-validator:0.1 --no-cache . % docker run -id --name rpki --privileged=true -p 8080:8080 rpki-validator:0.1
ブラウザで http://127.0.0.1:8080 にアクセス。 ただしこのままではトラストアンカーが指定されておらず、すっからかんの状態で見えます。ので、本体にあるtalファイルをdockerディレクトリ以下に置き、コンテナにvolumeでくっつけてみました。
% pwd /YOUR/DIR/rpki-validator/rpki-validator-app/docker % mkdir tal % cp ../conf/tal/*.tal tal/ % docker run -id --name rpki --privileged=true -v `pwd`/tal:/opt/docker/conf/tal -p 8080:8080 rpki-validator:0.1
ブラウザで先程のページを更新してみると、いくつかのトラストアンカーが読み込み中になっています。 しばらくすると読み込みが完了し、なんとなくそれっぽく見えます。ROAsのタブを見るとROAがインストールされているのが分かります。
外部からRPKI-RTRでアクセス
RPKI-Validatorでは TCP 8282
でRTRを待ち受けるみたいです。
コンテナの外からアクセスできるように EXPOSE
して再度ビルドし、コンテナを起動します。
% emacs Dockerfile % git diff Dockerfile diff --git a/rpki-validator-app/docker/Dockerfile b/rpki-validator-app/docker/Dockerfile index 264d043..9073586 100644 --- a/rpki-validator-app/docker/Dockerfile +++ b/rpki-validator-app/docker/Dockerfile @@ -8,5 +8,6 @@ COPY *.conf conf/ COPY docker-startup.sh ./ EXPOSE 8080 +EXPOSE 8282 CMD /opt/docker/docker-startup.sh \ No newline at end of file % docker build -t rpki-validator:0.2 --no-cache . % docker run -id --name rpki --privileged=true -v `pwd`/tal:/opt/docker/conf/tal -p 8080:8080 -p 8282:8282 rpki-validator:0.2
BGPフィルタリングをやる前に、RPKI-RTRクライアントでちゃんと動いているか確認しておきたいです。RTRのクライアントツールをまず入れました。 github.com
% cd YOUR_DEV_DIR % git clone git@github.com:rtrlib/rtrlib.git % cd rtrlib % cmake -D CMAKE_BUILD_TYPE=Release . % make % make install % rtrclient -h Usage: rtrclient tcp [options] <host> <port> Options: -k Print information about SPKI updates. -p Print information about PFX updates. Examples: rtrclient tcp rpki-validator.realmv6.org 8282 rtrclient tcp -k -p rpki-validator.realmv6.org 8282
先程動かしたコンテナに対して実行します。RTRはまだちゃんと勉強してないので、現時点ではログは流し見するとして、ROA情報が取れてきているのが分かります。
% rtrclient tcp -p 127.0.0.1 8282 | head -n 20 Prefix Prefix Length ASN RTR-Socket changed connection status to: RTR_RESET, Mgr Status: RTR_MGR_CONNECTING RTR-Socket changed connection status to: RTR_SYNC, Mgr Status: RTR_MGR_CONNECTING RTR-Socket changed connection status to: RTR_FAST_RECONNECT, Mgr Status: RTR_MGR_CONNECTING RTR-Socket changed connection status to: RTR_CONNECTING, Mgr Status: RTR_MGR_CONNECTING RTR-Socket changed connection status to: RTR_RESET, Mgr Status: RTR_MGR_CONNECTING RTR-Socket changed connection status to: RTR_SYNC, Mgr Status: RTR_MGR_CONNECTING + 88.199.162.0 24 - 24 42923 + 89.107.224.0 24 - 24 43260 + 109.132.0.0 14 - 14 5432 + 77.138.12.0 22 - 22 12849 + 37.148.0.0 17 - 18 31549 + 185.176.33.0 24 - 24 64413 + 80.86.239.0 24 - 24 21104 + 193.48.137.0 24 - 24 1945 + 111.119.172.0 24 - 24 132165 + 195.130.64.0 18 - 24 5408 + 178.20.80.0 21 - 21 39449 + 193.54.45.0 24 - 24 781 + 185.38.172.0 23 - 23 205938
RPKI Validationによる経路フィルタリングをやってみる
ローカルで立てたRPKI-Validatorを使ってBGPの経路のフィルタリングをやってみます
今回はBGPデーモンにGoBGPを使いました。もちろんコンテナ化されており、簡単便利に使えます。 RPKI-Validatorのコンテナ1つと、2つのGoBGPコンテナを立ち上げ、図のような環境を作っていきます。
まずはコンテナネットワークを用意する。
% docker network create --driver=bridge --subnet=192.168.100.0/24 --gateway=192.168.100.1 bgpnet
続いてRPKI Validatorのコンテナを起動しておく。ブラウザでhttp://127.0.0.1:8080
にアクセスしてROAが見えることを確認。
## talファイルが必要なのでrpki-validatorのところに移動 % cd /YOUR/DIR/rpki-validator/rpki-validator-app/docker ## RPKI-Validatorコンテナを起動 % docker run -id --name rpki --privileged=true -v `pwd`/tal:/opt/docker/conf/tal -p 8080:8080 --net=bgpnet --ip=192.168.100.100 rpki-validator:0.2
GoBGPのコンテナを用意する。今回はgobgp1(AS65001)でRPKI Validationに基づく経路フィルタリングをやりました。
## 適当なディレクトリに移動 % cd YOUR_TEST_DIR ## gobgpのコンテナを入手 % docker pull osrg/gobgp ## gobgp1用のconfigファイルを作成する ## rpki-servers:にてRPKI-RTRの接続先情報を記載 ## policy-definitions:にてInvalidだった経路をRejectするようなポリシー"AS65002-IMPORT-RPKI"を書く % mkdir gobgp1 % emacs gobgp1/gobgp.yml global: config: as: 65001 router-id: 192.168.100.10 apply-policy: config: import-policy-list: ["AS65002-IMPORT-RPKI"] default-import-policy: accept-route rpki-servers: - config: address: 192.168.100.100 port: 8282 neighbors: - config: neighbor-address: 192.168.100.20 peer-as: 65002 policy-definitions: - name: AS65002-IMPORT-RPKI statements: - conditions: bgp-conditions: rpki-validation-result: "invalid" actions: route-disposition: reject-route ## gobgp2用のconfigファイルを作成 % mkdir gobgp2 % emacs gobgp2/gobgp.yml global: config: as: 65002 router-id: 192.168.100.20 neighbors: - config: neighbor-address: 192.168.100.10 peer-as: 65001
コンテナを起動していきます。
## GoBGPコンテナを起動 % docker run -id --name gobgp1 --privileged=true -v `pwd`/gobgp1:/etc/gobgp --net=bgpnet --ip=192.168.100.10 osrg/gobgp % docker run -id --name gobgp2 --privileged=true -v `pwd`/gobgp2:/etc/gobgp --net=bgpnet --ip=192.168.100.20 osrg/gobgp
コンテナ内のGoBGPを起動する。
% docker exec gobgp1 gobgpd -f /etc/gobgp/gobgp.yml & % docker exec gobgp2 gobgpd -f /etc/gobgp/gobgp.yml & ## Peer状態を確認 % docker exec gobgp1 gobgp neighbor Peer AS Up/Down State |#Received Accepted 192.168.100.20 65002 00:03:57 Establ | 0 0 % docker exec gobgp2 gobgp neighbor Peer AS Up/Down State |#Received Accepted 192.168.100.10 65001 00:04:22 Establ | 0 0
gobgp1にてRPKIの状態を確認する。
RPKI-Validatorに接続し、ROA情報を取得できてる。
## RPKI-Validatorとのコネクション状態を確認 % docker exec gobgp1 gobgp rpki server Session State Uptime #IPv4/IPv6 records 192.168.100.100:8282 Up 00:02:11 2621/166 # ROA情報を確認 % docker exec gobgp1 gobgp rpki table | head -n10 Network Maxlen AS Server 1.9.0.0/16 24 4788 192.168.100.100:8282 1.9.12.0/24 24 65037 192.168.100.100:8282 1.9.21.0/24 24 24514 192.168.100.100:8282 1.9.23.0/24 24 65120 192.168.100.100:8282 1.9.31.0/24 24 65077 192.168.100.100:8282 1.9.65.0/24 24 24514 192.168.100.100:8282 1.37.0.0/16 17 4775 192.168.100.100:8282 1.37.2.0/23 24 4775 192.168.100.100:8282 1.37.4.0/22 24 4775 192.168.100.100:8282
gobgp2から経路広報する。
今回はPrivate空間の10.0.0.0/8
と、gobgp rpki table
の一番上にエントリされている1.9.0.0/16
を広告してみます。後者は実際のリアルな経路なので試す環境によってはご注意ください。
% docker exec gobgp2 gobgp global rib add -a ipv4 10.0.0.0/8 origin igp % docker exec gobgp2 gobgp global rib add -a ipv4 1.9.0.0/16 origin igp
gobgp1でフィルタリング結果を確認。
1.9.0.0/16
は本来のOrigin ASであるAS4788からの広告ではもちろんないので、Validation結果はInvalidとなり、Global RIBにインストールされていません。
一方10.0.0.0/8
はValidation結果がUnknownであるため、今回のAS65001のポリシー上ではAcceptされ、Global RIBにインストールされました。
% docker exec gobgp1 gobgp neighbor 192.168.100.20 adj-in ID Network Next Hop AS_PATH Age Attrs I 0 1.9.0.0/16 192.168.100.20 65002 00:00:43 [{Origin: i}] N 0 10.0.0.0/8 192.168.100.20 65002 00:01:17 [{Origin: i}] % docker exec gobgp1 gobgp global rib Network Next Hop AS_PATH Age Attrs N*>10.0.0.0/8 192.168.100.20 65002 00:01:49 [{Origin: i}]
おわりに
dockerを使うことで結構簡単にRPKIを試すことができました。 もちろん、わざわざローカルにValidatorを立てなくても、インターネット上に公開されたROAキャッシュを使うこともできます。
ただし、パブリックなROAキャッシュを使う方法や、今回のように実際のNIRの認証情報を使う方法では、自分の好きなPrefixを登録し認証の試験をすることが難しいです。今回の内容を前段として、次はCertificate Authorityを検証環境に立てるところをやってみたいと思います。