AWS Transit Gateway ConnectをFortiGate-VMとの組み合わせで構築してみた

#はじめに
AWS Transit GatewayとSD-WANを簡単に接続することができる「AWS Transit Gateway Connect」を触ってみました。アプライアンス(SD-WAN)側はFortiGate-VMを使用しました。
なお、AWS側の設定は、以下のドキュメントを参考にしています。

https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/tgw-connect.html

https://aws.amazon.com/jp/blogs/networking-and-content-delivery/simplify-sd-wan-connectivity-with-aws-transit-gateway-connect/

# AWS Transit Gateway Connect
詳しくは上記リンク先通りですが、各社SD-WANとTransit Gatewayを簡単に接続できるようにしたものです。
SD-WAN側はVPCへ仮想アプライアンスを設置し、仮想アプライアンスとTransit Gatewayを今回の機能であるConnectアタッチメントを使用して接続します。
仮想アプライアンスとTransit Gateway間は、IPSecではなく、GREを使用します。ルーティングプロトコルはBGPのみサポートします。
# FortiGate-VM
Firewall製品で有名なFortinet社ForiGateのVM版となります。AWSではMarketPlaceを通じて利用することができます。課金は従量制とBYOLが用意されています。
今回使用するものは以下となります。

https://aws.amazon.com/marketplace/pp/B00PCZSWDA

# 環境

- 構成
メインは黄色枠の「Transit Gateway Connect」ですが、FortiGate間のVPNを絡めた、一般的であろう構成にしてみました。
構築後、ServerA,B～ServerC間でPingによる疎通ができることが確認できればOKとします。
※FortiGate-VMのPublic addressは構築中にElastic IPを取得するため、ここでは未確定としています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/95227d30-8a57-3970-033d-230d90b636a8.png)

- バージョン等
    - FortiGate-VM: 7.0.0
    - Server A,B,C: Amazon Linux 2
    
# 構築

#### VPC,Transit Gateway,EC2の作成　※Transit Gateway Connect周り, FortiGate-VM除く
本題では無いため、CloudFormationで一気に作成します。
※Transit Gateway Connect関連とFortiGate-VMは後ほど手動で構築します。
※構築後に稼働確認を行うため、各ServerへSession Managerを使用して接続できるようにCloudFormationへ必要な設定を組み込んでおきます。
※AWS CLIを使用するため、事前にセットアップしておきます。

- バージニア

CloudFormationテンプレートは最後の補足を参照。

```
aws cloudformation validate-template --template-body file://010-UsVpcEc2.yml

aws cloudformation deploy --stack-name handson-tgw-connect --template-file 010-UsVpcEc2.yml --region us-east-1 --capabilities CAPABILITY_NAMED_IAM
```

- 東京

CloudFormationテンプレートは最後の補足を参照。

```
aws cloudformation validate-template --template-body file://020-JpVpcEc2.yml

aws cloudformation deploy --stack-name handson-tgw-connect --template-file 020-JpVpcEc2.yml --region ap-northeast-1 --capabilities CAPABILITY_NAMED_IAM
```


#### (バージニア)Transit GatewayへCIDR(192.0.2.0/24)の割り当て
Transit Gateway Connectは、割り当てたCIDRからGREで使用するアドレスを割り当てます。
[VPC]-[TRANSIT GATEWAY]-[Transit Gateway]から上記で作成済みのTGWを選択→[Modify]→[Transit Gateway CIDR blocks]の順で進み「192.0.2.0/24」を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/07d13302-c70f-4757-491d-69404ef462da.png)

#### (バージニア)各VPCへTransit Gateway向きのルートの追加
[VIRTUAL PRIVATE CLOUD]-[ルートテーブル]から、以下のように各VPCのルートテーブルへ上記で作成済みのTGWをターゲットとしたルートを追加します。

- VPC A
上記で作成済みのTGWをターゲットとしたデフォルトルートを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/69ca0ebf-258b-6fd1-c1d3-8954b682f49d.png)

- VPC B
上記で作成済みのTGWをターゲットとしたデフォルトルートを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/770871f5-0b62-5f3a-e039-d5e675580cd2.png)

