この記事は、Ansible 3 Advent Calendar 2019の22日目の記事です。
昨日分は、よこちさんのNetBoxに関する記事でした。
Ansibleを構成管理ツールとして使う場合、特にTower/AWXを使わない場合、インベントリをAnsibleで管理するか…というのは悩ましい点ですよね。NetBoxも一つの解にできそうですね。
さて、私の分は「またFortigate」です。すみません。
Ansibleのネットワーク系の課題をやると、A10/BIG-IPさんの課題でよく例に出る「ロードバランシング機能」があります。
実は、Fortigateでもロードバランシング機能が存在します。それをAnsibleで利用するまでの流れを記載させていただきます。
Ansible関連の実践記事一覧はこちら。
目的
fortigateでロードバランシング機能を使うためのPlaybookの書き方や、<your_own_value>を明らかにするため
最初に結論
- AnsibleでFortigateのLB機能を一通り設定することができた
- ヘルスチェックなども問題なく動作することが分かった
- 手動での動作確認を、assertなどで実施できるよう学習を進める
Ansible/Fortigate環境
- ansible: 2.9.0
- python: 3.6.8
- Fortios: 6.0.8
- コネクションプラグイン: httpapi
構成図
このような感じの構成で確認を行いました
ロードバランサー的な用語でいうと、「ワンアーム構成」です。
(自宅のネットワーク環境の構成上、これ以外つらいんです。直さねば)

前提条件
- Webサーバはすでに構築されている前提
- 各々の index.htmlにはホストを示す異なるコンテンツを配備
- Fortigateは、シングル構成、DMZのIFにIPが付与されている程度
- 前回作成したHA環境は今回は使っていません。
- クライアント(Ansibleホスト)はVIPで提供される「192.168.10.113」にWebアクセスする
- FortigateがLBとして動作し、ラウンドロビンで各Webサーバにバランシングする
- ヘルスチェックでDownを検知したサーバには振り分けをしないようにする。
- Webサーバへ接続する際には、Fortigateのアドレスで送信元NATする。
事前確認
■Webサーバ#1へのアクセス確認
$ curl http://192.168.10.111
Web01(192.168.10.111)
■Webサーバ#2へのアクセス確認
$ curl http://192.168.10.112
Web02(192.168.10.112)
→各Webサーバにアクセスした際、明示的に異なる結果になることを確認
LB機能が動作する環境を作成する
事前の補足
Fortigateのロードバランシング機能は、WebUIのメニュー上は[Virtual Servers]という名称です。
ただ、コマンドは[vip]だったり、[Load Balancing]だったり、いろいろ変わってくるのでちょっとわかりにくいです。
NAT機能部分に[Virtual IP]とか[IP Pool]とかもあるのでお間違え無きよう。
作業の流れ
全体的な作業の流れとしては、以下のようになります。
- Feature SetでLoad Balancing機能(表示するか否か)を有効化する。
- ヘルスモニターを作成する。
- Virtual Serverを作成する。
- 作成したVirtual Serverを用いたポリシーを設定する。
なお、最初のFeature Setは、無視しても設定は可能です。
作成したPlaybook
いろいろ使ったので、結構長くなりました。
with_item構成にしたほうが恰好がいい(ヘルスチェックのところとか)とも思うんですが、どういう単位でPlaybookを再利用するかによりますかね。個人的にはわかりやすさ重視なのでべた書きでも良い派です。
構成要素ごとに簡単に説明もします。
---
- hosts: fortigate
gather_facts: false
vars:
web01_address: "192.168.10.111"
web02_address: "192.168.10.112"
vip_address: "192.168.10.113"
vip_name: "Ansible_TEST_VIP"
tcp_port: "80"
vip_if: "dmz"
balance_method: "round-robin"
policy_srcintf: "{{ vip_if}}"
policy_dstintf: "{{ vip_if}}"
policy_service: "HTTP"
tasks:
#1. Feature SetでLoad Balancing機能(表示するか否か)を有効化する。
- name: Enable Loadbalance Feature Visibillity
fortios_system_settings:
system_settings:
gui_load_balance: "enable"
#2. ヘルスモニターを作成する。
- name: Create Health Monitor(PING)
fortios_firewall_ldb_monitor:
firewall_ldb_monitor:
name: "PING"
state: "present"
type: "ping"
interval: "10"
retry: "3"
timeout: "2"
port: "0"
- name: Create Health Monitor(TCP_80)
fortios_firewall_ldb_monitor:
firewall_ldb_monitor:
name: "TCP_80"
state: "present"
type: "tcp"
interval: "10"
retry: "3"
timeout: "2"
port: "{{ tcp_port}}"
- name: Create Health Monitor(HTTP_GET_80)
fortios_firewall_ldb_monitor:
firewall_ldb_monitor:
name: "HTTP_GET_80"
state: "present"
type: "http"
interval: "10"
retry: "3"
timeout: "2"
port: "{{ tcp_port}}"
http_get: ""
http_match: ""
#3. Virtual Serverを作成する。
- name: Create VIP Setting
fortios_firewall_vip:
firewall_vip:
state: "present"
arp_reply: "enable"
name: "{{ vip_name}}"
comment: "{{ vip_name}}"
id: "0"
extip: "{{ vip_address}}"
extintf: "{{ vip_if}}"
protocol: "tcp"
extport: "{{ tcp_port}}"
server_type: "http"
ldb_method: "{{ balance_method}}"
type: "server-load-balance"
monitor:
- name: "PING"
- name: "TCP_80"
- name: "HTTP_GET_80"
realservers:
-
id: "1"
client_ip: ""
ip: "{{ web01_address}}"
port: "{{ tcp_port}}"
status: "active"
healthcheck: "vip"
-
id: "2"
client_ip: ""
ip: "{{ web02_address}}"
port: "{{ tcp_port}}"
status: "active"
healthcheck: "vip"
#4. 作成したVirtual Serverを用いたポリシーを設定する。
- name: Create Firewall Policy for VIP
fortios_firewall_policy:
state: "present"
firewall_policy:
policyid: "2"
srcintf:
- name: "{{ policy_srcintf}}"
dstintf:
- name: "{{ policy_dstintf}}"
service:
- name: "{{ policy_service}}"
srcaddr:
- name: "all"
dstaddr:
- name: "{{ vip_name}}"
schedule: "always"
action: "accept"
nat: "enable"
status: "enable"
- Feature SetでLoad Balancing機能(表示するか否か)を有効化する。
詳細はこちら
- name: Enable Loadbalance Feature Visibillity
fortios_system_settings:
system_settings:
gui_load_balance: "enable"
WebUIで見るとこの部分です。

