Fortigateのコンサーブモードの通信影響

Fortigateのコンサーブモード conserve mode が実際の通信にどのような影響を与えるか？
勉強を兼ねて自宅構成で検証しました。


# Fortigateのコンサーブモードとは

公式ナレッジベースからの引用

https://community.fortinet.com/t5/FortiGate/Technical-Note-%E9%80%9A%E5%B8%B8%E3%81%AEConserve-mode%E3%81%A8Kernel-conserve-mode%E3%81%AE%E9%81%95%E3%81%84-Japanese/ta-p/197858


> **Conserve modeとはどのようなモードですか？**
>
> システム上で使用しているメモリ使用率が高まったときに、FortiGateは自己防御機能としてのConserve modeへ移行します。Conserve modeに移行したときには、FortiGateはメモリ領域を確保するための動作をとります。十分なメモリが回復された場合、システムはConserve modeを抜け(leaving/exiting)、自己防御機能を解除します。

メモリが少なくなってきた際の「節約モード」ということである。
また、以下では

https://community.fortinet.com/t5/FortiGate/Technical-Note-quot-Kernel-enters-conserve-mode-quot/ta-p/194115

>Conserve modeになった時は、Antivirusの機能とパフォーマンスが影響を受けます。詳細については下記Related ArticlesにリストされているKB"Antivirus failopen and optimization"を参照してください。

「アンチウイルス機能とパフォーマンスが影響を受ける」と記載がある。

コンサーブモードの概要や設定、具体的な影響は以下のAdminGuideにあるとおり。

https://docs.fortinet.com/document/fortigate/7.2.4/administration-guide/194558/conserve-mode

* メモリ利用率が **88%(=red)** を超過すると、コンサーブモード発動
* メモリ利用率が **95%(=extreme)** を超過すると、コンサーブモードのまま＋新規セッションをドロップ
* メモリ利用率が **82%(=green)** を下回れば、コンサーブモードが終了

これらはデフォルト値であり green < red < extreme になるように、70%~97% の間で設定可能である。

```:デフォルト値
config system global
    set memory-use-threshold-extreme 95
    set memory-use-threshold-red 88
    set memory-use-threshold-green 82
end
```

Proxy Inspection/Flow Inspectionのどちらも `fail-open` の動作を規定できると書いてあるが、それぞれでデフォルト動作が全く逆のようである。
* Proxy Inspectionのデフォルトはpassで、プロキシとしてのセキュリティチェックがバイパスされる。
* Flow Inspectionのデフォルトはdisableで、フローベースのセキュリティチェックするセッションがドロップされる。


また、システムがその時点でコンサーブモードになっているかどうかは、以下のコマンドで確認可能。

```:コンサーブモード確認コマンド
diagnose hardware sysinfo conserve
```

今回の検証では「透過モード」「フローベース」を想定し、コンサーブモードに突入したときの影響を調査する。
調査には、ESXiにデプロイするFortigateVMを利用するが、強制的にコンサーブモードへ遷移させるため、仮想マシンの搭載メモリを減らしており、完全に現実世界の動作を再現できていない可能性がある。


# 検証

https://community.fortinet.com/t5/Support-Forum/Setting-ICMP-UDP-Virtual-Session-Timeout/td-p/4512

によると、ICMPのセッションタイムアウトは60秒で固定とのこと。

これを利用して、以下のようにテストを実施する。

* 下流PC→Fortigate→上流PCにPINGを継続的に発行する
* コンサーブモード（red/extreme）を強制的に発動
* PINGの状態を確認
* PINGを停止し、セッションタイムアウト（60秒）を待つ or セッションを強制的にクリアする
* PINGを再開して状態を確認

公式ページには、

## redモードの動作

コンサーブモードはメモリを使いすぎると発動するが、なかなかそこまでメモリを使い切ることは難しい。
幸い、FortigateのVMで検証したため、仮想マシン自体のメモリを減らしたうえで、以下コマンドでスレッショルドを変更することでなんとかredモードにすることができた。


```:redモード強制発動
config system global
    set memory-use-threshold-red 71
    set memory-use-threshold-green 70
end
```

PINGを継続的に発行した状態でセッションテーブルを確認する。

まず、セッションフィルタでICMPだけに絞る。
このセッションフィルタは表示だけでなく、後述する `diag sys session clear`するときのフィルタでもあり、これをやらずにセッションクリアすると、管理用のsshセッションや、そのほかの全通信のセッションがクリアされるので、注意が必要。

