クライアントVPNを使ってリモート接続環境を構築してみた

今回は[AWS初心者向けハンズオン](https://aws.amazon.com/jp/events/aws-event-resource/hands-on/)から[Network編#3 クライアントVPNをつかって、リモート接続環境を構築しよう](https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Network-3-2022-reg-event.html?trk=aws_introduction_page)を実際に構築し、挙動を確認していきたいと思います。

# アーキテクチャー図
アーキテクチャ図は次のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/ea224149-5181-7f13-9789-971a21b808cc.png)

ローカルのClient端末からAWS環境にクライアントVPN接続を経由して接続します。
クライアントVPNエンドポイントではCertificate Managerに登録した証明書を用いてClientの認証を行います。


# 利用しているAWSサービス

## VPN接続
VPN接続には「AWS Client VPN」というアプリケーションを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/55619205-fead-a2bb-66d2-1e05d4d465be.png)

## クライアントVPNエンドポイント
上記のアプリケーションを使用してVPNトンネルを通って接続する先のエンドポイントです。
AWSの管理画面上はVPCの設定ページにあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/3e997ef4-9328-30f6-cc9e-251050041ed8.png)

## AWS Certificate Manager
今回は証明書を使用してVPN接続をしますので、証明書の配置先としてACMを利用します。

# 構築(ポイントとなる箇所のみ)
## EC2
ENIを経由してEC2にアクセスできることを確認するためにインスタンスを設けます。

なお、こちらのCIDRは198.19.1.0/24としましたが、ご覧の皆さんの中には
「198.19.1.0/24はパブリックIPなんじゃないの？」と思われた方もいるかもしれません(最初私もそう思いましたw)
実際は、198.18.0.0/15(つまり、198.18.0.0から198.19.255.255)の範囲は、ネットワーク機器のベンチマークテストや、パフォーマンステストのためにIANA(Internet Assigned Numbers Authority)によって予約されていますので、このようにプライベートIPとして使用しても問題はありません。

## CloudWatch
クライアントVPNエンドポイントへのアクセスをログ出力するために設定します。
ロググループ、および、ログ出力先のログストリームを作成します。
ここでは以下の名前で作成。
ロググループ：/aws/cvpn
ログストリーム：connection-log
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/59f43468-ae9c-4f28-596d-880f501e5bec.png)

## 証明書の作成
クライアントVPN接続では３種類の認証方法が利用可能です。
* Active Directory認証
* 相互認証（証明書を利用した認証）
* シングルサインオン（SAMLベースのフェデレーション認証）

ここでは証明書を利用した相互認証を使用して接続を行います。
相互認証なので、サーバ側の証明書とクライアント側の証明書がそれぞれ必要となります。
証明書の作成は[AWSの相互認証有効のページ](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-auth-mutual-enable.html)に記載の手順に従って実施します。

```
# 証明書とキーの作成に使用するツール「OpenVPN easy-rsa」をダウンロード
git clone https://github.com/OpenVPN/easy-rsa.git
・・・省略・・・
# サーバ証明書とプライベートキーを生成
./easyrsa --san=DNS:server build-server-full server nopass
# クライアント証明書とプライベートキーを生成
./easyrsa build-client-full client1.domain.tld nopass
・・・省略・・・
# サーバ証明書を管理するためAWS Certificate Managerにアップロード
aws acm import-certificate --certificate fileb://server.crt --private-key fileb://server.key --certificate-chain fileb://ca.crt
# クライアント証明書を管理するためAWS Certificate Managerにアップロード
aws acm import-certificate --certificate fileb://client1.domain.tld.crt --private-key fileb://client1.domain.tld.key --certificate-chain fileb://ca.crt
```

クライアント証明書とクライアントのプライベートキーは後工程でクライアントからの接続の際に使用するので、ローカルに保存しておいてください。

## クライアントVPNエンドポイントの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/83bafd34-6b8d-f60d-ddff-94d928b86732.png)

ACMに格納した証明書をクライアントVPNエンドポイントにアタッチします。
なお、ELB、Cloud Front、API GatewayなどのACMに統合されたAWSリソースに対しても、同様にACMで管理されている証明書をアタッチすることが可能です。

「その他のパラメータ」にて「スプリットトンネルを有効化」は必ずチェックを入れるようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/04fb59b1-bcbd-1b15-7bbc-8a7f4f5b5e24.png)
デフォルトでは、クライアントデバイスとクライアント VPN エンドポイントとの間に VPN 接続が確立されると、クライアントデバイスからのすべてのトラフィックは VPN トンネル経由でルーティングされます。
今回はVPC宛ての通信のみVPNを経由するようにしたいので、こちらの設定を有効化します。

クライアントVPNエンドポイントの作成が完了しましたら、VPCをこちらのVPNに関連付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/97a34eba-7177-4bbc-9261-b04d7b7e1547.png)

最後に、AWS VPN Clientが読み込むための設定ファイルのテンプレートをダウンロードしておきます。
画面右上の「クライアント設定をダウンロード」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/1507827b-179e-345d-dd89-a769d8dcdbd0.png)

## AWS VPN Clientの設定

ローカルに以下３つのファイルがダウンロードされていることを確認します。
* downloaded-client-config.ovpn (クライアントVPNエンドポイントの画面でダウンロードしたテンプレート)
* client1.domain.tld.key　(クライアント側のプライベートキー)
* client1.domain.tld.crt　(クライアント証明書)

downloaded-client-config.ovpnにクライアントのプライベートキーと証明書貼り付けます(詳細は割愛)。

AWS VPN Clientを起動し、編集後のdownloaded-client-config.ovpnを読み込めば準備は完了です。

# 動作確認
AWS VPN Clientを起動し、接続ボタンを押してVPN接続を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/3b3623a9-43ce-20db-a743-f201154ee870.png)

接続後の動作確認として、Client端末からVPC内のEC2インスタンスにpingが飛ぶことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/6cc4f7b3-6a41-f9c1-de14-3384399a76b2.png)

# 感想
今回はクライアントVPNを利用してVPCに接続する構成を試してみました。

通常の開発ではクライアント環境からVPC環境につなぐシーンは結構多いと思いますが、今回の構成ではVPC内にSSHアクセス用の踏み台が不要であるという点がメリットとして挙げられるかと思います。

また、相互認証を使用しているので、クライアントごとに個別の証明書を発行してACMに登録しておくことで、例えばプロジェクトを離れた人についてはACMから証明書を除去すれば接続できなくなる、といった使われ方も可能です。証明書の有効期限も管理するなどで、より厳密な接続管理ができるという点もよいと思いました。

それでは今回はこのあたりで。