- Connect VPC
上記で作成済みのTGWをターゲットとしたVPC A,B及び「192.0.2.0/24」宛てのルートを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/aee1f2ff-0665-5ac1-0b78-5e194cf4ff94.png)

#### (バージニア)Transit Gateway Connectの作成
[VPC]-[TRANSIT GATEWAY]-[Transit Gateway接続]から[Create Transit Gateway Attachment]をクリックし以下のように設定します。

| 項目 | 設定内容 |
| ---- | ---- |
| Transit Gateway ID | 上記で作成済みのTGW |
| Attachment type | Connect |
| Attachment name tag | 任意 |
| Transport Attachment ID  | tgw_handson_us-connectvpc  ※FortiGate-VMが存在するVPC |
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/32708b34-8895-0131-b783-e3f3a6eca558.png)
[VPC]-[TRANSIT GATEWAY]-[Transit Gateway接続]から上記のConnect Attachmentを選択し、[Connect peers]から[Create Connect peer]をクリックします。
Connect Peerは以下のように設定します。
※「Transit Gateway GRE address」は未入力の場合、自動でアサインされます。
※BGPアドレスは「BGP inside CIDR blocks」から3つ自動でアサインされます。
　挙動としては、Peer GRE address、Transit Gateway BGP 1 address、Transit Gateway BGP 2 addressの順にアサインされるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/5a7187a0-9205-1013-d4f7-8c9f9e7f69eb.png)

#### (バージニア)FortiGate-VMの作成
[EC2]-[インスタンス]-[インスタンス]から[インスタンスを起動]をクリックします。
[AWS Marketplace]を選択し"fortigate"を検索後「Fortinet FortiGate Next-Generation Firewall」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/decc919f-2765-22e5-2174-ca73f878a52c.png)
[Continue]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/5677182e-f58e-5c5a-2c2b-b0941127b15b.png)
「ステップ 2: インスタンスタイプの選択」では、[t2.small]を選択し、次へ進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/06718deb-3367-b61c-a32a-6524626a23a9.png)
「ステップ 3: インスタンスの詳細の設定」では、[ネットワーク]は「tgw_handson_us-connectvpc」を選択、[ネットワークインターフェース]-[eth0]-[プライマリIP]は「172.31.0.11」と入力し、次へ進みます。
※上記以外はデフォルトのままで問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/9e34ead4-1a58-7db0-d8e0-2f146de7ba50.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/60b2e7ac-34b3-74b6-21b7-636da0ef5bba.png)
「ステップ4:ストレージの追加」は何もせず、次へ進みます。
「ステップ 5: タグの追加」では、キーと値へ識別し易い名称を入力し、次へ進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/74369651-d209-ea06-08b4-016224728ba0.png)
「ステップ 6: セキュリティグループの設定」では、以下のように設定し、[確認と作成]へ進みます。

| 操作 | タイプ | プロトコル | ポート範囲 | ソース | 補足 |
| ---- | ---- | ---- | ---- | ---- | ---- |
| 変更 | SSH | TCP | 22 | 管理者オフィスのIP | |
| 変更 | HTTP | TCP | 80 | 管理者オフィスのIP | |
| 変更 | HTTPS | TCP | 443 | 管理者オフィスのIP | |
| 削除 | カスタムTCP | TCP | 541 | 0.0.0.0/0 | 今回未使用 |
| 削除 | カスタムTCP | TCP | 3000 | 0.0.0.0/0 | 今回未使用 |
| 削除 | カスタムTCP | TCP | 8080 | 0.0.0.0/0 | 今回未使用 |
| 新規 | カスタムプロトコル | 47 | all | 0.0.0.0/0 | TGW ConnectとのGRE |
| 新規 | カスタムプロトコル | 50 | all | 0.0.0.0/0 | 東京のFortiGate-VMとのIPSecVPN - ESP |
| 新規 | カスタムUDP | UDP | 500 | 0.0.0.0/0 | 東京のFortiGate-VMとのIPSecVPN - IKE |
| 新規 | カスタムUDP | UDP | 4500 | 0.0.0.0/0 | 東京のFortiGate-VMとのIPSecVPN - NAT-T |
| 新規 | すべてのICMP | ICMP | 0 - 65535 | 10.0.0.0/8 | 疎通確認用 |
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/92295a8c-b494-06e9-36c0-9c81579b0a31.png)