```:セッションフィルタでICMPだけに絞る
diagnose sys session filter proto 1
```

```:セッションリストの表示
diagnose sys session list
```

PINGを継続的に発行しているため `expire=59` で常時更新されていることがわかる。
つまり、セッションが「落ちる」ことはない。

```:diag sys session list の出力
session info: proto=1 proto_state=00 duration=2201 expire=59 timeout=0 flags=00000000 socktype=0 sockport=0 av_idx=0 use=3
origin-shaper=
reply-shaper=
per_ip_shaper=
class_id=0 ha_id=0 policy_dir=0 tunnel=/ vlan_cos=0/255
state=may_dirty br
statistic(bytes/packets/allow_err): org=130320/2172/1 reply=130320/2172/1 tuples=2
tx speed(Bps/kbps): 59/0 rx speed(Bps/kbps): 59/0
orgin->sink: org pre->post, reply pre->post dev=4->5/5->4 gwy=10.254.10.11/10.254.10.35
hook=pre dir=org act=noop 10.254.10.35:1->10.254.10.11:8(0.0.0.0:0)
hook=post dir=reply act=noop 10.254.10.11:1->10.254.10.35:0(0.0.0.0:0)
misc=0 policy_id=4 auth_info=0 chk_client_info=0 vd=0
serial=00018f3b tos=ff/ff app_list=0 app=0 url_cat=0
sdwan_mbr_seq=0 sdwan_service_id=0
rpdb_link_id=00000000 rpdb_svc_id=0 ngfwid=n/a
npu_state=0x041001 no_offload
total session 1
```

pingを停止して60秒待つと以下のようになる。

```
fortigate # diagnose sys session list
total session 0

fortigate #
```

60秒待たなくても、手動でクリアすればセッションが消える。

```:セッションのクリア
diagnose sys session clear
```

この状態で、新規にPINGを打とうとしても通らない。
が、下流PCでパケットキャプチャしたところ、ARPリクエスト⇔ARPリプライは通っていることがわかった。
そのうえ、セッションリストにもICMPとして出てきている。

```:PINGは通らないのにセッションとしては確立しているらしい
diagnose sys session list
```

```:diag sys session list の出力
session info: proto=1 proto_state=00 duration=4 expire=55 timeout=0 flags=00000000 socktype=0 sockport=0 av_idx=0 use=3
origin-shaper=
reply-shaper=
per_ip_shaper=
class_id=0 ha_id=0 policy_dir=0 tunnel=/ vlan_cos=0/255
state=may_dirty ndr br
statistic(bytes/packets/allow_err): org=0/0/0 reply=0/0/0 tuples=2
tx speed(Bps/kbps): 0/0 rx speed(Bps/kbps): 0/0
orgin->sink: org pre->post, reply pre->post dev=4->5/5->4 gwy=10.254.10.11/10.254.10.35
hook=pre dir=org act=noop 10.254.10.35:1->10.254.10.11:8(0.0.0.0:0)
hook=post dir=reply act=noop 10.254.10.11:1->10.254.10.35:0(0.0.0.0:0)
misc=0 policy_id=4 auth_info=0 chk_client_info=0 vd=0
serial=00022135 tos=ff/ff app_list=0 app=0 url_cat=0
sdwan_mbr_seq=0 sdwan_service_id=0
rpdb_link_id=00000000 rpdb_svc_id=0 ngfwid=n/a
npu_state=0x041001 no_offload
total session 1
```

一時的にセッションフィルタをクリアして、他の通信もみてみると、わんさか出てくる。

```:他の通信セッションも成立しているもよう
diagnose sys session filter clear
diagnose sys session list
（いっぱいでてくる）
diagnose sys session filter proto 1
```

これは、FlowInspectionのデフォルト動作である「セキュリティチェックが必要な新規セッションをドロップ」と思われる。

FWポリシーに「Certificate-Inspection」だけが有効になっている通信は、セッションクリアしてもPING疎通可。
FWポリシーに「Webフィルタ」と「Certificate-Inspection」が有効になっている通信は、セッションクリア後にPING疎通不可。
ただし、ポリシーの順番で、「Webフィルタ」と「Certificate-Inspection」が先に来ている場合はPING疎通不可となった。