これを有効化すると、左側のメニューの[Policy & Objects]に[Virtual Servers],[Health Check]というメニューが登場します。

- ヘルスモニターを作成する。
詳細はこちら
- name: Create Health Monitor(HTTP_GET_80)
fortios_firewall_ldb_monitor:
firewall_ldb_monitor:
name: "HTTP_GET_80"
state: "present"
type: "http"
interval: "10"
retry: "3"
timeout: "2"
port: "{{ tcp_port}}"
http_get: ""
http_match: ""
HTTP監視の部分を持ってきました。 fortios_firewall_ldb_monitorというモジュールを使います。モジュールのリファレンスはこちら。
所定のパスの応答(http_get)や、レスポンスのチェック(http_match)も可能なようです。
- Virtual Serverを作成する。
詳細はこちら
- name: Create VIP Setting
fortios_firewall_vip:
firewall_vip:
state: "present"
arp_reply: "enable"
name: "{{ vip_name}}"
comment: "{{ vip_name}}"
id: "0"
extip: "{{ vip_address}}"
extintf: "{{ vip_if}}"
protocol: "tcp"
extport: "{{ tcp_port}}"
server_type: "http"
ldb_method: "{{ balance_method}}"
type: "server-load-balance"
前半部分では、対象のVIPの名前やアドレス、インターフェースの定義などを行います。
fortios_firewall_vipというモジュールを使います。モジュールのリファレンスはこちら。
ldb_method という部分がロードバランシング機能の肝です。
least-session(既存コネクション数の少ないもの)、Weighted(重みづけラウンドロビン)など、他のアルゴリズムもいくつか選択できるようです。
monitor:
- name: "PING"
- name: "TCP_80"
- name: "HTTP_GET_80"
realservers:
-
id: "1"
client_ip: ""
ip: "{{ web01_address}}"
port: "{{ tcp_port}}"
status: "active"
healthcheck: "vip"
後半に2.で作成したヘルスモニターや、バランシング対象の実サーバの情報を登録します。対象サーバの指定で、ポリシー用のオブジェクトが使えればいいんですが、利用できないようです。残念。
- 作成したVirtual Serverを用いたポリシーを設定する。
詳細はこちら
- name: Create Firewall Policy for VIP
fortios_firewall_policy:
state: "present"
firewall_policy:
policyid: "2"
srcintf:
- name: "{{ policy_srcintf}}"
dstintf:
- name: "{{ policy_dstintf}}"
service:
- name: "{{ policy_service}}"
srcaddr:
- name: "all"
dstaddr:
- name: "{{ vip_name}}"
schedule: "always"
action: "accept"
nat: "enable"
status: "enable"
別の記事でも利用した、fortios_firewall_policyを利用します。ワンアーム構成なので、実態としてはsrcintf/dstintfは同じものです。dstaddrの部分に、作成したVirtual Serverを宣言します。送信元NATはここで定義しています。
動作確認
バランシング確認
Ansibleホストからcurlで確認してみたところ、問題なくバランシングされていました。
$ curl http://192.168.10.113
Web01(192.168.10.111)
$ curl http://192.168.10.113
Web02(192.168.10.112)
$ curl http://192.168.10.113
Web01(192.168.10.111)
$ curl http://192.168.10.113
Web02(192.168.10.112)
NAT確認
192.168.10.61 - - [22/Dec/2019:15:27:39 +0900] "GET / HTTP/1.1" 200 23 "-" "curl/7.29.0"
curlでアクセスしている際の送信元IPがちゃんとFortigateのアドレス(192.168.10.61)になっています。
ヘルスチェック確認(定期監視)
サーバ側のアクセスログは以下のようになっていました。
ちゃんとインターバルで定義した10秒ごとにチェックが来ています。
User-AgentがFortiOS 4.0というのがなんとも…
192.168.10.61 - - [22/Dec/2019:12:13:49 +0900] "GET / HTTP/1.0" 200 23 "-" "FortiGate (FortiOS 4.0)"
192.168.10.61 - - [22/Dec/2019:12:13:59 +0900] "GET / HTTP/1.0" 200 23 "-" "FortiGate (FortiOS 4.0)"
192.168.10.61 - - [22/Dec/2019:12:14:09 +0900] "GET / HTTP/1.0" 200 23 "-" "FortiGate (FortiOS 4.0)"
ヘルスチェック確認(ダウン時)
試しにWeb01のhttpdをダウンさせ、動作確認してみます。
$ curl http://192.168.10.113
Web02(192.168.10.112)
$ curl http://192.168.10.113
Web02(192.168.10.112)
$ curl http://192.168.10.113
Web02(192.168.10.112)
$ curl http://192.168.10.113
Web02(192.168.10.112)
ちゃんとWeb02側だけにバランシングされました。
イベントログにもこんな形でログが記録されます。(VirtualServer側には何も出ません)

まとめ
以下のような結果になりました。
- AnsibleでFortigateのLB機能を一通り設定することができた
- ヘルスチェックなども問題なく動作することが分かった
- 手動での動作確認を、assertなどで実施できるよう学習を進める
商用でFortigateをLBとして使うケースはあまりないかも、とも思いますが、中小規模環境で、予算が削られて個別のLBが買えない、なんていう場合には利用できるかもしれません。(性能面は要検証です)
今回は試していませんが、SSLオフロード用機器としても利用できそうです。
また、今回はIPv4のみですが、IPv6や64/46も可能なようです。
なんかAnsibleというよりFortigate機能検証みたいな形になっていますが、どなたかのお役に立てれば幸いです。
バトンリレー
前回に引き続き、今回も無事にバトンをつなぐことができました。
お次は、@atsushi586さんです。
よろしくお願いいたします!
https://tenko.hatenablog.jp/entry/2019/12/22/152158
バックアップ日時: 2026年11月11日