[起動]をクリックします。キーペアは[キーペアなしで続行]とし、[インスタンスの作成]をクリックします。
[EC2]-[ネットワーク&セキュリティ]-[Elastic IP]から「Elastic IPアドレスの割り当て」を行い、上記のFortiGate-VMへ関連付けを行います。

ブラウザから「https\://FortiGate-VMのパブリックIP」もしくは「https\://パブリックDNS」へアクセスします。ブラウザによっては(自己署名のため)「潜在的なセキュリティリスク」と表示しますが、そのまま続行します。

[Accept]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/cf094404-2351-0b14-ce80-6bc87ffb6854.png)
[Username]は「admin」、「Password」は「インスタンスID」を入力し[Login]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/2cbffb35-56d2-6bdd-d953-1bd4e8ec8c2c.png)
[Old Password]は「インスタンスID」、「New Password」「Confirm Password」は「任意のパスワード」を入力し[OK]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/9720945e-5f21-4008-612c-e7b25336327c.png)
再度、認証画面が表示するため、「admin」「任意のパスワード」を入力します。

[Begin]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/7521960d-5b04-4004-b236-52cc06068c4e.png)
[Hostname]へ「FortiGate-VM-US」を入力し、[OK]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/baf3a122-cf22-d904-716e-a94361e804c7.png)
そのまま[OK]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/b52ae45c-4c80-707e-43ff-7c4f83d5e3cc.png)
[Don't show again]へチェックを入れ、[OK]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/c6db67e8-917d-b2ca-99dc-680979a6b9f2.png)
GREの設定を行います。CLIからのみ設定が可能です。
右上の「>_」をクリックし、CLI Consoleを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/20e09210-bde6-0256-d071-b8b2c0c8d007.png)
GREトンネル及びTunnelインタフェースの設定を行います。

```
config system gre-tunnel
    edit "tunnel1"
        set interface port1
        set local-gw 172.31.0.11
        set remote-gw 192.0.2.1
    next
end
config system interface
    edit "tunnel1"
        set ip 169.254.10.1 255.255.255.255
        set allowaccess ping
        set type tunnel
        set remote-ip 169.254.10.2 255.255.255.255
        set interface port1
    next
end
```
設定後、右上の[x]をクリックし、CLI Consoleを閉じます。
[Network]-[Interfaces]から「tunnel1」が作成されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/05c4267e-f33b-36c3-7854-225294b23e67.png)
BGPの設定を行います。
東京のサブネットをTGWへアドバタイズするためにASパスプリペンドの設定を行います。
ASパスプリペンドの設定が無いと、TGW側でサブネット情報を受信してもTGWのルートテーブルへ反映しないようです。

https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/tgw-connect.html

[Network]-[Routing Objects]から[Create New]-[Prefix List]の順に選択します。
Prefix Listは以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/18328153-9187-d0f3-6616-fbe49877234a.png)
同様に[Create New]-[Route Map]の順に選択します。
Route Mapは以下のように設定します。
[Match IP address]は上記Prefix Listを選択、[Set AS path]は「99」を入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/965919c6-521e-8f6a-a751-869aa1603bb9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/b13e89a4-0fd7-da24-e3fa-1ef86ca8de5a.png)

[Network]-[BGP]から以下のように設定します。
「Local AS」「RouterID」「Neighbors」「Networks」を設定します。
[Neighbors]は「IP：169.254.10.2」「Remote AS：64512」「Route map out：as-path-prepend-route-map」を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/b5e8b3f2-9ec3-5e57-54ee-f12bc99bb961.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/8f7be9d8-9622-a631-a728-76d24e77676c.png)

(補足)
上記設定後に再度何らかの理由でRouteMapを変更した場合は、設定を反映させるためにCLI ConsoleからBGPハードクリアを行います。

```
execute router clear bgp all
```

