これは Batfish Advent Calendar 2018 の1日目の記事です。
先日、Ansible と Batfish を使ったネットワークコンフィグの事前検証についてのウェビナーがあり、Ansible 公式サイトに動画も公開されました。 この記事では、動画の内容のまとめと補足をしたいと思います。
なお、Batfish とは、ネットワークコンフィグの検証ツールです。概要については以下の記事を参照してください。
[Batfish] ネットワーク機器のコンフィグを読み込んでルーティングなどの様々な検証ができるツール「Batfish」の紹介 - てくなべ (tekunabe)
ソース
動画の内容の詳細については以下のソースを参照してください。
動画
スライド (PDF)
https://www.ansible.com/hubfs/2018_Content/Ansible-Intentionet-Webinar-Slides.pdf
デモ Playbook 一式
https://github.com/batfish/ansible-demo
以下、内容
■ Part I Network validation today
(P6) Batfish とは
(P7) なぜこのようなツールが必要か?
- 自動化がスケールラビリティやスピードが得られる
- しかし、ちょっとしたミスでも影響が大きい
- そのため、ワークフローには自動化された効果的な変更の検証が重要
(P8) 効果的な変更の検証とは?
- プロアクティブ
- 事前、自動的な検証
- 包括的
- 商用環境スケール、すべての障害時経路の検証
(P9-) こんにちの検証方法の比較
テキスト解析
- コンフィグのテキストをチェックする
- 確認できる例
- NTPサーバー、DNSサーバーなどが設定さているか
- 事前検証可能か: ○
- 包括的か: ×
- ネットワークの振る舞いを検証できない
エミュレーション
- VM などによるネットワーク環境のシミュレーション環境を準備して行うチェック
- 確認できる例
- BGPセッションが確率されているか、
- テストクライアントが DNS サーバーに到達できるか
- リンク障害時にどうなるか
- 事前検証可能か: ○
- 包括的か: ×
- 商用環境スケールにならない、すべての障害経路はテストできない
Operational State Analysis
- 実環境での確認
- 確認できる例
- BGPセッションが確率されているか
- テストクライアントが DNS サーバーに到達できるか
- traceroute は想定通りか
- 事前検証可能か: ×
- 包括的か: ×
- すべての障害経路はテストできない
事前検証可能、かつ包括的な検証方法がなかっため、新しいアプローチが必要。
モデルベース検証
- Batfish で可能なタイプの検証アプローチ
- 確認できる例
- サブネットAからBへのフローはあるか
- すべてのクライアントが DNS サーバーに到達できるか
- 特定のサービスを中断させるリンク障害はあるか
- 事前検証可能か: ○
- 包括的か: ○
■ Part II Comprehensive pre-commit validation with Batfish
(P16) Batfish とは?
内部処理
- Cisco、Juniper、Arista、PaloAlto などの機器のコンフィグを読み込み
- ベンダーニュートラルなコンフィグモデルを生成
- ルーティングモデルを生成
- ネットワークの振る舞いのモデルを生成
なにをテストできるか
- 例
- すべての機器がパスワードで保護されていること
- 通信不可能な箇所
- 可用性を低下させる機器障害
(P18) Batfish Network Policies
Security
- 通信できてはいけないトラフィックがないこと
- 暗号化されていること
Reliability
- 単一リンク障害で停止しないこと
Compliance
- 機器へのアクセスが安全な通信のみに制限されていること
- 未定義の設定がないこと
(P20) Batfish の活用方法
- ネットワーク CI/CD パイプラインへの組み込み
- シナリオテスト
■ Part III Demo of Ansible + Batfish
(P22-) デモシナリオ
- シナリオ1
- DC ファブリックに新たなリーフスイッチを追加する
- シナリオ2
- 新しいサービス向けのファイアウォールに許可ポリシーを設定する
(P23) シナリオ1: リーフスイッチの追加
AS番号 65003 を利用するリーフスイッチ leaf-03 を追加する。
流れ
- ユーザーからの入力
- リーフスイッチの名前
- POD ID
- BGP AS番号
- Jinja2 テンプレートによるコンフィグ生成
- git コミット
- Batfish による検証
- NTPサーバーの設定、未定義の参照がないか、BGP設定が正しいかなど
- 検証結果を S3 に記録
- Slack へ通知
デモ
(詳細は動画の 20:35 頃からご覧ください)
最初の実行
意図的に、すでに利用されている AS番号(65002)を新しいリーフスイッチで利用しようとしたため、Badfish が FAIL という結果を返す。
実行コマンド
ansible-playbook -i playbooks/inventory playbooks/master.yml --tags "create, git, s3, slack"
実行する Playbook (playbooks/master.yml)
https://github.com/batfish/ansible-demo/blob/master/playbooks/master.yml
2回目の実行
AS 番号を修正(65003
)して OK に。
シナリオ1 のまとめ
入力された AS 番号の間違いを Batfish で検出できた。
(P27) シナリオ2: サービスの有効化
シナリオ1 で追加したリーフスイッチ leaf-03
配下のホスト向けに、TCP/80
を許可するポリシーを追加する。
Provably safe ACL and firewall rule changes と同様の
検証。
流れ
- ユーザーからの入力 (シナリオ1と異なり、入力パラメータはコンフィグ生成ではなく、検証目的で利用される)
- 対象の FW はどこか
- 検証したいポリシー(送信元IP、宛先IP、宛先ポート)
- Jinja2 テンプレートによるコンフィグ生成
- git コミット
- Batfish による検証
- シナリオ1と同様の検証に加えて、今回の変更固有の検証
- すでに設定済みのポリシーでないこと
- 仕様が満たされること
- 既存のフローに意図しない影響がないこと
- シナリオ1と同様の検証に加えて、今回の変更固有の検証
- 検証結果を S3 に記録
- Slack へ通知
デモ
(詳細は動画の 24:40 頃からご覧ください)
最初の実行
permit tcp any 10.1.5.0 0.0.0.63 eq 80
を追加した candidate config に対して、意図通りのポリシーになるかチェックするために以下のパラメーターを入力(最初の実行と同じ)
- 送信元アドレス:
0.0.0.0/0
- 宛先アドレス:
10.1.5.0/27
- 宛先ポート:
TCP/80
検証1: すでに設定済みのポリシーでないこと (OK)
検証2: 要件が満たされること (OK)
検証3: 既存のフローに意図しない影響がないこと (NG)
入力した 10.1.5.0/27
に対して、candidate config の 10.1.5.0 0.0.0.63 (/26)
の範囲が広すぎるため、エラーとなる。
例として、10.1.5.32 TCP/80
( 10.1.5.0/27
の範囲外) へのフローが、意図せず 許可されることが示される。
検出の仕組み
ポイントは playbooks/validate_acl_change.yml の question3に対応するタスク 。
- name: "Checking: {{ question3 }}" batfish_searchfilters: name: "{{ bf_base_snapshot }}" reference_snapshot: "{{ bf_candidate_snapshot }}" network: "{{ bf_network }}" filters: "{{ filters }}" nodes: "{{ nodes }}" source_ips: "{{ source_ips }}" destination_ips: "{{ destination_ips }}" ip_protocols: "{{ ip_protocols }}" destination_ports: "{{ destination_ports }}" invert_search: yes register: answer3 tags: - always
ACLエントリ追加前のコンフィグのスナップショットと、追加後の candidate config の違いを抽出しています。
抽出する条件は、ユーザーによって入力されたポリシー(送信元IP、宛先IPなど)の範囲外(invert_search: yes
)です。
これにより、意図しないポリシー(今回の場合、広すぎるプレフィックスによる許可)検出できることになります。
なお、
batfish_searchfilters
モジュールと、内部で呼び出されている [pybatfish](https://github.com/batfish/pybatfish)
の主なパラメータの対応は以下の通りです。
項目 | batfish_searchfilters | pybatfish |
---|---|---|
検証スナップショット名 | name |
pybatfish.client.commands.bf_get_answer の snapshot |
比較対象スナップショット名 | reference_snapshot |
pybatfish.client.commands.bf_get_answer の reference_snapshot |
入力ポリシーの範囲外を検証するかどうか | invert_search |
pybatfish.question.bfq.searchfilters の invertSearch |
宛先IPアドレス | destination_ips |
pybatfish.datamodel.flow.HeaderConstraints の dstIps |
実行コマンド
ansible-playbook -i playbooks/inventory playbooks/maste_acl.yml --tags "create, git, s3, slack"
実行する Playbook (playbooks/master_acl.yml)
https://github.com/batfish/ansible-demo/blob/master/playbooks/master_acl.yml
2回目の実行
ワイルドカードマスクを修正した condidate config permit tcp any 10.1.5.0 0.0.0.31 eq 80
に対して、意図通りのポリシーになるかチェックするために以下のパラメーターを入力(最初の実行と同じ)
- 送信元アドレス:
0.0.0.0/0
- 宛先アドレス:
10.1.5.0/27
- 宛先ポート:
TCP/80
(再)検証2: 仕様が満たされること (OK)
(再)検証3 :既存のフローに意図しない影響がないこと (OK)
正しくワイルドカードマスクに修正され、要件を満たし、意図しない影響もないため OK になった。
シナリオ2 のまとめ
部分的に正しいかったような、とても見つけにくいエラーを Batfish で検出できた。
■ (P30) まとめ
- 自動化は効果的な検証なしではリスキー
- Batfish は、包括的な事前検証が可能