FortiGateVMをHA構成でAWS上にデプロイする

# はじめに
AWSではEC2インスタンスとして利用できる仮想ルータや仮想ファイアウォール製品がサードパーティベンダから提供されており、AWS MarketPlaceから利用することが可能です。この記事では仮想ファイアウォールであるFortiGateVMをHA構成でAWS上にデプロイする際のナレッジについて紹介していきたいと思います。
# VPCを作成
今回は以下のトポロジーを想定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/a8698b3f-0b44-4bd2-880d-88f2557e637c.png)
FortiGateVMは以下の役割を持つインターフェースを必要とします。EC2インスタンスを起動する前に必要なサブネット数をあらかじめ確認し、作成しておきます。なお、AZ冗長を取るため２つのAZに作成します。

#### 1. パブリックサブネット
Elastic IPを持たせ、インターネットからのアクセスを受けるインターフェースを設置します。ブランチからのIPsecVPNもこのインターフェースで終端します。
#### 2. プライベートサブネットA
踏み台サーバ（このサブネットである必要はない）、業務サーバ、他のVPCとの接続用にTransit Gateway Attatchmentを設置します。
#### 3. HAサブネット
冗長化（HA）されたFortiGateVMに必要なハートビートを送受信するHAインターフェースを設置します。
#### 4. Managementサブネット
GUIアクセス、SNMPなどの管理用に作成するManagementインターフェースを設置します。AWS上でHA構成をとる場合にAWS APIを利用しますが、APIをキックするSourceとなるインターフェースでもあります。
#### 5. プライベートサブネットB
VRFなどでマルチテナントを実現したい場合を想定した２つ目のプライベートサブネットです。分割したいテナント分だけ設置します。

# １台目のFortiGateVM(EC2)を作成
HA構成のPrimary機となるFortiGateVMをEC2でデプロイします。マシンイメージは「Fortinet FortiGate Next-Generation Firewall」を選択します。
ライセンスがある場合はBYOLのものを指定してください。
インスタンスタイプは作成するインターフェースまで対応しているC5.4xlarge（8NICsまで対応可能）などが必要です。

### （参考）FortiGateVM on AWSのインスタンスタイプについて
・Compute最適化タイプで最大15までENIを作成できる。
・FortiGateではトラフィック転送用NICのほかに管理用とHA用のNICも必要なため、テナント向けに確保できるENI数は各インスタンスタイプ-2までとなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/6e3a2174-72cf-46c5-8eeb-4949129dd0dc.png)

https://docs.fortinet.com/document/fortigate-public-cloud/7.6.0/aws-administration-guide/261537

# EIPを作成
EIP(Elastic IP)アドレスを割り振り、FortiGateVMのパブリックサブネットに設置したENIへ関連付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/2b1560e7-873e-4a50-83ab-01534d2fa7a9.png)
なお、フェイルオーバーをAWSのAPIで作動させるためにはManagementポートからのインターネットアクセスも必要になりますので、EIPを各FortiGateVMにアサインしましょう。

# セキュリティグループを作成
送信元IPアドレスを踏み台サーバなどに制限したHTTPSやSSH許可ルールを作成し、FortiGateVMのGUIやSSHにアクセスできるようにします。
マシンイメージでFortiGateを指定するとEC2起動時のセキュリティグループにデフォルトで設定されているプロトコルを利用するとよいでしょう。
この後インターネットからのIPsecVPNを張るときはこのセキュリティグループを編集し、特定または不特定のグローバルIPアドレスからのESPや、必要に応じて500/udpと4500/udpを許可します。Transit Gateway ConnectとBGP over GREを行う場合はTransit Gateway CIDRからのGREを許可します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/31b56299-47dd-45a1-a405-d73f0cd1aa9a.png)

# ソース/宛先チェックを無効に変更
FortiGateVMがパケットを転送できるようにするため、EC2インスタンスのアクション⇒ネットワーキングからソース/宛先チェックを変更⇒停止を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/a4d5cadb-833e-4685-9805-2d6d66a0e477.png)

# HAをAWSのAPIで実行するためのIAMロールを作成する
FortiGateVMのHA機能はAWSのAPIで実装されています。PrimaryのFortiGateVMが停止すると、Activeに昇格したFortiGateVMのport1にEIPを付け替えたり、ルートテーブルにおいては、停止したFortiGateVMが持っていたENIをターゲットとするルートをActiveに昇格したFortiGateVMの持つENIに変更したりすることでHAを実現します。
APIにアクセスするためのIAMロールは以下の許可ポリシーを持つ必要があります。
"ec2:Describe*",
"ec2:AssociateAddress",
"ec2:AssignPrivateIpAddresses",
"ec2:UnassignPrivateIpAddresses",
"ec2:ReplaceRoute"
作成したIAMロールをFortiGateVMに割り当てます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/9e737a3c-e4c0-4836-b78b-de1c9348588a.png)