BGPの状態を確認します。
Next Hopに「169.254.10.2」が表示していればTransit Gateway ConnectとBGPのコネクションが確立できています。

```
# get router info bgp network
VRF 0 BGP table version is 2, local router ID is 169.254.10.1
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
              S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight RouteTag Path
*>i10.1.0.0/16      169.254.10.2           100    100      0        0 i <-/1>
*>i10.2.0.0/16      169.254.10.2           100    100      0        0 i <-/1>
*> 10.99.0.0/16     0.0.0.0                       100  32768        0 i <-/1>
*>i172.31.0.0       169.254.10.2           100    100      0        0 i <-/1>

Total number of prefixes 4
```

#### (バージニア)確認1
[VPC]-[TRANSIT GATEWAY]-[Transit Gateway接続]から"tgw-connect01"を選択し、[Connect peers]から上記で作成したConnect peerから[Transit Gateway BGP 1 Status]が「UP」であることを確認します。
※「Transit Gateway BGP 2 Status」はFortiGate-VM側で設定していないため「DOWN」のままで問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/d81ff53f-160e-02f7-7199-5cb6f2cc827e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/a8b6b638-158d-6e14-c138-96515b436d41.png)

[VPC]-[TRANSIT GATEWAY]-[Transit Gatewayルートテーブル]から今回作成したルートテーブルを選択し、[Routes]をクリックします。
「10.99.0.0/16」のルートがあることを確認します。FortiGate-VMからBGPでルートを正常に受信できていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/1da5971d-588e-ab28-bd34-a8dc8dcfe15a.png)

#### (バージニア)VPCへFortiGate-VM宛てのルートの追加
[VIRTUAL PRIVATE CLOUD]-[ルートテーブル]から「tgw_handson_us-connectvpc-public」を選択し、ルートを追加します。
上記で作成したFortiGate-VMをターゲットとした東京宛てのルートを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/ba915137-16b3-7ae4-43ac-e936a8f623f9.png)

#### (バージニア)FortiGate-VMの「送信元/送信先チェック」の無効化
[EC2]-[インスタンス]-[インスタンス]から「FortiGate-VM-US」を選択し、右クリック[ネットワーキング]-[ソース/宛先チェックを変更]をクリックします。「送信元/送信先チェック中」の「停止」へチェックを入れ[保存]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/917b8e5b-bd81-6515-14da-5c48b3aa3c1c.png)

#### (東京)FortiGate-VMの作成
上述の「(バージニア)FortiGate-VMの作成」を参照し、ForiGate-VMを作成します。
以降は(バージニア)と異なる箇所のみ記載します。

「ステップ 3: インスタンスの詳細の設定」では、[ネットワーク]は「tgw_handson_jp」を選択、[ネットワークインターフェース]-[eth0]-[プライマリIP]は「10.99.1.11」と入力し、次へ進みます。
※上記以外はデフォルトのままで問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/565ab81f-9c2e-115f-73cd-f78575806cd9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/a3a86ab1-55c3-2de6-6003-e205f07308f4.png)
「ステップ 5: タグの追加」では、キーと値へ識別し易い名称を入力し、次へ進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/d4bb63a7-dacc-745b-fa0e-a7deaee5f2c0.png)
「ステップ 6: セキュリティグループの設定」では、以下のように設定し、[確認と作成]へ進みます。

| 操作 | タイプ | プロトコル | ポート範囲 | ソース | 補足 |
| ---- | ---- | ---- | ---- | ---- | ---- |
| 変更 | SSH | TCP | 22 | 管理者オフィスのIP | |
| 変更 | HTTP | TCP | 80 | 管理者オフィスのIP | |
| 変更 | HTTPS | TCP | 443 | 管理者オフィスのIP | |
| 削除 | カスタムTCP | TCP | 541 | 0.0.0.0/0 | 今回未使用 |
| 削除 | カスタムTCP | TCP | 3000 | 0.0.0.0/0 | 今回未使用 |
| 削除 | カスタムTCP | TCP | 8080 | 0.0.0.0/0 | 今回未使用 |
| 新規 | カスタムプロトコル | 50 | all | 0.0.0.0/0 | 東京のFortiGate-VMとのIPSecVPN - ESP |
| 新規 | カスタムUDP | UDP | 500 | 0.0.0.0/0 | 東京のFortiGate-VMとのIPSecVPN - IKE |
| 新規 | カスタムUDP | UDP | 4500 | 0.0.0.0/0 | 東京のFortiGate-VMとのIPSecVPN - NAT-T |
| 新規 | すべてのICMP | ICMP | 0 - 65535 | 10.0.0.0/8 | 疎通確認用 |
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/eaa841bb-23d1-4e62-3539-175ed140e278.png)

