AWSのSite-to-Site VPN機能だけでAWS VPC同士をIPsecVPN接続する

# やりたいこと
オンプレミス環境や社外の対外接続先などとAWS環境を接続するにあたってIPsecVPNを利用するケースがあるが、その場合に困ることとして対外接続先と接続するまでIPsec周りを使ったテストを自社内で完結できないという点が挙げられる。
AWSアカウントの中で2つのVPCを立ててIPsecVPNを構成することができればその課題を解消できるということで、その方法について検討・実装をしてみた。

なお、通常このような場合には片方のVPCのEC2上にソフトウェアVPN（VyOSなど）を立てて実現するパターンもあるが、検証目的の場合、できるだけ早く・安く実装することが望ましいため今回はAWSのマネージド機能のみで実装できる方法で実現している。

文字に起こすと複雑に見えるが、環境自体の構築は除いてVPN接続のみでいうと30分もあれば実装可能。

# 実装イメージ

![IPsec.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645488/e3dfed48-68a3-70a1-041a-e7fe7ce22ed6.jpeg)


### 留意事項
・ CIDRはあくまで記載上の例。プライベートアドレスであれば何でも良い
・ 上図のイメージは同一AWSアカウントの中に複数VPCを設ける想定にしているが、別AWSアカウントのVPCでも同じ対応が可能

# 実装手順
## 概要説明
- 両方のVPCにVPN接続を作成し、そのVPN接続の設定を合わせることでトンネルを確立する
- AWSのVPN接続では対抗先（通常はオンプレ）をカスタマーゲートウェイとして設定する必要があるが、今回はそのカスタマーゲートウェイに相手型VPCのVPNで利用しているIPアドレスを設定する
- IPsecを確立する際に必要な鍵情報としてPreSharedKey（事前共有キー）があるので、これは両方のVPCのVPN接続で同一のものを利用する
- 通常AWSとオンプレ間の接続においてはオンプレ側からAWSに対して接続のネゴシエーションを行うが、今回はAWS同士なのでVPNトンネルオプションのスタートアップアクションでネゴシエーションを明示的に行う

## 具体的な設定手順の説明
### 環境準備（VPC/Subnet/SG/RouteTable/VGW/EC2の作成）
ここに関してはAWS上での基本的な環境構築であり今回の主題から外れるため概要の記載に留める
1. AWSアカウント上でVPCを2つ作成、その中にPrivateSubnetを設ける
2. 通信させたい対象となるコンポーネントを作成する（上図ではEC2を2台作成し、片方にNginxを搭載してVPC1側からVPC2側にHTTP通信ができること想定）
3. VPC1,2の両方にVirtual Private Gatewayを作成・アタッチする
4. Route Table/Security Groupに必要な設定を実施する

留意事項：
・ 通信したい双方のSubnetのRouteTableでVGW向けのルート設定を行うこと。
　（上図の例ではVPC1側のRouteTableに10.128.0.0/24でVGWを向くように設定、VPC2側のRoutetTableに10.0.0.0/24でVGWを向くように設定）
・ 通信を行うEC2にアタッチしているSecurityGroupで対抗先の情報をInbound/Outboundのルールに設定すること。


### IPsecVPNの設定その1 VPC1（10.0.0.0/16)側のVPN設定
以下の作業は基本的にマネジメントコンソール上、VPCのメニューから行う。

1. 仮想プライベートネットワーク（VPN）のカスタマーゲートウェイを選択し、カスタマーゲートウェイの作成を行う。
    - 名前：任意（後で削除するので何でも良い）
    - ルーティング：静的
    - IPアドレス：任意（後で変更するので1.1.1.1のようなものでOK）
    - Certificate ARN：指定しない
    - Device：指定しない
2. サイト間のVPN接続を選択し、VPN接続の作成を行う。
    - 名前：任意（用途が分かるようにはしておく）
    - ターゲットゲートウェイタイプ：仮想プライベートゲートウェイ
    - 仮想プライベートゲートウェイ：環境準備の手順3で作成したVGWのうち、VPC1にアタッチしたものを選択
    - カスタマーゲートウェイ：既存
    - カスタマーゲートウェイID：手順1で作成したCGWを選択
    - 上記以外はデフォルト　OR 空白のままでOK
