てんこ

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

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"
},

f:id:tatematsu_san:20191208170048p:plain

頭を悩ませていたんですが、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 )

f:id:tatematsu_san:20191208190845p:plain

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

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

source: uploadの場合(未達成)

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

なんですが。

f:id:tatematsu_san:20191208173530p:plain

なぜ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を伸ばして、処理結果を取得する方法