[起動]をクリックします。キーペアは[キーペアなしで続行]とし、[インスタンスの作成]をクリックします。
[EC2]-[ネットワーク&セキュリティ]-[Elastic IP]から「Elastic IPアドレスの割り当て」を行い、上記のFortiGate-VMへ関連付けを行います。

ブラウザから「https\://FortiGate-VMのパブリックIP」もしくは「https\://パブリックDNS」へアクセスします。ブラウザによっては(自己署名のため)「潜在的なセキュリティリスク」と表示しますが、そのまま続行します。
上述の「(バージニア)FortiGate-VMの作成」を参照し、ログインします。

#### (バージニア,東京)FortiGate-VM間のIPSec VPNの作成
(東京)IPSec VPNを設定します。今回はウィザードで進めます。
[VPN]-[IPsec Wizard]から以下の順番で設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/ca9e9025-5572-a072-d32b-1a6430c5aa4f.png)
[Remote IP address]は「FortiGate-VM-US」のEIPを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/da0139e9-d703-e857-3af7-cf4148aa7e9c.png)
ここはFirewall Policyの設定情報となります。通信させたい送信元・宛先サブネットを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/08707d4d-26af-e5d6-1409-b7c13112bffa.png)
[Create]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/0dff37ad-a20b-81fa-5c55-0dcc4e87e6ee.png)
[Show Tunnel List]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/a55dda21-abd6-50df-1132-017d6fbb0052.png)
現時点ではVPNはInactiveとなります。
※バージニア側のVPN設定が完了後、トラフィックが発生するとActiveとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/bef3933b-34fa-79e2-9887-17f2092ed159.png)
(バージニア)IPSec VPNを設定します。今回はウィザードで進めます。
[VPN]-[IPsec Wizard]から以下の順番で設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/f237bc0c-2dc2-13dc-2797-5bd5bbf4cb9a.png)
[Remote IP address]は「FortiGate-VM-US」のEIPを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/79a1a83a-e21b-f0e1-f13a-a3b8904e2b61.png)
ここはFirewall Policyの設定情報となります。通信させたい送信元・宛先サブネットを指定します。
※「10.1.0.0/24」「10.2.0.0/24」は「tunnel1(GRE)」インタフェースに関連するサブネットですが、本項目では「port1」しか選択できないため一旦仮で設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/98431fcc-4fda-429c-1112-4452fb99c890.png)
[Create]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/dcba500d-a94e-1c76-7342-a57f9f5cea5a.png)
[Show Tunnel List]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/2ee7116c-731f-19b5-6971-5f53fd7995f5.png)
現時点ではVPNはInactiveとなります。
※トラフィックが発生するとActiveとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/6a7e002c-11e5-b842-0711-89fb4f7bd670.png)
[Policy & Objects]-[Firewall Policy]から「port1→vpn01」のポリシーを選択し[Edit]をクリックします。
[Incoming Interface]の「port1」を「tunnel1」へ変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/af342dc1-9780-896e-e51d-b20ad28ba082.png)
※このとき[OK]をクリックすると「Comments」において「Invalid characters」となるため"("")"を削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/2da0448d-5461-8759-eaff-0db7983aeb1a.png)
を
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/a1e2dcc6-ecf8-c44c-19fe-d2a968a46b93.png)
へ変更。
同様に「vpn01→port01」のポリシーも[Edit]から「port1」を「tunnel1」へ変更します。
変更後のポリシー一覧は以下となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/743c7fde-93b7-5ace-298b-686c3fdea048.png)