3. しばらく待って作成したVPNの状態が「使用可能」になったら対象のVPNを選択して「設定のダウンロード」を実施→ベンダーやプラットフォーム・ソフトウェアはなんでも良い
4. ダウロードした設定をテキストで開き、「PreShared」もしくは「Shared」というキーワードで検索、32桁ぐらいのランダム文字列があるのでその文字列を記録する　・・・　PreShared Key
4. VPN接続の中の「トンネル詳細」タブを選択し、トンネル番号1の「外部IPアドレス」を記録する　・・・　VPC1の接続先IP

### IPsecVPNの設定その2 VPC2（10.128.0.0/16)側のVPN設定
1. カスタマーゲートウェイの作成を行う
    - 名前：任意（用途が分かるようにはしておく）
    - ルーティング：静的
    - IPアドレス：「IPsecVPNの設定その1 VPC1（10.0.0.0/16)側のVPN設定」の手順5で記録したVPC1の接続先IPを入力
    - その他は指定せずにOK
1. VPN接続の作成を行う
    - 名前：任意（用途が分かるようにはしておく）
    - ターゲットゲートウェイタイプ：仮想プライベートゲートウェイ
    - 仮想プライベートゲートウェイ：環境準備の手順3で作成したVGWのうち、VPC2にアタッチしたものを選択
    - カスタマーゲートウェイ：既存
    - カスタマーゲートウェイID：手順1で作成したCGWを選択
    - トンネル内オプション　トンネル1の事前共有キー：「IPsecVPNの設定その1 VPC1（10.0.0.0/16)側のVPN設定」の手順4で記録したPreShared Keyを入力
    - 上記以外はデフォルト　OR 空白のままでOK
1. しばらく待って作成したVPNの状態が「使用可能」になったら対象のVPNを選択して「設定のダウンロード」を実施
1. ダウンロードした設定をテキストを開き、「PreShared」もしくは「Shared」というキーワードで検索、そこで表示される32桁ぐらいの文字列が先ほど入力したPreShared Keyの文字列に一致していることを確認
1. VPN接続の中の「トンネル詳細」タブを選択し、トンネル番号1の「外部IPアドレス」を記録する　・・・　VPC2の接続先IP


### IPsecVPNの設定その3 VPC1（10.0.0.0/16)側のVPN設定修正
1. カスタマーゲートウェイの作成を行う
    - 名前：任意（用途が分かるようにはしておく）
    - ルーティング：静的
    - IPアドレス：「IPsecVPNの設定その2 VPC2（10.128.0.0/16)側のVPN設定」の手順5で記録したVPC2の接続先IPを指定
    - Certificate ARN：指定しない
    - Device：指定しない
2. 「IPsecVPNの設定その1 VPC1（10.0.0.0/16)側のVPN設定」の手順2で作成したVPNを選択し、アクションから「VPN接続を変更」を選択、ターゲットタイプ「Customer Gateway」、ターゲットカスタマーゲートウェイとして手順1で作成したカスタマーゲートウェイを選択する
2. 手順2で選択したのと同じVPNに対してアクションから「VPNトンネルオプションを変更」を選択、対象のVPNトンネルとしてトンネル番号1のIPアドレスを選択して、「スタートアップアクション」で開始を選択して保存
2. 上記を行なってしばらくしてVPNの状態が「使用可能」になったらVPC1・2両方のトンネル詳細タブを確認、うまくいっていればトンネル番号1のステータスがアップになっているはず！

以上で接続できる状態になっているので、VPC1上のEC2からVPC2上のEC2（Nginx）にCurlコマンドなどを実行すれば応答が得られる。
なお、VPN接続は2経路用意されているが、トンネル番号2同士の接続については、カスタマーゲートウェイで設定できるのが1つのIPしかなく、それをトンネル番号1で使ってしまっているためできない。

# 注意事項
今回紹介した方法について、AWSサポートに問い合わせたところ「サイト間VPNはオンプレミとVPCの間での接続を行う機能として提供されており、サイト間VPN接続同士を接続することは想定するご利用形態には含まれておりません」と回答を受けている。
この方法を業務の中で利用した場合、意図しない挙動となるリスクもあるため、あくまで開発環境でのテスト程度で利用するに留め、本番業務の中では利用しないことを推奨する。
本番業務においてAWSのVPC同士を接続したい場合にはPeeringもしくはPriateLinkなどAWSが用意している機能を素直に使うのが良い。

# 参考URL
https://docs.aws.amazon.com/ja_jp/vpn/latest/s2svpn/initiate-vpn-tunnels.html