てんこ

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

AnsibleでFortigateのSSL/SSHプロファイルを設定してみた【不具合あり】

年末に頂いていたお題がすっかり遅くなってしまい、申し訳ありません。

AnsiblejpのSlackにて、FortigateのSSLプロファイルに関するモジュールでのご相談があり、試していく中でいくつか分かったことがありますので記録しておきます。

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


目的

FortigateのSSL/SSHプロファイルの操作に利用するモジュールの動作を確認するため

環境

※普段はhttpapiを利用していますが、ご相談いただいた際のPlaybookがfortiosapiだったので今回はこちら。

SSL/SSHプロファイルについて解説

少し長くなりますが「SSL/SSHプロファイル」についての解説はこちら

昨今、HTTPではなくHTTPSでWebサイトを公開しているケースが増えています。

HTTPS通信は途中経路が暗号化されているため、セキュリティ系の装置でその中身を見て処理をしようと思っても、暗号化されたコンテンツの中身まで読み取ることができません。

このような状況でも詳細なアクセスログを取得したり、コンテンツのスキャンを行うために、Fortigateだけではなくさまざまなセキュリティ機器で「SSL復号」という処理が行われています。

ここではSSL復号の詳細な解説はしません。参考として、PaloAlto社のサイトのリンクを張っておきます。

このSSL復号ですが、様々な状況で「復号の除外」を行う必要があります。除外が必要なケースについて、いくつか例をあげておきます。

  • クライアント証明書が必要な場合
  • カスタムCA証明書が入れられなかったり、アプリケーションがOSの証明書ストアを参照しなかったりする場合
  • プロトコル的にはHTTPSを利用しているが、HTTPSではなく、トンネリング用途で使っている場合(SSL-VPNなど)

タイトルにある、「SSLプロファイル」というのは、上記のような復号処理の条件を定義する設定箇所のFortigate上での名前です。

Fortigateの場合、SSLプロファイルは以下の3種類しかないはずです。

名前 用途 備考
certificate-inspection Webサーバのアイデンティティ確認のため 初期値・カスタム不可
custom-deep-inspection 除外で定義されたものを除いてデータを復号・再暗号化する カスタム可能
deep-inspection 全てのサイトに対してデータを復号・再暗号化する 初期値・カスタム不可

この3種類のうち、カスタム可能なのは「custom-deep-inspection」しかありません。そのため、SSL復号の除外を設定する場合には、必然的に「custom-deep-inspection」のSSLプロファイルを利用することになります。

こちらのサイトに、設定方法まで含めてまとまっていました。興味のある方はご参照ください。

AnsibleでFortigateの上記SSL/SSHプロファイルを操作する場合、「fortios_firewall_ssl_ssh_profile」モジュールを利用します。

本題

頂いた質問事項

以下のようなPlaybookを作成したが、以下のような症状が発生している。

  • 既にcustom-deep-inspectionにID1/2/3がある状態だとChangedとなるが値が変わらない
  • custom-deep-inspectionに何も登録がない状態だと、Failedとなる。
  tasks:
  - name: Configure SSL/SSH protocol options in Fortinet's FortiOS and FortiGate.
    fortios_firewall_ssl_ssh_profile:
      host: "{{ host }}"
      username: "{{ username }}"
      password: "{{ password }}"
      vdom: "{{ vdom }}"
      https: "yes"
      ssl_verify: "{{ ssl_verify }}"
      state: "present"
      firewall_ssl_ssh_profile:
        name: "custom-deep-inspection"
        ssl_exempt:
          - id: "1"
            type: "wildcard-fqdn"
            wildcard_fqdn: "test_1"
          - id: "2"
            type: "wildcard-fqdn"
            wildcard_fqdn: "test_2"
          - id: "3"
            type: "wildcard-fqdn"
            wildcard_fqdn: "test_3"

こちらで確認してみた結果

こちらでも確認してみたところ、以下のような症状が確認できました。

  • ご相談いただいた症状は再現する。
  • ID1/2/3がある状態でPlaybookでID1/2/4のリクエストを投げると以下のようになり、結果はFailedになる。
    • ID1/2はそのまま残る。(値の変更は反映されない)
    • ID3は消える。
    • ID4は作成されない。
  • ssl_exemptのリスト形式以外の箇所は正常に(?)動作する
    • commentを入れると上書きできたり(changed)
    • SSL処理対象をコントロールする構文も問題なく動作したり(changed)
    • ただし、ssl_exemptの症状を再現させてAnsibleの処理結果が「Failed」となっても、ssl_exemptの部分以外は設定が反映されてしまう。

暫定回避方法について

AnsiblejpのSlackで得られた情報によると、現在のところ、この症状を回避するためには、上記のPlaybookのうち「wildcard_fqdn」(アンダーバー)の部分を「wildcard-fqdn」(ハイフン)とする必要があるようです。

この記述方法は、「fortios_firewall_ssl_ssh_profile」モジュール のリファレンス上のexampleとは異なる記載方法となりますが、下記のように書き換えることで正常にPlaybookが動作することが確認できました。

        ssl_exempt:
          - id: "1"
            type: "wildcard-fqdn"
            wildcard-fqdn: "test_1" # ここ
          - id: "2"
            type: "wildcard-fqdn"
            wildcard-fqdn: "test_2" # ここ
          - id: "4"
            type: "wildcard-fqdn"
            wildcard-fqdn: "test_3" # ここ

f:id:tatematsu_san:20200106205301p:plain

原因について

我らがよこちさんが、fortios用モジュールのissueから原因となるものを見つけてくださいました。

要約すると、以下のような処理の不具合のようです。

  • fortiosの内部では、パラメータはハイフンで処理されている(こちらに実例を挙げてあります)
  • AnsibleのPlaybook側では、Snake Case(アンダーバー)で記載する形が想定されている
  • この間のコンバートを、「 _ → - 」に変換するファンクションで実装している
  • この変換処理が、うまく動かない場合がある【不具合箇所】

ざっと眺めている限りだと、「List形式」でパラメータを与える部分で、その要素に「_を含むパラメータ」がある場合にこの不具合が出るようです。ネスト処理の部分ですかね。

そのため、今回例に挙げたSSL/SSHプロファイル以外の箇所でも該当する部分はあるようです。(fortios_firewall_addressとか)

正式な対応方法について

どうやら、2019年の年末に修正は完了しているようです。

github.com

よこちさんも、すでに動作確認を実施頂いているようですね。さすがよこちさん!

実際のモジュールへの取り込みは、どのタイミングで実施されるんですかね。Collectionとか使うんでしょうか。

ちょっと対処方法が締まりませんが、類似の不具合が確認されたら、以下の方法をお試しいただければと思います。

  • 同様の症状が出る場合はハイフンにして試してみる
  • Ansible用のモジュールが更新されたらアンダーバーに直して試してみる