てんこ

ブログ名は愛猫(てん)の愛称です。中身は個人のIT系学習記録です。

AnsibleでFortigateのLB機能を使ってみた

この記事は、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環境

構成図

このような感じの構成で確認を行いました

ロードバランサー的な用語でいうと、「ワンアーム構成」です。

(自宅のネットワーク環境の構成上、これ以外つらいんです。直さねば)

前提条件

  • 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]とかもあるのでお間違え無きよう。

作業の流れ

全体的な作業の流れとしては、以下のようになります。

  1. Feature SetでLoad Balancing機能(表示するか否か)を有効化する。
  2. ヘルスモニターを作成する。
  3. Virtual Serverを作成する。
  4. 作成した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"

1. 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]というメニューが登場します。

2. ヘルスモニターを作成する。

詳細はこちら

  - 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)も可能なようです。

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"

前半部分では、対象の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.で作成したヘルスモニターや、バランシング対象の実サーバの情報を登録します。対象サーバの指定で、ポリシー用のオブジェクトが使えればいいんですが、利用できないようです。残念。

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"

別の記事でも利用した、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さんです。

よろしくお願いいたします!

AnsibleでFortigateのHA構成を組んでみた。

この記事は、Ansible 2 Advent Calender 2019の15日目の記事です。

昨日の…というか、先週一週間は、@sky_jokerxxさん「Ansible2 Advent Calender 一週間全部俺」の無双をやっていただいてまして、あれだけ引き出しが多いのすごいなあと、ただただ尊敬する次第です。

昨日の記事はこちらです。

さて、私はいつもの通り、AnsibleでFortigateを操作してみた話を書かせていただきます。今回はHAを組むモジュールである、fortios_system_haを使ってみました。

Ansible関連の実践記事一覧はこちら


目的

fortigateを冗長構成(HA)を組むためのPlaybookの書き方や、<your_own_value>を明らかにするため

…そろそろ<your_own_value>との戦いから卒業せねば(汗)

先に結論

  • FortigateのHA設定用モジュールを利用して、HA構成を組むことができた
    • 初回設定のときはfailedになるが、設定は成功している
    • HeartBeat用のインターフェースを指定する場合は注意する
  • internalを分離させるためのvirtual-switchを扱うモジュールは現時点では存在しない。

環境

構成図

このような感じの構成で確認を行いました。

前提条件として、初期設定でFortigate側は初期状態からDMZポートに各々の管理用IPを付与した状態を前提としています。

構成上の注意点

検証で利用しているFortigateは60Dなのですが、スイッチ用のポートとして、「internal」というポートが備わっています。(1-7番ポートまで存在)

HA構成を組む場合、このスイッチポートを分離させて独立したポートにすることが多いです。 実機の設定では、「config system virtual-switch」というConfigで定義されているのがその箇所なのですが、残念ながら現時点では、Ansibleのfortios用のモジュールには、このvirtual-switchに関連するモジュールが存在しません。

今回は可能な限りPlaybookのみで実施しようとしていますので手動での分離などは行っていませんが、手動で分離した場合などについては、また別途記事にしたいと思います。

参考までに、実機で全ポートを独立したポートに分離する場合には、以下の通りのコマンドで実施可能です。

config system virtual-switch
delete 1
end

作成したinventory、group_vars、host_vars、Playbook

モジュールリファレンスを参考にしつつ、まずは以下のような環境設定を定義。

■inventory

[fortigate]
fg_fw01 ansible_host=192.168.10.61
fg_fw02 ansible_host=192.168.10.62

■group_vars

---
ansible_user: admin
ansible_password: password
ansible_network_os: fortios
ansible_connection: httpapi
ansible_httpapi_use_ssl: yes
ansible_httpapi_validate_certs: no
timeout: 600

■FW01用(host_vars/fg_fw01.yml)

---
fw_hostname: fw01
ha_manage_if: dmz
ha_manage_gw: 192.168.10.254
vc1_node_role: master
vc1_priority: 200
vc1_monitor_if: wan1

■FW02用(host_vars/fg_fw02.yml)

---
fw_hostname: fw02
ha_manage_if: dmz
ha_manage_gw: 192.168.10.254
vc1_node_role: backup
vc1_priority: 100
vc1_monitor_if: wan1

基本的には、単純なHA構成だけであれば、Priorityの値だけをホスト毎に変えれば問題ないと思います。

本当はもうちょっとvarsに入れたほうがいいものもあるんですが、時間も足りなくて未整理です。申し訳ありません。 そして、作成したPlaybookがこちら。

■Playbook

