はじめに
<バージョン>
Cisco IOS: 12.4(15)T1
Batfishとは、実機に接続せずにネットワーク機器の検証を行えるツールです。
今回は、Ciscoルータの設定を読み込ませて、access-listの設定を確認してみます。
Router#show running-config
~省略~
interface FastEthernet0/0
ip address 192.168.0.1 255.255.255.0
duplex auto
speed auto
!
interface FastEthernet0/1
ip address 192.168.1.1 255.255.255.0
ip access-group 100 out
duplex auto
speed auto
!
interface FastEthernet1/0
ip address 192.168.2.1 255.255.255.0
ip access-group 110 out
duplex auto
speed auto
!
interface FastEthernet1/1
no ip address
duplex auto
speed auto
shutdown
!
interface Vlan1
no ip address
shutdown
!
~省略~
!
access-list 100 permit tcp 192.168.0.0 0.0.0.255 192.168.1.0 0.0.0.255 eq 22
access-list 100 deny tcp 192.168.0.0 0.0.0.255 192.168.1.0 0.0.0.255 eq www
access-list 100 permit tcp 192.168.0.0 0.0.0.255 192.168.1.0 0.0.0.255 eq 443
access-list 110 deny tcp 192.168.0.0 0.0.0.255 192.168.2.0 0.0.0.255 eq www
access-list 110 permit tcp 192.168.0.0 0.0.0.255 192.168.2.0 0.0.0.255 eq 443
access-list 120 deny ip any any
access-list 130 permit ip any any
!
~省略~
end
1. 事前準備
まずはdockerコンテナ内にButfishを構築します。Docker イメージはbatfish/allinoneとbatfish/batfishの
2つがありますが、今回はJupyter Notebookで動作確認を行いたいのでallinone
の方を選択しました。
2. ディレクトリ構成
Jupyter Notebook内のディレクトリ構成は以下のようにしました。一番上の階層が、デフォルトで
/notebooks
になっており、/notebooks/networks
配下にサンプル用のconfigが格納されています。
今回は、自分で用意したconfigを入れたいので、/notebooks/my_network
を作成してCisco機器の
Config(Router.log)を格納しました。
/notebooks/
├ networks/ # デフォルトで存在
└ my_network/ # 以下、新規追加
└ configs/
└ Router.log
3. 動作確認
3-1. 初期設定
初期設定の内容は、Batfish documentation - Interacting with the Batfish serviceを参考にしました。
手順の通り、Jupyter Notebookに入力すればよいですが、SNAPSHOT_PATH
はConfigを入れたpathを指定しましょう。
import pandas as pd
from pybatfish.client.commands import *
from pybatfish.datamodel import *
from pybatfish.datamodel.answer import *
from pybatfish.datamodel.flow import *
from pybatfish.question import *
from pybatfish.question import bfq
NETWORK_NAME = "example_network" # 任意
SNAPSHOT_NAME = "example_snapshot" # 任意
SNAPSHOT_PATH = "/notebooks/my_network" # Configを入れたpathを指定
load_questions()
bf_session.host = 'localhost'
bf_set_network(NETWORK_NAME)
bf_init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True)
ここまで入れると、以下のようなerrorが出ることがあります。意味としては、
「configの読み取りには成功したが、一部読み取れない部分があった」ということなので、
どこにあるかを確認しましょう。
Your snapshot was successfully initialized but Batfish failed to fully recognized some lines in one or more input files.
以下のコマンドを入れると、Configで読み取れなった行がわかります。
結果を見ると、1行目のRouter#show running-config
が読み取れなかったようです。
Configに関する行ではなかったのでここではスルーします。
bfq.initIssues().answer().frame()
3-2. access-listの確認
今回は以下の通信を確認します。access-listの確認をする場合は、通過するinterfaceも指定する必要があります。
通過するinterfaceがわからない場合は、intefaceやroutingの情報から抽出するのがよいと思います。
id | 送信元IP | 宛先IP | 通過interface(in) | 通過interface(out) | 宛先ポート番号 | deny/permit |
---|---|---|---|---|---|---|
1 | 192.168.0.2 | 192.168.1.2 | Eth0/0 | Eth0/1 | 80 | deny |
2 | 192.168.0.2 | 192.168.2.2 | Eth0/0 | Eth1/0 | 443 | permit |
-
- HTTP(80)の通信がdenyになることを確認する
変数(flow/flow_in/flow_out)に必要な情報を記載し、結果を変数resultに格納します。
flow=HeaderConstraints(srcIps='192.168.0.2',dstIps='192.168.1.2',dstPorts=["80"])
flow_in="@enter(router[FastEthernet0/0])"
flow_out="@out(FastEthernet0/1)"
result = bfq.testFilters(headers=flow, startLocation=flow_in, filters=flow_out).answer().frame()
変数resultの中身は以下です。想定通り、access-list 100でdenyになっていることがわかります。
また、通信に関係のないaccess-listは表示されていません。
ちなみに、出力用変数.iloc[行番号]
(今回はresult.iloc[0])とすることで、表示結果が以下のように縦に見やすく表示されます。
Node router
Filter_Name 100
Flow start=router interface=FastEthernet0/0 [192.168.0.2:49152->192.168.1.2:80 TCP length=512]
Action DENY
Line_Content deny tcp 192.168.0.0 0.0.0.255 192.168.1.0 0.0.0.255 eq www
Trace - Matched line deny tcp 192.168.0.0 0.0.0.255 192.168.1.0 0.0.0.255 eq www
Name: 0, dtype: object
-
- HTTPS(443)の通信がpermitになることを確認する
flow=HeaderConstraints(srcIps='192.168.0.2',dstIps='192.168.2.2',dstPorts=["443"])
flow_in="@enter(router[FastEthernet0/0])"
flow_out="@out(FastEthernet1/0)"
result = bfq.testFilters(headers=flow, startLocation=flow_in, filters=flow_out).answer().frame()
変数resultの中身は以下です。想定通り、access-list 110でpermitになっていることがわかります。
result.iloc[0]の結果は以下です。
Node router
Filter_Name 110
Flow start=router interface=FastEthernet0/0 [192.168.0.2:49152->192.168.2.2:443 TCP length=512]
Action PERMIT
Line_Content permit tcp 192.168.0.0 0.0.0.255 192.168.2.0 0.0.0.255 eq 443
Trace - Matched line permit tcp 192.168.0.0 0.0.0.255 192.168.2.0 0.0.0.255 eq 443
Name: 0, dtype: object
参考(出力結果の表示設定)
pandasのDataFrameをJupyter Notebookで見る際に結果の全てが見えない場合があるので、
以下の設定を適宜入れるようにして下さい。
- 出力する列の制限を解除する(デフォルト:20列)
pd.set_option("display.max_columns", None)
- 出力する行の制限を解除する(デフォルト:60行)
pd.set_option("display.max_rows", None)
- 1列の表示文字数の制限を解除する(デフォルト:50文字)
pd.set_option("display.max_colwidth", None)
まとめ
今回紹介したCisco機器の検証以外にも、Batfishは様々なベンダー機器に対応しているので、
興味がある方はBatfishに読み込ませてみるとよいと思います。(リンクは以下)
Batfish documentation - Supported Network Device and Operating System List
なお、Batfishの結果はDataFrameで出力されるので、結果の抽出にはpandasの知識が必要です。
参考記事
pandas 1.3.3 documentation - pandas.set_option
Batfish documentation - Interacting with the Batfish service
Batfish documentation - Datamodel classes(HeaderConstraints)
Batfish documentation - Access-lists and firewall rules
Batfish documentation - Analyzing ACLs and firewall rules with Batfish
Batfish documentation - Supported Network Device and Operating System List