#### (東京)VPCへFortiGate-VM宛てのルートの追加
[VIRTUAL PRIVATE CLOUD]-[ルートテーブル]から「tgw_handson_jp-private」を選択し、ルートを追加します。
上記で作成したFortiGate-VMをターゲットとしたVPC A,B宛てのルートを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/86dfc655-e477-a939-b1eb-bfeb2746adcf.png)

#### (東京)FortiGate-VMの「送信元/送信先チェック」の無効化
[EC2]-[インスタンス]-[インスタンス]から「FortiGate-VM-JP」を選択し、右クリック[ネットワーキング]-[ソース/宛先チェックを変更]をクリックします。「送信元/送信先チェック中」の「停止」へチェックを入れ[保存]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276941/2f59fda8-163e-89fc-28f7-af9220d630c1.png)

#### (バージニア,東京)確認2
バージニア、東京のそれぞれのServerから相互でPingの疎通ができることを確認します。

(東京)[EC2]-[インスタンス]-[インスタンス]から「tgw_handson_us-servera」を選択し「接続」をクリックします。「セッションマネージャー」で接続後、Pingを実行します。

```
# ServerA宛て
ping 10.1.0.11
PING 10.1.0.11 (10.1.0.11) 56(84) bytes of data.
64 bytes from 10.1.0.11: icmp_seq=1 ttl=252 time=146 ms
# ServerB宛て
ping 10.2.0.11
PING 10.2.0.11 (10.2.0.11) 56(84) bytes of data.
64 bytes from 10.2.0.11: icmp_seq=1 ttl=252 time=147 ms
```

(バージニア)[EC2]-[インスタンス]-[インスタンス]から「handson-tgw-connect」を選択し、同様にPingを実行します。

```
ping 10.99.0.11
PING 10.99.0.11 (10.99.0.11) 56(84) bytes of data.
64 bytes from 10.99.0.11: icmp_seq=1 ttl=252 time=146 ms
```

(バージニア)[EC2]-[インスタンス]-[インスタンス]から「handson-tgw-connect」を選択し、同様にPingを実行します。

```
ping 10.99.0.11
PING 10.99.0.11 (10.99.0.11) 56(84) bytes of data.
64 bytes from 10.99.0.11: icmp_seq=1 ttl=252 time=149 ms
```

# まとめ
AWS Transit Gateway ConnectとFortiGate-VMを接続しました。
従来はIPSecVPNで設定していましたが、Transit Gateway Connectを使用することでGREの設定になり若干ですが設定がシンプルとなりました。
なお、FortiGateのGREの設定は、CLIからとなりますので注意しましょう。

# 補足
- バージニア分のCloudFormationテンプレート