---
- hosts: fortigate
  gather_facts: false
  vars:
    vdom: "root"

  tasks:
  - name: Fortigate Hostname Setting # ホスト名の定義
    fortios_system_global:
      system_global:
        hostname: "{{ fw_hostname }}"
        alias: "{{ fw_hostname }}"

  - name: Fortigate HA VC1 Setting # 実際のHA設定
    fortios_system_ha:
      system_ha:
        group_id: "10"
        group_name: "FG_TEST"
        mode: "a-p"
        authentication: "enable"
        password: "hogehoge"
        ha_direct: "enable"
        ha_mgmt_status: "enable"
        ha_mgmt_interfaces:
          - 
            id: "1"
            interface: "{{ ha_manage_if }}"
            dst: "0.0.0.0 0.0.0.0"
            gateway: "{{ ha_manage_gw }}"
        priority: "{{ vc1_priority }}"
        monitor: "{{ vc1_monitor_if }}"
        hbdev: "\"wan2\" 128" # 注意点(後述)
        session_sync_dev: "wan2"
        sync_config: "enable"
        vcluster2: "disable"
        schedule: "none"
        override: "disable"
        vcluster_id: 0
        vdom: "{{ vdom }}"

冗長を組むと、さすがにホスト名を定義しないと区別が難しくなるため、ha設定を行う前に、hostnameの定義などを行っています。

このPlaybookを実行すると、以下のようにHA設定の部分はfailedになります。

しかしながら、WebUIなどで覗いてみると、意図した通りの設定になっていることが確認できます。

なぜfailedになるのに設定は完了しているのかについてですが、failedの要因は応答待ちのtimeoutです。 この辺りは機器の仕様もあると思いますが、HAの設定操作を行ったHTTPコネクションでは、HA設定に関しては応答を返せないのかな、と推測しています。

ちなみに、すでにHA構成が組まれているホストに対しての設定変更を行うPlaybookであれば、応答は返ってきます。

Playbook作成上の注意点

このあたりが<your_own_value>との戦いである所以なのですが、Playbook上にコメントした、hddev: のところで少しハマりました。

以下の画像は、モジュールリファレンスのサンプルの記述です。

hbdev:の部分は、目的は「Heart Beat パケットをやりとりするインターフェース(デバイス)を指定する」箇所です。

CLIなどで設定している人は良くご存じかもしれませんが、この設定においては、インターフェース名だけを指定するだけではなく、その「プライオリティ」を定義する必要があります。

記述方法が ”<インターフェース名>" <プライオリティ値> という指定をする必要があるため、ダブルクォーテーションもパラメータとして必要になります。

そのため、エスケープ文字を挟み、このように書く必要があります。

        hbdev: "\"wan2\" 128" # 注意点(後述)

まとめ

「先に結論」の個所でも書きましたが、以下のような結果になりました。

  • FortigateのHA設定用モジュールを利用して、HA構成を組むことができた
    • 初回設定のときはfailedになるが、設定は成功している
    • HeartBeat用のインターフェースを指定する場合は注意する
  • internalを分離させるためのvirtual-switchを扱うモジュールは現時点では存在しない。

リファレンスの<your_own_value>と戦いは、以下のような流れでやっています。

  • とりあえずCLIで最低ラインを探してみる
  • WebUIでも設定を実施してみる
  • uriモジュールを利用した汎用Playbookで設定後の状態をJSONで取得する
    • 今回のものは、cmdb/system/haで取得が可能
  • Playbookに落としこむ

楽しくはあるんですが、時間が限られたときにやるものではないですね…

また今度、今回作成したPlaybookを生かして、この構成を使った運用のつらみだったり、複数のVDOM Cluster構成を組むようなPlaybookにチャレンジしたいと思います。

バトンリレー

なんとか前走者から渡されたバトンを落とさず、ブログを書くことができました。

お次のssato1138さんにバトンをつなぎます。

よろしくお願いいたします!

AnsibleでFortigateをファームアップしてみた

Advent Calenderの時期で、私もAnsible 2 Advent Calender 2019にエントリしていますが、空気を読まずに通常投稿!!

先日の記事にも書きましたが、我が家の検証用のFortigateが2台構成になりました。

最終的にHAを組むつもりなので、各々のバージョンを合わせるために、Ansibleでファームアップを試みてみましたので、それを記録しておきます。

Ansible関連の実践記事一覧はこちら


目的

AnsibleによるFortigateのファームアップにおけるPlaybookに必要なパラメータを明らかにするため

モジュールのリファレンス<your_own_value>ばかりで困るんです…

環境

※途中の過程でFortios5.6でも試しかけましたが、fortios_factsすら通らなかったので断念。

fortios_system_firmware_upgradeの手法毎の結果

source: usbの場合

