FortiGate の設定を REST API で取得|Excel パラメータシートを自動生成

  • URLをコピーしました!
目次

はじめに

FortiGate の構成レビューや変更前後の差分確認で、GUI を画面ごとに開いてパラメータシートへ転記する作業は、台数が増えるほど負荷が上がります。show full-configuration の出力をそのまま貼り付ける方法もありますが、Policy と参照先のオブジェクト定義は別の箇所に出力されるため、Policy に書かれた Address 名や Service 名が実際にどの値を指しているかを知るには、両者を相互に照合する必要があります。

そこで、FortiGate の REST API から設定情報を読み取り、Excel パラメータシートとして出力する Python スクリプトを作成しました。この記事では、その実装方針と実際の出力内容をまとめます。

この記事でわかること
  • FortiGate の REST API から設定情報を取得する Python スクリプトの設計方針
  • REST API Administrator と Trusted Hosts の準備手順
  • 生成される Excel パラメータシート 21 枚の中身
  • Policy が参照するオブジェクトを実値へ展開する Policy_Resolved シートの読み方
  • 取得結果と参照解決を点検する Validation シートの使い方
  • 取得できる範囲の限界と、運用へ持ち込む際の注意点

作成したスクリプトは HTTP GET だけを発行し、FortiGate の設定変更は行いません。1 回の実行で 18 エンドポイントを取得し、21 枚のシートを持つ Excel ファイルと、サニタイズ済みの JSON スナップショットを出力します。API トークンは対話入力でファイルへ保存せず、API の生レスポンスも保存しない設計としました。なお、現時点ではエクスポート専用で、Excel から FortiGate へ設定を書き戻すインポート機能は実装していません。

今回作成するもの

スクリプトの実行で得られる成果物は 2 つです。

成果物内容
fortigate_parameter_sheet.xlsx21 枚のシートを持つ Excel パラメータシート。オートフィルターと印刷設定を適用済み
fortigate_sanitized_snapshot.json同じ内容を機械可読な形で保持した JSON。差分比較やスクリプト連携を想定

どちらも許可したフィールドだけを出力しており、API の生レスポンスは残しません。

検証環境と構成

検証は VMware Workstation Pro 上の仮想環境で行いました。