Certificate-Inspectionはフローベースのセキュリティチェックではないのだろうか？
ともかくWebフィルタがある場合は、ここに引っかかる。ということがわかった。
なお、FWポリシーの対象プロトコルはICMPとしたため「Webフィルタ」「Certificate-Inspection」の設定は何の意味もないが、デフォルト動作に引っ張られるようだ。

試しに `fail-open` を有効にして、セキュリティチェックをバイパスできるかをチェックしてみる。

```:fail-open設定
config ips global
  set fail-open enable
end
```

この設定をいれることで、コンサーブモード（red）による疎通不可の回避ができるようになった。が、おそらく、なんのフィルタもしないので、セキュリティ的にはザル状態である。


アンチウィルスを含め、そのほかのFWポリシーはFortiGuardに接続できなくて使えていないため、検証はしていない。


## extremeモードの動作

さらにスレッショルドを低く設定することで強制的にextremeモードを発動させて検証してみる。

```:extremeモード強制発動
config system global
    set memory-use-threshold-extreme 72
    set memory-use-threshold-red 71
    set memory-use-threshold-green 70
end
```

この場合はpingを発行し続けた状態で `diagnose sys session clear` してもセッションリストに載ってくることはなかった。通信セッションそのものがドロップされているためだと思われる。
セッションのexpireが続く限りはPINGは疎通し続けていた。

通信セッション自体が確立されないので、Proxy Inspection/Flow Inspectionのどちらであろうとも通信不能となる。たとえ `fail-open` 設定をしていたとしても、そもそも通信そのもののセッションが確立できずセキュリティフィルタまで到達しないため、通信は成立しない。


## マルチキャスト通信への影響

自宅では、VyosでVRRPを動作させてたり、GNS3のCiscoでHSRPを動作させたりしているので、HSRP/VRRPの通信状況も調査してみた。
HSRP/VRRPのどちらもマルチキャストを利用しており、マルチキャストポリシーで許可の設定としている。
red/extremeのどちらのコンサーブモードでもマルチキャスト通信はポリシーで許可した通りに通過しており、上流PCでは下流からのVRRPが、下流PCでは上流からのHSRPが到着していた。


# SNMPによるコンサーブモードの検知

`FORTINET-FORTIGATE-MIB` （FortigateのWebUIから取得できるファイル）を見ると、以下のものがコンサーブモードに関連しているものとみられる。

なお、これ以降のSNMP関連コマンドを利用するためにMIBファイルを `/usr/share/snmp/mibs` にそのままぶち込んでいる。（ちょっと横着してしまいました）

```:Polling
FORTINET-FORTIGATE-MIB::fgSIAdvMemEnterKerConsThrsh
FORTINET-FORTIGATE-MIB::fgSIAdvMemLeaveKerConsThrsh
FORTINET-FORTIGATE-MIB::fgSIAdvMemEnterProxyConsThrsh
FORTINET-FORTIGATE-MIB::fgSIAdvMemLeaveProxyConsThrsh
```

```:Trap
FORTINET-FORTIGATE-MIB::fgTrapAvEnterConserve
FORTINET-FORTIGATE-MIB::fgTrapAvBypass
```

ポーリングはいずれも「設定されている閾値」を取得するものであり、「現在コンサーブモードであるかどうか」を取得するものではないらしい。

PollingのOIDは`fgSysInfoAdvMem`配下に所属するらしいので、これを取得してみる。


```
$ snmptranslate -Tp FORTINET-FORTIGATE-MIB::fgSysInfoAdvMem
+--fgSysInfoAdvMem(1)
   |
   +-- -R-- Gauge     fgSIAdvMemPageCache(1)
   +-- -R-- Gauge     fgSIAdvMemCacheActive(2)
   +-- -R-- Gauge     fgSIAdvMemCacheInactive(3)
   +-- -R-- Gauge     fgSIAdvMemBuffer(4)
   +-- -R-- Gauge     fgSIAdvMemEnterKerConsThrsh(5)
   +-- -R-- Gauge     fgSIAdvMemLeaveKerConsThrsh(6)
   +-- -R-- Gauge     fgSIAdvMemEnterProxyConsThrsh(7)
   +-- -R-- Gauge     fgSIAdvMemLeaveProxyConsThrsh(8)

$ snmpwalk -v 2c -c ro fortigate.prosper2.net FORTINET-FORTIGATE-MIB::fgSysInfoAdvMem
FORTINET-FORTIGATE-MIB::fgSIAdvMemPageCache.0 = Gauge32: 502328 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemCacheActive.0 = Gauge32: 166144 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemCacheInactive.0 = Gauge32: 302628 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemBuffer.0 = Gauge32: 72 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemEnterKerConsThrsh.0 = Gauge32: 735680 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemLeaveKerConsThrsh.0 = Gauge32: 685520 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemEnterProxyConsThrsh.0 = Gauge32: 735680 KB
FORTINET-FORTIGATE-MIB::fgSIAdvMemLeaveProxyConsThrsh.0 = Gauge32: 685520 KB
```