# 踏み台サーバからFortiGateVMへログインする
デプロイ後直後はPort1にアサインしたプライベートIPアドレスに対してVPC内の踏み台サーバからブラウザでアクセスします。
たまにパブリックIPアドレスに対してインターネットからアクセスするような手順がありますがこちらのほうがおすすめです。初期パスワードはインスタンスIDになっており、ログイン後すぐにパスワード変更が必要です。BYOLの場合はログイン後にライセンスアップロード画面が表示されますので、ドラッグアンドドロップで適用しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/d710133a-ce5d-4dc5-98cd-ad812174d568.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/4697a016-8e0c-40cf-87fd-b2dfa5e21f5e.png)

# FortiGateVMの初期セットアップ
自動アップデートや紹介動画などを経てログインが完了します。
AWSからDHCPでアサインされたIPアドレスが想定通りになっているか確認しましょう。ダッシュボードのステータス画面でEIPを使用してFortinetのライセンスサーバへ通信が出来ていることも確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/81847581-3093-40c6-9d10-c845ce1a83b5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/a7b07d60-929a-4639-984a-b7a1a151cce3.png)

# 2台目のFortiGateVM（EC2）を作成
HA構成のSecondary機となる２台目のFortiGateVMをEC2でデプロイします。IPアドレス以外は1台目と同じ手順です。セキュリティグループとIAMロールは１台目と共用でよいです。
１台目と２台面のFortiGateVMにHA用のConfigurationを投入します。このConfigurationを投入した時点で即Primary機への同期が始まる挙動をしていたので、安全のためにPrimaryとSecondary機の通信ができない状態（１台ずつ起動している状態）で作業をしたほうが良いと思いました。
#### 1台目（Primary機）
~~~
config system ha
    set group-name HA
    set mode a-p
    set password *****
    set authentication enable
    set hbdev port3 50
    set session-pickup enable
    set ha-mgmt-status enable
    config ha-mgmt-interfaces
        edit 1
            set interface port4
            set gateway 10.0.4.1
        next
    end
    set override disable
    set priority 255
    set unicast-hb enable
    set unicast-hb-peerip 10.0.13.11
end
config system vdom-exception
    edit 1
        set object system.interface
    next
    edit 2
        set object router.static
    next
    edit 3
        set object vpn.ipsec.phase1-interface
    next
    edit 4
        set object vpn.ipsec.phase2-interface
    next
end 
~~~

#### 2台目（Secondary機）
~~~
config system ha
    set group-name HA
    set mode a-p
    set password *****
    set authentication enable
    set hbdev port3 50
    set session-pickup enable
    set ha-mgmt-status enable
    next
    config ha-mgmt-interfaces
        edit 1
            set interface port4
            set gateway 10.0.14.1
        next
    end
    set override enable
    set priority 1
    set unicast-hb enable
    set unicast-hb-peerip 10.0.3.11
end
config system vdom-exception
    edit 1
        set object system.interface
    next
    edit 2
        set object router.static
    next
    edit 3
        set object vpn.ipsec.phase1-interface
    next
    edit 4
        set object vpn.ipsec.phase2-interface
    next
end 
~~~
このConfigurationを投入し、2台の間で同期が完了すればFortiGateVMのHA構成は完成です。必要な定義を設定した後にHAを組んでも、HAを組んでから定義してもいいです。

# フェイルオーバーのテスト
HA構成のForitgateVMのフェイルオーバーが問題なく作動するかテストします。Secondary機のDebugを有効にしておき、Primary機のEC2インスタンスを停止します。
~~~
FGVM16TM25000041 # HA event
HA state: primary
awsd get iam role XXXXX
awsd checking ha status for vdom root
awsd checking elastic ip for port1
awsd associate elastic ip xx.xxx.xxx.xxx to 10.0.11.11 of eni eni-xxxxxxxxxxxxxxxxx
awsd associate elastic ip xx.xxx.xxx.xxx successfully
awsd checking elastic ip for port2
awsd checking elastic ip for port5
send_vip_arp: vd root primary 1 intf port1 ip 10.0.11.11
send_vip_arp: vd root primary 1 intf port2 ip 10.0.12.11
send_vip_arp: vd root primary 1 intf port5 ip 10.0.15.11
send_vip_arp: vd root primary 1 intf fortilink ip 10.255.1.1
send_vip_arp: vd root primary 1 intf Lo ip 10.200.1.11
send_vip_arp: vd root primary 1 intf tgwc ip 169.254.101.1
send_vip_arp: vd root primary 1 intf tgwc12 ip 169.254.102.1
awsd checking route table rtb-xxxxxxxxxxxxxxxxx
awsd update route table rtb-xxxxxxxxxxxxxxxxx, replace route of dst 172.16.0.0/16 to eni-xxxxxxxxxxxxxxxxx
awsd update route successfully
~~~
EIPの付け替えやルートテーブルの編集が成功しました。なおこの時FortiGateVMにはブランチへのVPNやTransit Gateway ConnectへのBGP over GREを張っていたのですが、それぞれを利用した通信は即Secondary機を使用した経路に切り替わっていました。