事前準備として、ファームアップ用のファイル(.outファイル)をUSBメモリに入れ、本体に接続します。

その後、以下のようなPlaybookで、問題なくファームアップが実施できました。

最後にdebug仕込んでますが、Reboot入ってしまうのでエラーになります。(うろ覚えなので、確認後修正するかもしれません。)

ただ、処理はちゃんと実行されていて、Reboot後には新しいファームで起動してきます。

---
- hosts: fortigate
  gather_facts: false
  vars:
    vdom: "root"

  tasks:

  - name: Perform firmware upgrade with firmware file on USB.
    fortios_system_firmware_upgrade:
      vdom:  "{{ vdom }}"
      system_firmware:
        filename: "FGT_60D-v6-build0303-FORTINET.out" #USBメモリ上のファイル名を入れる
        format_partition: "yes"
        source: "usb"
    register: fortios_system_firmware_upgrade_result
  
  - name: Debug
    debug:
      var: fortios_system_firmware_upgrade_result

source: fortiguardの場合

事前準備として、ファームアップ用のファイル名が必要になります。

この「ファイル名」が曲者でして。「オンラインなのにファイル名…?」となりました。バージョンの指定とかならわかるんですが。

  • USBでやったときの結果と同じファイル名でやってみる→NG ( "FGT_60D-v6-build0303-FORTINET.out" )
  • ターゲットにしているバージョンを入れてみる→NG ( "v6.0.8" )

■NG時の出力(Playbookの実行結果のstateとしてはokになります)

"results": {
    "error": "download_failed",
    "status": "error"
},

頭を悩ませていたんですが、fortios_factsに「system_firmware_select」というfactがあったことを思い出しまして、以下のPlaybookを実行。

■fortios_facts実行用のPlaybook

---
- hosts: fortigate
  gather_facts: false

  tasks:
  - name: Get Facts.
    fortios_facts:
      gather_subset:
        - fact: 'system_firmware_select'
    register: getfact_result

  - name: Debug
    debug: 
      var: getfact_result

その結果、以下のようなJSON形式の情報が戻ってきました。

■fortios_factsの出力結果