コンサーブモード状態を確認するコマンドで閾値が確認できる。

```
fortigate # diagnose hardware sysinfo conserve
memory conserve mode:                        off
total RAM:                                          816 MB
memory used:                                        604 MB   74% of total RAM
memory freeable:                                    140 MB   17% of total RAM
memory used + freeable threshold extreme:           775 MB   95% of total RAM
memory used threshold red:                          718 MB   88% of total RAM
memory used threshold green:                        669 MB   82% of total RAM
```

トラップのOIDは以下のようになっていた。

```:TrapのOID
$ snmptranslate -On FORTINET-FORTIGATE-MIB::fgTrapAvEnterConserve
.1.3.6.1.4.1.12356.101.2.0.605

$ snmptranslate -On FORTINET-FORTIGATE-MIB::fgTrapAvBypass
.1.3.6.1.4.1.12356.101.2.0.606
```


redモードに強制的に遷移したときのトラップは以下のように受信された。

```
$ sudo tcpdump -Z root -i ens192  udp  port 162 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
13:39:17.528180 IP 10.254.254.193.162 > 10.254.10.251.162:  C="ro" Trap(89)  .1.3.6.1.4.1.12356.101.1.30 10.254.254.193 enterpriseSpecific s=605 309758 .1.3.6.1.4.1.12356.100.1.1.1.0="FGVMEVYY516CRLD9" .1.3.6.1.2.1.1.5.0="fortigate"
13:39:17.528319 IP 10.254.254.193.162 > 10.254.10.251.162:  C="ro" V2Trap(113)  .1.3.6.1.2.1.1.3.0=309758 .1.3.6.1.6.3.1.1.4.1.0=.1.3.6.1.4.1.12356.101.2.0.605 .1.3.6.1.4.1.12356.100.1.1.1.0="FGVMEVYY516CRLD9" .1.3.6.1.2.1.1.5.0="fortigate"
^C
2 packets captured
2 packets received by filter
0 packets dropped by kernel
```

v1/v2cが同時に発出されているため、このようになっているが、要するに `.1.3.6.1.4.1.12356.101.2.0.605` つまり `FORTINET-FORTIGATE-MIB::fgTrapAvEnterConserve`が送出されていることがわかる。

なお、コンサーブモードから復旧した場合のトラップは存在しないようだった。



# 結論

検証した環境である「透過モード」「フローベース」では `fail-open`設定をデフォルト（＝disable）としている場合は、red/extremeのどちらのコンサーブモードでも、セキュリティチェックを伴う通信は不可となることがわかった。

また、マルチキャストはコンサーブモードかどうかにかかわらず、通信可能であることがわかった。

以下、いいわけですが
* 限定的な構成（透過モード＆フローベース）の１種類しか検証してないこと
* 実機ではなくVMでの検証であること
* ライセンスがトライアル用であること
* 搭載メモリを意図的に減少させていること
* コンサーブモード自体の動作が不安定な可能性があり、仕様通りの動作か不明であること

ということから、あくまで「いち検証の結果」ということで終了としたいと思います。

「`fail-open`を期待して、コンサーブモードになるような仕掛けでセキュリティ的にザル状態にさせる。っていう攻撃が～～」みたいな記述がナレッジベースだかフォーラムにあって、おもわず「なるほどー」と思ってしまいました。
何を優先させるか？みたいなポリシーはあると思いますが、こういうのを見てしまうと `fail-open` は他の手段でどうにもならなかったときの最後の手段として考えたいですね。

# 参考


https://community.fortinet.com/t5/FortiGate/Technical-Note-quot-Kernel-enters-conserve-mode-quot/ta-p/194115

https://community.fortinet.com/t5/FortiGate/Technical-Tip-Conserve-mode-changes/ta-p/198502


https://community.fortinet.com/t5/FortiGate/Technical-Tip-IPS-socket-size-and-fail-open/ta-p/191254