```020-JpVpcEc2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: TGW Connect handson in Virginia

Parameters:
  ParamTag:
    Type: String
    Default: tgw_handson_us
  ParamVpcACidrBlock:
    Type: String
    Default: "10.1.0.0/16"
  ParamVpcBCidrBlock:
    Type: String
    Default: "10.2.0.0/16"
  ParamConnectVpcCidrBlock:
    Type: String
    Default: "172.31.0.0/16"
  ParamAMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
## VPC A
  VpcA:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref ParamVpcACidrBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpca ] ]
  VpcAPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VpcA
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpca, private ] ]
  VpcAPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [ 0, !GetAZs ]
      VpcId: !Ref VpcA
      CidrBlock: !Select [ 0, !Cidr [ !Ref ParamVpcACidrBlock, 1, 8 ]]
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpca, private, a ] ]
  VpcAPrivateSubnetAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VpcAPrivateRouteTable
      SubnetId: !Ref VpcAPrivateSubnet

## VPC B
  VpcB:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref ParamVpcBCidrBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcb ] ]
  VpcBPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VpcB
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcb, private ] ]
  VpcBPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [ 0, !GetAZs ]
      VpcId: !Ref VpcB
      CidrBlock: !Select [ 0, !Cidr [ !Ref ParamVpcBCidrBlock, 1, 8 ]]
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcb, private, a ] ]
  VpcBPrivateSubnetAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VpcBPrivateRouteTable
      SubnetId: !Ref VpcBPrivateSubnet

## Connect VPC
  ConnectVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref ParamConnectVpcCidrBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, connectvpc ] ]
  ConnectVpcIgw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Ref ParamTag
  ConnectVpcAttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref ConnectVpc
      InternetGatewayId: !Ref ConnectVpcIgw
  ConnectVpcPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref ConnectVpc
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, connectvpc, public ] ]
  ConnectVpcPublicRoute:
    DependsOn: ConnectVpcIgw
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref ConnectVpcPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref ConnectVpcIgw
  ConnectVpcPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [ 0, !GetAZs ]
      VpcId: !Ref ConnectVpc
      CidrBlock: !Select [ 0, !Cidr [ !Ref ParamConnectVpcCidrBlock, 1, 8 ]]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, connectvpc, public, a ] ]
  ConnectVpcPublicSubnetAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref ConnectVpcPublicRouteTable
      SubnetId: !Ref ConnectVpcPublicSubnet

# Transit Gateway
  Tgw:
    Type: AWS::EC2::TransitGateway
    Properties:
      AmazonSideAsn: 64512
      Tags:
        - Key: Name
          Value: !Ref ParamTag
  TgwAttachmentToVpcA:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VpcAPrivateSubnet
      TransitGatewayId: !Ref Tgw
      VpcId: !Ref VpcA
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpca ] ]
  TgwAttachmentToVpcB:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref VpcBPrivateSubnet
      TransitGatewayId: !Ref Tgw
      VpcId: !Ref VpcB
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcb ] ]
  TgwAttachmentToConnectVpc:
    Type: AWS::EC2::TransitGatewayAttachment
    Properties:
      SubnetIds:
        - !Ref ConnectVpcPublicSubnet
      TransitGatewayId: !Ref Tgw
      VpcId: !Ref ConnectVpc
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, connectvpc ] ]

# VPC Endpoint for Session Manager
  EpSsmVpcA:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpointA
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VpcAPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VpcA
  EpSSMMsgVpcA:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpointA
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VpcAPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VpcA
  EpEC2MsgVpcA:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpointA
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VpcAPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VpcA
  EpS3VpcA:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VpcAPrivateRouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VpcA
  EpSsmVpcB:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpointB
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VpcBPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VpcB
  EpSSMMsgVpcB:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpointB
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VpcBPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VpcB
  EpEC2MsgVpcB:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpointB
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VpcBPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref VpcB
  EpS3VpcB:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VpcBPrivateRouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref VpcB

# SecurityGroup
  SGEndpointA:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EpA
      VpcId: !Ref VpcA
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 10.0.0.0/8
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcendpointa ] ]
  SGEndpointB:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EpB
      VpcId: !Ref VpcB
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 10.0.0.0/8
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcendpointb ] ]
  SGServerA:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ServerA
      VpcId: !Ref VpcA
      SecurityGroupIngress:
        - IpProtocol: icmp
          FromPort: -1
          ToPort: -1
          CidrIp: 10.0.0.0/8
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, servera ] ]
  SGServerB:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ServerB
      VpcId: !Ref VpcB
      SecurityGroupIngress:
        - IpProtocol: icmp
          FromPort: -1
          ToPort: -1
          CidrIp: 10.0.0.0/8
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, serverb ] ]

# IAM Role
  IamRoleForEc2:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - ec2.amazonaws.com
          Action:
            - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
      - Key: Name
        Value: !Ref ParamTag
  InstanceProfileForEc2:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Ref ParamTag
      Path: /
      Roles:
      - !Ref IamRoleForEc2

# EC2
  ServerA:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ParamAMI
      IamInstanceProfile: !Ref InstanceProfileForEc2
      InstanceType: t2.micro
      PrivateIpAddress: 10.1.0.11
      SubnetId: !Ref VpcAPrivateSubnet
      SecurityGroupIds:
        - !Ref SGServerA
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, servera ] ]
  ServerB:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ParamAMI
      IamInstanceProfile: !Ref InstanceProfileForEc2
      InstanceType: t2.micro
      PrivateIpAddress: 10.2.0.11
      SubnetId: !Ref VpcBPrivateSubnet
      SecurityGroupIds:
        - !Ref SGServerB
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, serverb ] ]
```
- 東京分のCloudFormationテンプレート

