- 2017 年版
- 2018 年版
- 2019 年版
- 2020 年版 - 1枚目
- 2020 年版 - 2枚目
- 2021 年版 - 1枚目
- 2021 年版 - 2枚目
- 2022 年版
- 2023 年版
- 2024 年版
どんな人向けの記事?
この記事は以下のような方を想定しています。
- ネットワーク関連の業務を担当されている方
- Batfish を使って効率良く、業務を進めたい方
- 「プログラミングせずに済ませたい」という方!
はじめに
Batfish の利用には Python コードを書くのが一般的ですが、bfqry というツールを使うことでプログラミングせずに Batfish を利用できます。 この記事では Batfish + bfqry を組み合わせる方法を説明します。
Batfish とは
Batfish は Java で書かれた OSS です。 Batfish を使うと「ネットワーク機器のコンフィグから、設定情報を抽出したり、妥当性を確認する」ということが可能です。 公式サイトには Batfish 自身の説明として以下の記載があります。
Batfish is a network validation tool that provides correctness guarantees for security, reliability, and compliance by analyzing the configuration of network devices. It builds complete models of network behavior from device configurations and finds violations of network policies (built-in, user-defined, and best-practices).
Batfish は様々なメーカーの製品に対応しており、サポート対象の一覧は Supported Network Device and Operating System List に掲載されています。
- A10 Networks
- Arista
- AWS (VPCs, Network ACLs, VPN GW, NAT GW, Internet GW, Security Groups, etc…)
- Cisco (All Cisco NX-OS, IOS, IOS-XE, IOS-XR and ASA devices)
- Check Point
- Cumulus
- F5 BIG-IP
- Fortinet
- Free-Range Routing (FRR)
- iptables (on hosts)
- Juniper (All JunOS platforms: MX, EX, QFX, SRX, T-series, PTX)
- Palo Alto Networks
- SONiC
Batfish のメリット・デメリット
Batfish にはメリットもあればデメリットもあります。 各々の点について簡単に触れます。
メリット
Batfish には以下のようなメリットがあります。
- 「コンフィグだけを対象に処理を行う」という仕組み上、実機へのアクセスが不要 (=安全)
- 過去であっても、コンフィグさえあれば処理が可能 (=任意の時点を対象に出来る)
- L3 以上の処理、特にルーティングの計算は得意
- 実機では再現し辛い構成を論理的に作成する機能が豊富 (=ホストを JSON で再現する、BGP のアトリビュートをファイルから注入する、等)
- マルチベンダー対応である
構成管理ツールを利用する場合、通常は「実機へアクセス出来ること」が利用の大前提になります。 ですが Batfish は「コンフィグさえ、あれば動作する」為、Batfish を本番環境へ接続する必要はありません。 本番環境から隔離された、普段のオフィス内から安全に Batfish を実行することが出来ます。
Batfish は任意のタイミングで取得したコンフィグを対象に出来ます。 1 年前のコンフィグであっても、まだ本番環境には存在しない「机上で作成した未来のコンフィグ」であっても対象にすることが出来ます。 その為、工事前後のコンフィグを用意して「追加したコンフィグが妥当であるか?」の確認に利用することも出来ます。
また、Layer3 以上の処理、特にルーティングの計算は非常に得意です。 各種のルーティングプロトコルに対応しており、「どの機器が・どのようなルーティングテーブルになるはずか?」を計算させることが出来ます。
一般的に BGP のテストを実施する場合、「任意のアトリビュートが付与された受信経路」の再現が手間になる場合があります。 Batfish の External BGP announcements という機能を利用することで JSON ファイルで BGP 経路を生成することが出来、任意の経路を簡単に再現出来ます。
デメリット
勿論、万能のツールでは無く、下記のような制限・デメリットもあります。
- OS バージョンを意識した処理は出来ない (=「OS バージョンによって振る舞いが変わる」というケースには対応が難しい)
- 対応していないコンフィグ構文も多い
- パフォーマンステストは実施出来ない
- L2 以下の処理は苦手
- (コンフィグ以外に)「show コマンドの結果などを追加して情報の精度を上げる」といった仕組みは存在しない。 あくまでコンフィグしか処理対象に出来ない
Batfish で計算を行わせる際、対象コンフィグの OS バージョンは意識しません。 例えば「OS バージョンによって振る舞いの変わる処理」があったとしても、「Batfish のコードが再現している振る舞い」しか行いません。 その為、バージョンによって振る舞いが変わるような繊細な挙動の確認には、Batfish は向きません。
「Batfish はコンフィグだけあれば動作する」とは言っても、ありとあらゆるメーカーの・全てのコンフィグ構文に対応している… とはお世辞にも言えない状況です。 Batfish を利用する場合は「Batfish が対応しているコンフィグ構文」「対応していないコンフィグ構文」を理解した上で「Batfish が向いている、使える」というシチュエーションに限定して利用する方が安全だと思います。
また、あくまで「コンフィグを計算している」という仕組みであり、ハードウェアは存在していない為、パフォーマンステストも実施出来ません。
Batfish の利用方法
Batfish はクライアント・サーバモデルで動作します。 そのため、Batfish 用のクライアントとサーバを用意する必要があります。
Batfish サーバ
上述の通り、Batfish は Java で書かれており、勿論 JAVA アプリケーションとして動作させることが可能です。 ですが How do I get started? に書かれているようにサーバ側は Docker (Podman) コンテナとして動作させるのが簡単です。 Batfish のコンテナには以下があります。
名称 | 内容 |
---|---|
batfish/batfish | Batfish 本体のみ |
batfish/allinone | Batfish 本体 + Jupyter Notebook |
後述しますが、Batfish を利用するには「Python のソースコードを書く」必要があります。 はじめて Batfish を利用する際は Python コードと格闘することになるかもしれませんので Jupyter Notebook を含む batfish/allinone イメージを使ってトライ&エラーするのが簡単かも知れません。 本番運用するのであれば Jupyter Notebook は不要になりますので batfish/batfish を利用します。
Batfish の GitHub に記載されていますが、batfish/allinone コンテナを開始するには以下のように実行します。 Batfish 自体は v1 ポート (デフォルト:TCP/9997) と v2 ポート (デフォルト:TCP/9996) という概念がありますが、v1 ポートは古いバージョンでしか利用されません。
docker pull batfish/allinone
docker run --name batfish -v batfish-data:/data -p 8888:8888 -p 9997:9997 -p 9996:9996 batfish/allinone
Batfish クライアント
Batfish を利用するには pybatfish を使って Python コードを書くのが一般的です。 Batfish 本体は Java で書かれていますが、クライアントは Python 版しかリリースされていないようです。
Batfish への問い合わせには Question を使う
Batfish クライアントから Batfish サーバへ計算処理を依頼するには Batfish Questions を用います。 Batfish Questions には以下のカテゴリーがあり、各々のカテゴリー内には幾つかの Question が存在します。
- Configuration Properties
- Topology
- Routing Protocol Sessions and Policies
- Routing and Forwarding Tables
- Packet Forwarding
- Access-lists and firewall rules
- Snapshot Input
- IPSec Tunnels
- VXLAN and EVPN
- Resolving Specifiers
- Differential Questions
例えば「インターフェイスの設定情報を取得したい」場合、Configuration Properties カテゴリーに含まれる Interface Properties Question を利用します。
Batfish を利用する際のディレクトリ・ファイル構造
Batfish を利用する場合、対象のディレクトリ・ファイルは以下の構造にします。Batfish の処理対象とするネットワーク機器のコンフィグは configs
というディレクトリ配下に保存します。 このディレクトリ名は Batfish にハードコーディングされている為、変更することは出来ません。
simple
└── configs
├── dev1.txt
├── dev2.txt
├── dev3.txt
├── dev4.txt
└── dev5.txt
Batfish を簡単に利用できる「bfqry」
Batfish クライアントは「Python コードで pybatfish を import し、Batfish Question(s) を実行する」のが一般的な方法です。 つまり「Batfish を利用するには Python のプログラミングスキルが必要」になってしまいます。
ですが、bfqry というツールを使うことでプログラミングを行うことなく、Batfish を利用することが出来ます。
bfqry のインストール
bfqry のパッケージは pypi で公開されており、CLI ツールとして利用することが出来ます。 他の Python パッケージと同様に pip でインストールすることが出来ます。
python -m pip install bfqry
bfqry の初期設定
bfqry の設定ファイルは以下、いずれかに配置します。 上にある程、優先度が高い方から採用されます。
優先順位 | ファイルパス |
---|---|
1 |
bfqry と同じディレクトリにある settings.ini
|
2 | ~/.config/bfqry/settings.ini |
3 | ~/.settings.ini |
設定ファイルの記載例は以下の通りです。
batfish=10.0.0.1
port1=9997
port2=9996
timeout=5.0
https=false
insecure=true
各々の項目は以下の意味を持ちます。
項目 | デフォルト値 | 説明 |
---|---|---|
batfish | 127.0.0.1 | Batfish サーバの名前 / IP アドレス |
port1 | 9996 | v1 ポート。 古いバージョンの Batfish で利用されるが、現在は利用されていない |
port2 | 9997 | v2 ポート。 Batfish クライアント / サーバ間の通信で利用される |
timeout | 5.0 | Batfish サーバ接続確立時のタイムアウト時間 (秒) |
https | False | Batfish サーバへの接続時、HTTPS の利用有無 |
insecure | False |
https フラグが True の場合にサーバ証明書の妥当性を確認するか、否か |
bfqry の使い方
bfqry を利用するには実行したい Question をツールのサブコマンドとして指定します。 以下は bfqry のヘルプ表示です。
# bfqry
usage: bfqry {command} ...
bfqry (Batfish Query Utility) 2024.12.01
commands:
{command}
aclsearch
Finds flows for which a filter takes a particular behavior.
acltest Returns how a flow is processed by a filter (ACLs, firewall rules).
aclunreach
Returns unreachable lines in filters (ACLs and firewall rules).
bgpedge Returns BGP adjacencies.
bgprib Returns routes in the BGP RIB.
bireach Searches for successfully delivered flows that can successfully receive a response.
bitrace Traces the path(s) for the specified flow, along with path(s) for reverse flows.
eigrpedge
EIGRP Edges
hsrp Returns configuration settings of HSRP groups.
interface
Returns configuration settings of interfaces.
ip Returns where IP addresses are attached in the network.
l3edge Lists all Layer 3 edges in the network.
loop Detects forwarding loops.
lpm Returns routing tables.
ospfedge Lists all OSPF adjacencies in the network.
parse Displays file parse status.
prefix Traces prefix propagation through the network.
reach Finds flows that match the specified path and header space conditions.
route Returns routing tables.
trace Traces the path(s) for the specified flow.
vlan Returns configuration settings of switched VLANs.
vrrp Returns configuration settings of VRRP groups.
前述の「Batfish を利用する際のディレクトリ・ファイル構造」を踏まえ、ip サブコマンドを実行するには以下のように実行します。 --base
は必須のオプションであり、configs
を配置した 親ディレクトリ を指定します。
bfqry ip --base simple/
bfqry の実行例
以下は bfqry の実行例です。
parse サブコマンド
parse サブコマンドは内部的に Snapshot Input File Parse Status Question を実行します。 Batfish は処理対象ファイルの特徴から「どのメーカーの・どの OS 種別なのか」を見分けているようです。 parse サブコマンドの File_Format
出力から「対象のコンフィグファイルがどの OS 形式として Batfish に処理されているのか?」などが分かります。
# bfqry parse --base simple/
Nodes File_Name Status File_Format Version
dev1 configs/dev1.txt PASSED CISCO_IOS 16.12.1
dev2 configs/dev2.txt PASSED CISCO_IOS 16.12.2
dev3 configs/dev3.txt PASSED CISCO_IOS 16.12.3
dev4 configs/dev4.txt PASSED CISCO_IOS 16.12.4
dev5 configs/dev5.txt PASSED CISCO_IOS ?
interface サブコマンド
interface サブコマンドは内部的に Interface Properties Question を実行します。 オプションを指定しない場合、プライマリアドレスや Description、VRF などを表示します。
# bfqry interface --base interface/
Interface Primary_Address Description VRF
dev11[Loopback0] 10.0.0.11/16 <11> default
dev12[Serial0/0] 10.0.0.12/16 <12> default
dev13[BRI0/1/0:0] 10.0.0.13/16 <13> default
dev14[BRI0/1/1:0] 10.0.0.14/16 <14> default
dev15[GigabitEthernet0/1] None <14> default
dev15[GigabitEthernet0/2] None <14> default
dev15[Port-channel15] None <14> default
dev15[Vlan15] 10.0.0.15/16 <14> default
dev16[Ethernet0/0] 10.0.0.16/16 <16> default
dev17[FastEthernet0/0] 10.0.0.17/16 <17> default
dev18[GigabitEthernet0/0] 10.0.0.18/16 <18> default
dev19[TwoGigabitEthernet0/0] 10.0.0.19/16 <19> default
dev21[TenGigabitEthernet0/0] 10.0.0.21/16 <21> default
dev22[TwentyFiveGigE0/0] 10.0.0.22/16 <22> default
dev23[FortyGigabitEthernet0/0] 10.0.0.23/16 <23> default
dev25[HundredGigabitEthernet0/0] 10.0.0.25/16 <25> default
interface サブコマンドには --column
オプションがあります。 このオプションを指定することで表示する内容を変更出来ます。
# bfqry interface --help
usage: bfqry interface [-h] -b BASE [--batfish BATFISH] [--port1 PORT1] [--port2 PORT2] [--timeout TIMEOUT] [--https] [--insecure]
[--nocache] [--log {debug,info,warning,error,ciritical}] [--excel EXCEL] [--node [NODE ...]]
[--column {acl,all,basic,hsrp,ip,portchannel,speed,state,stp,vlan}] [--wounit]
--column speed
を指定した場合、実行例は以下の通りです。 Speed や Bandwidth の値を表示します。 但し、幾つかのインターフェイス種別に関しては「想定と異なる値が表示されている」ことが分かります。
# bfqry interface --base interface/ --column speed
Interface Primary_Address Speed Bandwidth
dev11[Loopback0] 10.0.0.11/16 (None) 8G
dev12[Serial0/0] 10.0.0.12/16 (None) 1T
dev13[BRI0/1/0:0] 10.0.0.13/16 (None) 1T
dev14[BRI0/1/1:0] 10.0.0.14/16 (None) 1T
dev15[GigabitEthernet0/1] None 1G 1G
dev15[GigabitEthernet0/2] None 1G 1G
dev15[Port-channel15] None (None) 2G
dev15[Vlan15] 10.0.0.15/16 (None) 1G
dev16[Ethernet0/0] 10.0.0.16/16 10M 10M
dev17[FastEthernet0/0] 10.0.0.17/16 100M 100M
dev18[GigabitEthernet0/0] 10.0.0.18/16 1G 1G
dev19[TwoGigabitEthernet0/0] 10.0.0.19/16 2G 2G
dev21[TenGigabitEthernet0/0] 10.0.0.21/16 10G 10G
dev22[TwentyFiveGigE0/0] 10.0.0.22/16 25G 25G
dev23[FortyGigabitEthernet0/0] 10.0.0.23/16 (None) 1T
dev25[HundredGigabitEthernet0/0] 10.0.0.25/16 (None) 1T
ip サブコマンド
ip サブコマンドは内部的に IP Owners Question を実行します。 実行例は以下の通りです。
# bfqry ip --base ip/
Node VRF IP Mask Interface Active
dev1 default 10.0.0.1 24 Loopback0 True
dev1 default 10.0.0.99 24 Loopback0 True
dev2 default 10.0.0.2 24 Loopback0 True
dev2 default 10.0.0.92 24 Loopback0 True
dev3 default 10.0.0.3 24 Loopback0 True
dev3 default 10.0.0.93 24 Loopback0 True
dev4 default 10.0.0.4 24 Loopback0 True
dev4 default 10.0.0.99 24 Loopback0 True
dev5 A 10.0.0.5 24 Loopback0 True
dev5 A 10.0.0.99 24 Loopback0 True
--duplicate
オプションを指定すると「重複している IP アドレス」を表示することが出来ます。
# bfqry ip --base ip/ --duplicate
Node VRF IP Mask Interface Active
dev1 default 10.0.0.99 24 Loopback0 True
dev4 default 10.0.0.99 24 Loopback0 True
dev5 A 10.0.0.99 24 Loopback0 True
route サブコマンド
route サブコマンドは内部的に Routes Question を実行します。 実行例は以下の通りです。
# bfqry route --base ospf/ --node dev1
Node Network Next_Hop_IP Protocol Metric Admin_Distance
dev1 10.12.0.0/24 AUTO/NONE(-1l) connected 0 0
dev1 10.12.0.1/32 AUTO/NONE(-1l) local 0 0
dev1 10.23.0.0/24 10.12.0.2 ospf 2 110
dev1 10.34.0.0/24 10.12.0.2 ospf 3 110
dev1 10.45.0.0/24 10.12.0.2 ospf 4 110
dev1 10.99.0.0/24 AUTO/NONE(-1l) connected 0 0
dev1 10.99.0.1/32 AUTO/NONE(-1l) local 0 0
dev1 10.99.0.2/32 10.12.0.2 ospf 2 110
dev1 10.99.0.3/32 10.12.0.2 ospf 3 110
dev1 10.99.0.4/32 10.12.0.2 ospf 4 110
dev1 10.99.0.5/32 10.12.0.2 ospf 5 110
trace サブコマンド
trace サブコマンドは内部的に Traceroute Question を実行します。 以下のように実行することで擬似的に Traceroute を実行出来ます。 「Traceroute」といってもアプリケーションレイヤーも任意に指定することが出来ます。 下記の例では宛先に DNS (UDP/53) を指定しています。 下記は成功例ですが、失敗する場合は「どこで・どうった理由で失敗しているのか」が表示されます。
# bfqry trace --base simple/ --node dev1 --saddr 10.12.0.1 --daddr 10.45.0.5 --protocol udp --dport 53
============================================================ 1/1 Flow
start=dev1 [10.12.0.1:49152->10.45.0.5:53 UDP]
-------------------------------------------------- 1/1 Trace
ACCEPTED
1. node: dev1
ORIGINATED(default)
FORWARDED(Forwarded out interface: GigabitEthernet0/1 with resolved next-hop IP: 10.12.0.2, Routes: [static (Network: 0.0.0.0/0, Next Hop: ip 10.12.0.2)])
TRANSMITTED(GigabitEthernet0/1)
2. node: dev2
RECEIVED(GigabitEthernet0/0)
FORWARDED(Forwarded out interface: GigabitEthernet0/1 with resolved next-hop IP: 10.23.0.3, Routes: [static (Network: 0.0.0.0/0, Next Hop: ip 10.23.0.3)])
TRANSMITTED(GigabitEthernet0/1)
3. node: dev3
RECEIVED(GigabitEthernet0/0)
FORWARDED(Forwarded out interface: GigabitEthernet0/1 with resolved next-hop IP: 10.34.0.4, Routes: [static (Network: 10.45.0.0/24, Next Hop: ip 10.34.0.4)])
TRANSMITTED(GigabitEthernet0/1)
4. node: dev4
RECEIVED(GigabitEthernet0/0)
FORWARDED(Forwarded out interface: GigabitEthernet0/1, Routes: [connected (Network: 10.45.0.0/24, Next Hop: interface GigabitEthernet0/1)])
TRANSMITTED(GigabitEthernet0/1)
5. node: dev5
RECEIVED(GigabitEthernet0/0)
ACCEPTED(GigabitEthernet0/0)
bitrace サブコマンド
bitrace サブコマンドは内部的に Bi-directional Traceroute Question を実行します。 trace サブコマンドと異なり、往復をテストすることが出来ます。
# bfqry bitrace --base simple/ --node dev1 --saddr 10.12.0.1 --daddr 10.45.0.5 --protocol udp --dport 53
============================================================ 1/1 Flow(s)
start=dev1 [10.12.0.1:49152->10.45.0.5:53 UDP]
start=dev5 [10.45.0.5:53->10.12.0.1:49152 UDP]
-------------------------------------------------- 1 Forward Trace(s)
---------------------------------------- 1/1 Forward Trace
ACCEPTED
1. node: dev1
ORIGINATED(default)
FORWARDED(Forwarded out interface: GigabitEthernet0/1 with resolved next-hop IP: 10.12.0.2, Routes: [static (Network: 0.0.0.0/0, Next Hop: ip 10.12.0.2)])
TRANSMITTED(GigabitEthernet0/1)
2. node: dev2
RECEIVED(GigabitEthernet0/0)
FORWARDED(Forwarded out interface: GigabitEthernet0/1 with resolved next-hop IP: 10.23.0.3, Routes: [static (Network: 0.0.0.0/0, Next Hop: ip 10.23.0.3)])
TRANSMITTED(GigabitEthernet0/1)
3. node: dev3
RECEIVED(GigabitEthernet0/0)
FORWARDED(Forwarded out interface: GigabitEthernet0/1 with resolved next-hop IP: 10.34.0.4, Routes: [static (Network: 10.45.0.0/24, Next Hop: ip 10.34.0.4)])
TRANSMITTED(GigabitEthernet0/1)
4. node: dev4
RECEIVED(GigabitEthernet0/0)
FORWARDED(Forwarded out interface: GigabitEthernet0/1, Routes: [connected (Network: 10.45.0.0/24, Next Hop: interface GigabitEthernet0/1)])
TRANSMITTED(GigabitEthernet0/1)
5. node: dev5
RECEIVED(GigabitEthernet0/0)
ACCEPTED(GigabitEthernet0/0)
-------------------------------------------------- 1 Reverse Trace(s)
---------------------------------------- 1/1 Reverse Trace
ACCEPTED
1. node: dev5
ORIGINATED(default)
FORWARDED(Forwarded out interface: GigabitEthernet0/0 with resolved next-hop IP: 10.45.0.4, Routes: [static (Network: 0.0.0.0/0, Next Hop: ip 10.45.0.4)])
TRANSMITTED(GigabitEthernet0/0)
2. node: dev4
RECEIVED(GigabitEthernet0/1)
FORWARDED(Forwarded out interface: GigabitEthernet0/0 with resolved next-hop IP: 10.34.0.3, Routes: [static (Network: 0.0.0.0/0, Next Hop: ip 10.34.0.3)])
TRANSMITTED(GigabitEthernet0/0)
3. node: dev3
RECEIVED(GigabitEthernet0/1)
FORWARDED(Forwarded out interface: GigabitEthernet0/0 with resolved next-hop IP: 10.23.0.2, Routes: [static (Network: 10.12.0.0/24, Next Hop: ip 10.23.0.2)])
TRANSMITTED(GigabitEthernet0/0)
4. node: dev2
RECEIVED(GigabitEthernet0/1)
FORWARDED(Forwarded out interface: GigabitEthernet0/0, Routes: [connected (Network: 10.12.0.0/24, Next Hop: interface GigabitEthernet0/0)])
TRANSMITTED(GigabitEthernet0/0)
5. node: dev1
RECEIVED(GigabitEthernet0/1)
ACCEPTED(GigabitEthernet0/1)
まとめ
Batfish を利用することで手軽に・安全に、ネットワーク機器のコンフィグから情報抽出や妥当性確認を行うことが出来ます。 「Batfish は便利そうだけど、Python コードを書くのはチョット…」という方は是非、bfqry の利用をご検討頂ければと思います。
それでは皆様、素晴らしい年末年始をお過ごしください!