（余談）以下URLを参考に構築していたところ、AWS APIにうまく通信ができず手こずってしまいました。
https://docs.fortinet.com/document/fortigate-public-cloud/7.6.0/aws-administration-guide/229470/deploying-fortigate-vm-active-passive-ha-aws-between-multiple-zones
以下、AWSAPIによるEIPの付け替えがうまく動作しなかったときのログです。インターネットへのAPIを叩いていますがsyn/ackのレスポンスが来ていません。
~~~
FGVM16TMxxxxxxxx # diagnose sniffer packet any "net 99.0.0.0 mask 255.0.0.0"
Using Original Sniffing Mode
interfaces=[any]
filters=[net 99.0.0.0 mask 255.0.0.0]
16.046666 10.0.14.11.7198 -> 99.77.62.124.443: syn 3684962678
16.046666 10.0.14.11.7198 -> 99.77.62.124.443: syn 3684962678
17.087851 10.0.14.11.7198 -> 99.77.62.124.443: syn 3684962678
17.087851 10.0.14.11.7198 -> 99.77.62.124.443: syn 3684962678
19.177848 10.0.14.11.7198 -> 99.77.62.124.443: syn 3684962678
~~~
原因は、Managementポートからのインターネットアクセスが必要という記載を見逃していたからでした。当初、EIPをアサインしたport1からAPIを叩くものと勘違いしており、Managementポートのport4にEIPをアサインするとうまくいきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3731465/6665b658-e666-4a59-97f7-86c6cb26cd4e.png)
~~~
FGVM16TMxxxxxxxx # diagnose sniffer packet any "net 99.0.0.0 mask 255.0.0.0"
Using Original Sniffing Mode
interfaces=[any]
filters=[net 99.0.0.0 mask 255.0.0.0]
157.884174 10.0.14.11.20658 -> 99.77.60.113.443: syn 923583969
157.884174 10.0.14.11.20658 -> 99.77.60.113.443: syn 923583969
157.884348 99.77.60.113.443 -> 10.0.14.11.20658: syn 3656226348 ack 923583970
157.884348 99.77.60.113.443 -> 10.0.14.11.20658: syn 3656226348 ack 923583970
157.884367 10.0.14.11.20658 -> 99.77.60.113.443: ack 3656226349
157.884367 10.0.14.11.20658 -> 99.77.60.113.443: ack 3656226349
157.884711 10.0.14.11.20658 -> 99.77.60.113.443: psh 923583970 ack 3656226349
157.884711 10.0.14.11.20658 -> 99.77.60.113.443: psh 923583970 ack 3656226349
~~~

# Tips
- コンフィグの初期化
初期化したい場合は、ハードウェアと異なり物理的なリセットボタンはありませんので、CLIログインができる状態であれば「execute factoryreset」コマンドを実行します。AWS上でEC2を起動する際にアサインしたポートの数やサブネットに対応するIPアドレスなどはそのまま、Configurationだけ初期状態に戻ります。（再SSHする際にWARNINGエラーが出たら、アクセス元PCのファイルの中身を適切に削除してください）

- ライセンスリホスト
BYOLの場合ライセンスリホストも可能ですが、EC2インスタンスを終了し新たなEC2インスタンスにリホストする場合はFortinet社ライセンスサーバ上に記録が残っている場合があるため、半日程度待つ必要があります。

# まとめ
FortiGateVMをHA構成でAWS上にデプロイする際のナレッジについて紹介しました。EIPをManagementポートに必ず割り当てないといけないのか、代替手段があるかはまだ調査しておりませんが、前者の場合HAに必要なEIPが3つになりますのでコスト面で多少デメリットになるかなと思いました。なお、FortiGateVMをActive-StandbyでHA構成を組むか、Active-Activeで構成するかはそれぞれに特徴が異なり、設計思想次第になりますのでご注意ください。