項目内容
仮想化基盤VMware Workstation Pro 26H1
ファイアウォールFortiGate-VM64 / FortiOS 8.0.0 build 167 / Permanent Trial
クライアントUbuntu Desktop 26.04 LTS
Python3.14.4
openpyxl3.1.5(Ubuntu の apt パッケージ python3-openpyxl 3.1.5+dfsg-3

ネットワークは単一セグメントとし、FortiGate の port1 に 192.168.10.254/24、Ubuntu 側に 192.168.10.10/24 を割り当てています。スクリプトは Ubuntu から port1 の管理インターフェースへ HTTPS で接続します。port2 は DHCP モードで外部接続用に設定していますが、今回のスクリプトは設定値だけを読み取るため、実際の通信状態には依存しません。

FortiGate-VM 自体の構築手順は本記事の範囲外です。VMware Workstation へ FortiGate-VM を展開する流れは、関連記事『VMware Workstation への FortiGate-VM 構築手順』にまとめていますので、そちらを参照してください。

port1 では管理アクセスとして HTTPS を許可しています。REST API は管理インターフェースの HTTPS 経由で提供されるため、この設定が有効になっている必要があります。

REST API Administrator の準備

FortiGate の REST API はトークン認証を使用します。トークンは REST API Administrator を作成した時点で発行されます。

Administrator Profile の作成

REST API Administrator には Administrator Profile を割り当てます。今回の検証では api_automation という名前のプロファイルを作成しました。

次の表は検証時に設定した内容であり、推奨設定例ではありません。

権限カテゴリ設定値
FirewallRead/Write
Log & ReportRead
NetworkRead
SystemRead
CLI コマンド利用(Override Idle Timeout 等を含む CLI 実行の可否)Enable

表に挙げたのは、今回の検証時に設定を確認できたカテゴリです。ここに記載していない項目については、環境ごとに既定値が異なる可能性があるため、実際の画面で確認してください。

この構成は検証を優先したものであり、プロファイル自体は読み取り専用ではありません。 Firewall が Read/Write になっている点と、CLI コマンド利用が Enable になっている点は、いずれも書き込みを伴う操作を許容する設定です。スクリプト側が GET しか発行しないことと、プロファイルに与えた権限は、別の話として区別してください。

本番環境へ持ち込む場合は、取得したいエンドポイントに対応する参照権限だけへ絞り込み、CLI コマンド利用も不要であれば無効化することをおすすめします。公式ガイドも最小権限の適用を推奨しています。

参考: REST API administrator | FortiGate / FortiOS 8.0.0
“apply the principle of least privilege to the REST API administrator account”
(REST API 管理者アカウントには最小権限の原則を適用する)
https://docs.fortinet.com/document/fortigate/8.0.0/administration-guide/399023/rest-api-administrator

REST API Admin の作成と Trusted Hosts

System > Administrators から Create New > REST API Admin を選択し、作成したプロファイルを割り当てます。あわせて Trusted Hosts を設定します。今回は Ubuntu の IP アドレスだけに限定しました。Trusted Hosts を実行元の IP アドレスへ限定することで、指定した送信元以外からの管理アクセスを制限し、トークン流出時の不正利用リスクを下げられます。

参考: Administrator account options | FortiGate / FortiOS 8.0.0
“Trusted Hosts can only be configured for local and REST API administrator accounts”
(Trusted Hosts はローカル管理者アカウントと REST API 管理者アカウントにのみ設定できる)
https://docs.fortinet.com/document/fortigate/8.0.0/administration-guide/14906/administrator-account-options

保存すると API トークンが表示されます。このトークンは作成時に一度しか表示されないため、その場で控えておく必要があります。 表示を閉じたあとに再取得する手段はなく、必要になった場合はトークンを再生成することになります。

トークンの受け渡し方

FortiGate の REST API は、トークンをリクエストヘッダーへ含める方法と、URL パラメーターへ付与する方法の両方に対応しています。今回のスクリプトはヘッダー方式を採用しました。URL パラメーターはプロキシやアクセスログに残りやすく、公式ガイドもヘッダー方式を推奨しています。

参考: Using APIs | FortiGate / FortiOS 8.0.0
“it is strongly recommended to use API tokens in the request header”
(API トークンはリクエストヘッダーで使用することを強く推奨する)
https://docs.fortinet.com/document/fortigate/8.0.0/administration-guide/940602/using-apis

スクリプト側では次のようにヘッダーを組み立てています。

request = Request(
    url,
    method="GET",
    headers={
        "Authorization": f"Bearer {token}",
        "Accept": "application/json",
        "User-Agent": USER_AGENT,
    },
)

method"GET" で固定しており、POST や PUT を発行する経路はスクリプト内に存在しません。

Python スクリプトの実行

事前準備

Excel の生成に openpyxl を使用します。Ubuntu 26.04 は Python 環境が外部管理されているため、apt パッケージから導入しました。

sudo apt install -y python3-openpyxl

導入後のバージョンは 3.1.5 でした。仮想環境を使う場合は、python3 -m venv で環境を作成してから pip install openpyxl を実行する形になります。

実行方法

スクリプトはコマンドライン引数で接続先と取得対象を指定します。

python3 fortigate_parameter_export_v1_0.py \
    --base-url https://192.168.10.254 \
    --vdom root \
    --insecure

主なオプションは次のとおりです。

オプション内容
--base-urlFortiGate の URL。https:// 以外を指定するとエラー終了します
--vdom取得対象 VDOM。カンマ区切りで複数指定でき、その場合は各シートに VDOM 列が追加されます
--output-dir出力先。省略時は日時入りのディレクトリを作成します
--timeoutAPI タイムアウト秒。既定は 30 秒です
--insecureTLS サーバー証明書の検証を無効化します

実行すると API トークンの入力を求められます。getpass を使用しているため、入力内容は画面へ表示されません。

FortiGate API token:

トークンはコマンドライン引数にも環境変数にも対応させていません。シェル履歴やプロセス一覧に残ることを避けるためです。

--insecure を付ける理由

FortiGate-VM の初期状態では自己署名証明書が使われているため、証明書検証を有効にしたままでは接続に失敗します。今回は検証環境であることを前提に --insecure を指定しました。

--insecure は自己署名証明書を使用する検証環境に限定した指定です。 本番環境では、社内 CA などで発行した証明書を FortiGate へ導入し、このオプションを付けずに実行する運用が望ましいと考えます。スクリプトの既定は証明書検証が有効で、--insecure を明示したときだけ無効化される作りにしています。

実行結果と出力ファイル

実行が完了すると、日時入りのディレクトリに 2 つのファイルが出力されます。

読み取り専用エクスポートが完了しました。
JSON : fortigate_parameter_export_20260825_152850/fortigate_sanitized_snapshot.json
Excel: fortigate_parameter_export_20260825_152850/fortigate_parameter_sheet.xlsx
API生レスポンスと資格情報は保存していません。
FortiGateの設定変更は行っていません。

出力ディレクトリは 0700、生成した JSON と Excel は 0600 でパーミッションを設定しています。また、出力先がすでに存在する場合はエラー終了する作りにしており、過去の取得結果を上書きしません。

生成された Excel パラメータシート

21 枚のシート構成

出力される Excel は次の 21 枚で構成されます。

分類シート名
概要OverviewVDOMsSystem_Settings
インターフェースInterfacesZones
ルーティングConfigured_Static_RoutesPolicy_Routes
SD-WANSDWAN_ZonesSDWAN_MembersSDWAN_Health_ChecksSDWAN_Rules
オブジェクトAddressesAddress_GroupsVIPsVIP_GroupsServicesService_Groups
ポリシーFirewall_PoliciesPolicy_Resolved
その他DHCP_ServersValidation

各シートには見出し行の固定、オートフィルター、印刷時の見出し繰り返しを設定しています。

Overview シートには機器の識別情報と取得条件が並びます。今回の検証環境では次の値が出力されました。

項目
Exporter Version1.0.0
FortiOS Versionv8.0.0
Build167
HostnameFGVM************
Serial NumberFGVM************

Hostname と Serial Number は同じ値になっています。FortiGate-VM の既定ホスト名がシリアル番号と一致しているためです。スクリプト側で先頭 4 文字だけを残すマスク処理を行っており、記事へ掲載しても識別子として使える形では残りません。

なお System_Settings シートの Operation Mode は 未取得(対応レスポンスキー未確認) と表示されます。実機のレスポンスから該当するキーを確認できなかったため、推測で値を補わず、取得できていないことが分かる表示にしました。

Interfaces: 設定値と稼働ステータスの区別

Interfaces シートには、今回の環境で 7 件のインターフェースが出力されました。物理インターフェースの port1 と port2 のほか、fortilinkssl.rootl2t.rootnaf.rootdefault-mesh といった論理インターフェースが含まれます。

読み取る際に注意したい点が 2 つあります。

1 つ目は、IP アドレスが未設定の論理インターフェースが 0.0.0.0/0 と表示されることです。これは Address オブジェクトの all と同じ表記になりますが、意味は異なります。FortiOS が返した設定値をそのまま CIDR へ変換した結果であり、そのインターフェースへ全ネットワークが割り当てられているという意味ではありません。 今回はコードを変更せず、この表示のまま扱う方針としました。

2 つ目は、Default Gateway AcquisitionDistancePriorityDNS Server Override の 4 列です。今回の環境ではすべてのインターフェースで enable51enable と同じ値が並びました。FortiOS は Addressing Mode が static のインターフェースに対してもこれらの既定値を返すためです。

これらは「DHCP でアドレスを取得する際にどう振る舞うか」という設定値であり、実際にデフォルトゲートウェイを受け取ったかどうかを示すものではありません。 今回のスクリプトは設定情報の取得に限定しており、DHCP で実際に取得したゲートウェイ、現在のルーティングテーブル、リンク状態といった稼働ステータスは対象外です。設定値と稼働ステータスを取り違えないよう、シートを読むときに意識しておく箇所です。

Firewall_PoliciesPolicy_Resolved

Firewall_Policies シートは、Policy を GUI の一覧に近い形で並べたものです。今回は 2 件が出力されました。

Policy IDNameStatusSourceDestinationService
1Ubuntu_to_InternetenableallallALL
2Resolve_Demo_DisableddisableallMicrosoft Office 365Web Access

Policy 2 は、参照オブジェクトの展開動作を確認するために管理者が手動で追加した検証用の設定です。Python スクリプトは GET しか発行しないため、この Policy はスクリプトによって作成されたものではありません。通信への影響を避けるため statusdisable にしています。

config firewall policy
    edit 2
        set name "Resolve_Demo_Disabled"
        set srcintf "port1"
        set dstintf "port2"
        set srcaddr "all"
        set dstaddr "Microsoft Office 365"
        set action accept
        set schedule "always"
        set service "Web Access"
        set nat disable
        set status disable
    next
end

コマンドの構文は FortiOS 8.0.0 の CLI リファレンスで確認しています。

参照先: https://docs.fortinet.com/document/fortigate/8.0.0/cli-reference/333889629/config-firewall-policy

Policy_Resolved シートは、この Policy が参照しているオブジェクトを実値へ展開したものです。同じ 2 件が次のように出力されます。

Policy 1 の展開結果:

Source (Resolved)      : all=0.0.0.0/0
Destination (Resolved) : all=0.0.0.0/0
Service (Resolved)     : ALL=All protocols/services

Policy 2 の展開結果:

Destination (Resolved) : Microsoft Office 365=(login.microsoftonline.com=login.microsoftonline.com | login.microsoft.com=login.microsoft.com | login.windows.net=login.windows.net)
Service (Resolved)     : Web Access=(DNS=TCP/53; UDP/53 | HTTP=TCP/80 | HTTPS=TCP/443)

グループのメンバーは括弧で囲み、| で区切っています。1 つのサービス内で複数のポート定義を持つ場合は ; で区切られます。DNS が TCP/53; UDP/53 と表示されているのがその例です。区切り記号の意味が階層ごとに異なる点は、シートを読むときの前提として押さえておくと迷いません。

Policy 一覧を見ながらオブジェクト定義の画面を行き来する必要がなくなる点が、このシートを用意した理由です。 グループがネストしている構成では、展開が再帰的に行われるため差が大きくなります。

なお、コード上は Address Group と Service Group に加えて、VIP、VIP Group、Zone、SD-WAN Zone の展開も実装しています。ただし今回の検証環境ではこれらのオブジェクトを作成していないため、実機での動作は確認していません。 実装しているという事実と、実機で確認した範囲は分けて捉えてください。

参照解決の実装は次のような再帰構造になっています。

def resolve_address(name: str, trail: tuple[str, ...] = ()) -> str:
    if name in {"all", "all_ipv4"}:
        return "0.0.0.0/0"
    if name in trail:
        return f"循環参照({name})"
    if name in address_objects:
        return address_value(address_objects[name])
    group = address_group_objects.get(name)
    if group:
        return "(" + " | ".join(
            f"{member}={resolve_address(member, trail + (name,))}"
            for member in member_names(group.get("member"))
        ) + ")"
    validation.append({"severity": "WARN", ...})
    return f"未解決({name})"

trail に辿ってきたオブジェクト名を積み上げることで、グループが自分自身を含むような循環参照を検知します。解決できないオブジェクトは 未解決(名前) として出力し、あわせて Validation シートへ WARN を記録します。

Validation: 取得結果と参照解決の点検

Validation シートは、取得処理と参照解決の結果を 1 枚にまとめたものです。今回の実行では 22 件が記録され、すべて INFO でした。

内訳は、18 エンドポイントの取得結果が各 1 件ずつ、Policy の内容に関する注意喚起が 4 件です。

SeverityCategoryTargetMessage
INFOAPI取得InterfacesHTTP 200; API status=success
INFOAPI取得Firewall policiesHTTP 200; API status=success
INFOPolicy確認Policy 1送信元がallです
INFOPolicy確認Policy 1宛先がallです
INFOPolicy確認Policy 1ServiceがALLです
INFOPolicy確認Policy 2送信元がallです

このシートでは、スクリプトが実装している 18 エンドポイントの取得成否と、参照解決上の警告を確認できます。 すべて取得に成功していて、0 件のシートに「設定なし、または取得対象なし」と表示されている場合は、その取得対象で結果が返らなかったことを示します。

ただし、これは FortiGate の全設定に取得漏れがないことを保証するものではありません。個々の空欄セルについても、設定されていないのか、そのフィールドが出力対象に含まれていないのかまでは判別できません。あくまで、実装済みの取得対象の範囲で結果が揃っているかを確認するためのシートです。

Severity は 3 段階です。取得に成功すれば INFO、取得に失敗した場合は、そのエンドポイントが required 指定かどうかで ERROR と WARN に分かれます。required 指定は Interfaces、Configured static routes、Addresses、Address groups、Services、Service groups、Firewall policies の 7 件で、いずれかが失敗するとスクリプトは終了コード 1 を返します。

required_failures = [
    result
    for fetches in all_fetches
    for result in fetches.values()
    if result.endpoint.required and not result.ok
]

Excel 側では、Severity 列に条件付き書式を設定しています。WARN は淡い黄色、ERROR は淡い赤で塗られる作りです。ただし今回の検証では取得失敗を意図的に発生させていないため、この色分けが適用された状態は確認していません。 権限不足やネットワーク到達性の問題が起きた場合の見え方は、実環境での確認が必要です。

未設定のシートを省略しない理由

今回の環境では、次の 7 シートが 0 件でした。

ZonesConfigured_Static_RoutesPolicy_RoutesSDWAN_MembersSDWAN_RulesVIPsVIP_Groups

これらのシートは削除せず、「設定なし、または取得対象なし」という表示を残しています。シートが存在しないと、設定していないのか取得できなかったのかを後から判別できなくなるためです。Validation シートの取得結果と組み合わせることで、両者を区別できます。

SD-WAN 関連は、この考え方が分かりやすく現れた例でした。SDWAN_MembersSDWAN_Rules は 0 件ですが、SDWAN_Zones には既定の virtual-wan-link が 1 件、SDWAN_Health_Checks には Default_DNSDefault_Office_365 といった既定テンプレートが 5 件出力されています。つまり SD-WAN は未設定でありながら、既定オブジェクトは存在している状態です。この差は、シートを省略していたら見えませんでした。

なお SDWAN_Health_Checks シートの Server 列は、FortiOS が返す値にダブルクォートが含まれるため "www.office.com" のような表示になります。値をそのまま保持している結果です。

セキュリティ上の工夫と制限事項

GET のみで動作させるための設計

スクリプト側で講じた対策は次のとおりです。いずれもスクリプト実装上の制約であり、Administrator Profile の権限による強制ではありません。 今回の api_automation プロファイルには Firewall の書き込み権限が残っているため、別のツールから同じトークンを使えば設定変更は可能です。

対策実装
HTTP メソッドの固定api_get()method="GET" で固定。POST / PUT / PATCH / DELETE の実装なし
トークンの扱いgetpass で対話入力。コマンドライン引数、環境変数、ファイルのいずれにも保存しない
生レスポンスの非保存API レスポンスをそのまま書き出す経路が存在しない
出力項目の許可制各エンドポイントについて、シートへ出力するフィールドを明示的に列挙
識別子のマスクシリアル番号と、それに一致する既定ホスト名は先頭 4 文字のみ残す
ファイル権限出力ディレクトリ 0700、生成ファイル 0600
上書き防止出力先が存在する場合はエラー終了
接続先の検証https:// 以外の --base-url はエラー終了

機器の識別情報についても、レスポンスから取り込む項目を絞っています。

ENVELOPE_ALLOWLIST = ("serial", "version", "build")

FortiOS のレスポンスは results の外側にも機器情報を返しますが、そのうち取り込むのはこの 3 項目だけです。取り込んだシリアル番号は、Excel と JSON へ書き出す前にマスク処理を通します。

JSON スナップショットのメタデータにも、動作条件を記録しています。

{
  "exporter_version": "1.0.0",
  "fetched_at": "2026-08-25T15:28:50+09:00",
  "vdom": "root",
  "read_only": true,
  "raw_api_responses_saved": false
}

read_only: true は、このスクリプトが GET のみで動作したという実行条件を記録するための値です。 Administrator Profile の権限を強制するものでも、接続先アカウントが読み取り専用であることを証明するものでもありません。取得結果を後から検証する際は、この値ではなく、実行時のアカウント権限そのものを確認してください。

取得できる範囲の制限

このスクリプトで取得できるのは、実装した 18 エンドポイントの範囲に限られます。FortiGate のすべての設定を取得できるわけではありません。 具体的には、UTM プロファイル、IPsec VPN、SSL-VPN、ユーザー認証、ログ設定、HA 設定などは対象外です。設定のバックアップが必要な場合は、FortiGate の Configuration Backup 機能を使うことになります。

また、取得結果は次の要因で変わる可能性があります。

FortiOS のバージョン

エンドポイントのパスやレスポンスのフィールド構成はバージョン間で変わることがあります。今回の確認は FortiOS 8.0.0 build 167 の環境に限定したものです

Administrator Profile の権限

参照権限が与えられていないエンドポイントは取得できず、Validation シートに WARN または ERROR が記録されます

VDOM の構成

マルチ VDOM 環境では --vdom で指定した VDOM の設定だけが対象になります

稼働ステータスは対象外

繰り返しになりますが、このスクリプトが扱うのは設定情報です。DHCP で実際に取得したゲートウェイ、現在のルーティングテーブル、インターフェースのリンク状態、セッション数といった稼働中の状態は取得していません。Policy_Resolved シートの各行に付けている注意書きも、この点を意識したものです。

実際の転送経路はルーティング、Policy Route、SD-WAN Ruleも併せて確認

FortiGate では、ルーティング、Policy Route、SD-WAN Rule によって出口が選択され、その Incoming Interface と Outgoing Interface などに一致する Firewall Policy が評価されます。このシートは設定情報の一覧であり、現在のルーティングテーブルを含みません。そのため、実際の転送経路は別途確認する必要があります。 パラメータシートだけで転送経路を判断しないよう、シート上でも注記しています。

スクリプトの入手

作成したスクリプトは、GitHub Releases で公開しています。v1.0.0 の Release ページを開き、Assets にある Source code (zip) をダウンロードしてください。

FortiGate Parameter Sheet Exporter v1.0.0 をダウンロード

公開リポジトリには、Python スクリプト、README、MIT License を掲載しています。実機から出力した Excel、JSON、API トークン、実 Config は含めていません。

利用する際は、まず検証環境で動作を確認してから本番環境へ適用することをおすすめします。あわせて、Administrator Profile の権限を必要な参照権限へ絞り込み、Trusted Hosts を実行元のホストへ限定する運用を推奨します。

まとめ

FortiGate の REST API から設定情報を GET だけで取得し、Excel パラメータシートを生成する仕組みを作成しました。Policy が参照するオブジェクトを実値へ展開する Policy_Resolved と、取得結果を点検する Validation を組み合わせることで、パラメータシートの信頼性を読み手が判断できる形になります。

インポート機能については現時点で構想段階です。設定を書き戻す処理は、意図しない変更や設定の欠落が本番環境へ直接影響するため、エクスポートとは比較にならない慎重さが求められます。実装する場合は、差分プレビュー、ドライラン、変更前バックアップの自動取得、対象エンドポイントの限定といった仕組みを前提に設計する必要があると考えています。現段階では、エクスポート結果を運用の中でどう活かすかを固める段階です。

  • REST API の GET のみで 18 エンドポイントを取得し 21 シートを出力
  • API トークンは対話入力とし、ファイルや環境変数へ保存しない設計
  • 生レスポンスを保存せず、許可したフィールドのみを Excel と JSON へ出力
  • Policy の参照オブジェクトを実値へ展開する Policy_Resolved シート
  • 取得結果と参照解決を 1 枚で点検できる Validation シート
  • 設定情報と稼働ステータスを区別し、取得範囲を 18 エンドポイントに限定
  • インポート機能は未実装であり、今後の検討対象

以上、最後までお読みいただきありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

関西を拠点に活動する、現役インフラエンジニア。経験20年超。

大手通信キャリアにて、中〜大規模インフラ(ネットワーク・サーバ・クラウド・セキュリティ)の設計・構築およびプロジェクトマネジメントに従事。現場で直面した技術課題への対処や、最新の脆弱性情報への実務対応を、一次情報として発信しています。

保有資格
CCIE Lifetime Emeritus(取得から20年以上)/ VCAP-DCA / Azure Solutions Architect Expert

▶ 運営者プロフィール(詳細)

目次