```020-JpVpcEc2.yml
AWSTemplateFormatVersion: 2010-09-09
Description: TGW Connect handson in Tokyo

Parameters:
  ParamTag:
    Type: String
    Default: tgw_handson_jp
  ParamVpcCidrBlock:
    Type: String
    Default: "10.99.0.0/16"
  ParamAMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
## VPC
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref ParamVpcCidrBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag ] ]
  VpcIgw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Ref ParamTag
  VpcAttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref Vpc
      InternetGatewayId: !Ref VpcIgw
  VpcPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, public ] ]
  VpcPublicRoute:
    DependsOn: VpcIgw
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref VpcPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref VpcIgw
  VpcPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, private ] ]
  VpcPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [ 1, !GetAZs ]
      VpcId: !Ref Vpc
      CidrBlock: !Select [ 1, !Cidr [ !Ref ParamVpcCidrBlock, 2, 8 ]]
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, public, a ] ]
  VpcPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select [ 1, !GetAZs ]
      VpcId: !Ref Vpc
      CidrBlock: !Select [ 0, !Cidr [ !Ref ParamVpcCidrBlock, 1, 8 ]]
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, private, a ] ]
  VpcPublicSubnetAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VpcPublicRouteTable
      SubnetId: !Ref VpcPublicSubnet
  VpcPrivateSubnetAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref VpcPrivateRouteTable
      SubnetId: !Ref VpcPrivateSubnet

# VPC Endpoint for Session Manager
  EpSsmVpc:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpoint
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssm
      SubnetIds:
        - !Ref VpcPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref Vpc
  EpSSMMsgVpc:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpoint
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ssmmessages
      SubnetIds:
        - !Ref VpcPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref Vpc
  EpEC2MsgVpc:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PrivateDnsEnabled: true
      SecurityGroupIds:
        - !Ref SGEndpoint
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ec2messages
      SubnetIds:
        - !Ref VpcPrivateSubnet
      VpcEndpointType: Interface
      VpcId: !Ref Vpc
  EpS3Vpc:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds:
        - !Ref VpcPrivateRouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      VpcId: !Ref Vpc

# SecurityGroup
  SGEndpoint:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Ep
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 10.0.0.0/8
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag, vpcendpoint ] ]
  SGServerC:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ServerC
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: icmp
          FromPort: -1
          ToPort: -1
          CidrIp: 10.0.0.0/8
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag ] ]

# IAM Role
  IamRoleForEc2:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - ec2.amazonaws.com
          Action:
            - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
      - Key: Name
        Value: !Ref ParamTag
  InstanceProfileForEc2:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Ref ParamTag
      Path: /
      Roles:
      - !Ref IamRoleForEc2

# EC2
  ServerC:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ParamAMI
      IamInstanceProfile: !Ref InstanceProfileForEc2
      InstanceType: t2.micro
      PrivateIpAddress: 10.99.0.11
      SubnetId: !Ref VpcPrivateSubnet
      SecurityGroupIds:
        - !Ref SGServerC
      Tags:
        - Key: Name
          Value: !Join [ "-", [ !Ref ParamTag ] ]
```

- 削除手順

以下の順で削除を行います。
(東京) FortiGate-VM
(東京) ElasticIP
(東京) FortiGate-VM Security Group
(東京) CloudFormation
(バージニア) FortiGate-VM
(バージニア) ElasticIP
(バージニア) FortiGate-VM Security Group
(バージニア) Transit Gateway Connect peers
(バージニア) Transit Gateway Connect
(バージニア) CloudFormation

# 参考
https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/tgw-connect.html

https://aws.amazon.com/jp/blogs/networking-and-content-delivery/simplify-sd-wan-connectivity-with-aws-transit-gateway-connect/

https://kb.fortinet.com/kb/documentLink.do?externalID=FD31868