"results": {
"available": [
    {
        "branch-point": 303,
        "build": 303,
        "id": "06000000FIMG0009900008",
        "major": 6,
        "minor": 0,
        "name": "FortiOS",
        "notes": "http://docs.fortinet.com/d/fortios-6.0.8-release-notes/download",
        "patch": 8,
        "release-type": "GA",
        "source": "fortiguard",
        "version": "v6.0.8"
    },
    {
        "branch-point": 302,
        "build": 302,
        "id": "06000000FIMG0009900007",
        "major": 6,
        "minor": 0,
        "name": "FortiOS",
        "notes": "http://docs.fortinet.com/d/fortios-6.0.7-release-notes/download",
        "patch": 7,
        "release-type": "GA",
        "source": "fortiguard",
        "version": "v6.0.7"
    },
(中略)
],
"current": {
    "branch-point": 231,
    "build": 231,
    "id": "current",
    "major": 6,
    "minor": 0,
    "name": "FortiOS",
    "notes": "http://docs.fortinet.com/d/fortios-6.0.4-release-notes/download",
    "patch": 4,
    "platform-id": "FGT60D",
    "release-type": "GA",
    "source": "current",
    "version": "v6.0.4"
}

この中のどれかか…とあたりを付け、ファイル名になりそうな「id」という情報を試しに入れてみました。

結果、Playbookの実行が即download_Failed などにはならず、待ち状態→Timeoutっぽい形でfailedになりました。

■作成したPlaybook

---
- hosts: fortigate
  gather_facts: false
  vars:
    vdom: "root"

  tasks:

  - name: Perform firmware upgrade with firmware on fortiguard.
    fortios_system_firmware_upgrade:
      vdom:  "{{ vdom }}"
      system_firmware:
        filename: "06000000FIMG0009900008" #v6.0.8の場合の「ID」の値を記載
        format_partition: "yes"
        source: "fortiguard"
    register: fortios_system_firmware_upgrade_result
  
  - name: Debug
    debug:
      var: fortios_system_firmware_upgrade_result

しばらく放置すると、コンソール画面に変化が現れ、ファームアップのシーケンスに入ってくれて、その後自動で再起動→ファームアップが完了しました!!

というわけで、【source: fortiguardを利用する場合のfilenameにはfortios_factsで取得できる対象ファームウェアの「id」を入れればいい】ということがわかりました。

これも最後にdebug仕込んでますが、ファームウェアのダウンロード中の段階でTimeoutを迎えてエラーになります。ただ、処理はちゃんと実行されていて、Reboot後には新しいファームで起動してきます。

試しにPlaybook実行時に--timeout=6000 とオプションを入れてみましたが変わりませんでした。

httpapiのtimeout値をいじればもしかしたら戻りが取れるのかもしれません。また調べてみようと思います。

ダウングレードの場合

試しに、6.0.8->6.0.7を同じやり方で試してみたんですが、ダウングレードは始まりませんでした。

ファームウェア関連は、WebUIで見ると、こんな画面になります。(System -> Firmware )

上手く行かない理由は、この部分の「Confirm version downgrade」に当たる部分がモジュール上存在しないからかな、と予想してます。

(WebUIでやる場合には、問題なくダウングレードも実施可能です)

source: uploadの場合(未達成)

おそらく、Ansibleを使う時点でUSBはないな、と思ってます。そうすると、本命はfortiguardか、このupload。

なんですが。

なぜbase64エンコードをする必要があるのか…

モジュール側で処理してくれればいいのにと思いながら、ちょっと試してみましたが、上手く行かず。

■作成したPlaybook(失敗してます)

---
- hosts: fortigate
  gather_facts: false
  vars:
    vdom: "root"

  tasks:
  - name: Perform firmware upgrade with firmware file Upload File.
    fortios_system_firmware_upgrade:
      vdom:  "{{ vdom }}"
      system_firmware:
        file_content: lookup('file', '/home/ansible/ansible-playbook/fortigate/F60Dv608_base64')
        filename: "FGT_60D-v6-build0303-FORTINET.out"
        format_partition: "yes"
        source: "upload"
    register: fortios_system_firmware_upgrade_result
  
  - name: Debug
    debug:
      var: fortios_system_firmware_upgrade_result

外部でbase64化したものをlookupで読ませたんですが、失敗してます。

これは余裕がある時にもう少し別の方法を試してみます。

まとめ

最後の「upload」はまだ未完了ですが、FortigateのファームアップもAnsibleで実行できることが確認できました。

uploadのものも、fortiguardほどはわからなくはないと思いますので、また折を見てやってみます。

●残課題

  • uploadでのbase64での実践
  • fortiguard/uploadで発生するtimeoutを伸ばして、処理結果を取得する方法

ラボ環境がちょっとパワーアップしました。

いつもAnsibleで検証してるFortigateが2台構成になり、HAが組めるように…これで色々捗りそうです!!

配線は仮なので見直す予定。

12/5 見直し完了!!これで捗る予感!

  • 2PortのLANスイッチャ(左端に見える白い箱)で、1/2号機のFortigateのコンソール接続を切り替えられるように整備
  • LAN配線を全体的に短いケーブルへ移行
  • 純正電源ケーブルが長すぎるため、ミッキータイプの短い電源ケーブルに換装

AnsibleでFortigateのConfigをバックアップしてみた。

Ansibleのfortios用のモジュールには、バックアップモジュールはありません。

実際には、fortios_configというモジュールで取得ができたようなのですが、pyFGが必要なようです。

自分の環境ではpyFGが入らないので、うーんと思っていました。(細かい原因は追ってません…)

先日書いた汎用のuriを、こちらのブログを参考にして少しいじったら、バックアップを取得することができました。

参考にしたブログではAPI_KEYを利用されていましたが、現時点ではセッションのCookieでも取得は可能でした。(将来が若干不安ではありますが…)

Ansible関連の実践記事一覧はこちら


作成したPlaybook

---
- hosts: fortigate  
  gather_facts: false

  vars:
    api_type: "monitor"
    api_path: "system"
    api_name: "config"

  tasks:
  - name: Login
    uri:
      url: https://{{ ansible_host }}/logincheck
      validate_certs: no
      method : "POST"
      force_basic_auth: yes
      body_format: "form-urlencoded"
      url_username: "{{ ansible_user }}"
      url_password: "{{ ansible_password }}"
      body:
        - [ username, "{{ ansible_user }}" ]
        - [ secretkey, "{{ ansible_password }}" ]
        - [ ajax, "1" ]
    register: http_response
    
  - name: GET Config Backup
    uri:
      url: https://{{ ansible_host }}/api/v2/{{ api_type }}/{{ api_path }}/{{ api_name }}/backup?scope=global
      validate_certs: no
      method: "GET"
      headers:
        Cookie: "{{ http_response.set_cookie }}"
      return_content: yes
    register: get_obj

  - name: Backup File
    copy:
      content: "{{ get_obj.content }}"
      dest: ./backup.txt # バックアップ出力先指定

取得できたバックアップ

2バイト文字もばっちり。

うーん、この参考にしたブログの方はAPIリファレンスお持ちなのかな…

やっぱりフル活用するにはAPIリファレンスが読みたいなあ…