AWS Client VPN 経由でグローバルIPを固定する

AWS Client VPN 経由でグローバルIPを固定する手順をまとめます。

グローバルIPを固定できれば、リモートワークなどで接続状況が変わっても、ホワイトリスト登録された状態でウェブサーバやAPIサーバを利用できます。

今回参考にさせてもらったのは次の記事です。事前知識のある方はそちらを見れば進められると思います。

* 『[AWS Client VPNがTokyoに来た！ | 概要と固定IPの設定方法を解説 - SMARTCAMP](https://tech.smartcamp.co.jp/entry/2019/06/21/160546)』
* 『[[AWS Client VPN] VPC を経由して固定のIPでインターネットへアクセスする](https://dev.classmethod.jp/cloud/aws/aws-client-vpn-with-static-ip/)』

事前知識のない方は、より細かくまとめた以下の内容を参考にしてみてください :smiley:

*※ 後述のとおり、AWS の利用料金が発生するので自己責任でセットアップしてください。*

# 登場サービス・用語のおさらい

今回登場する AWS のサービス・用語について整理します。概ね公式ドキュメントからの抜粋・引用です。

## Amazon VPC

AWS リソースを起動できる仮想ネットワーク。用意されているリソースは、サブネット、Elastic IP、セキュリティグループ、ネットワークACL、ゲートウェイ、ルートテーブルなど。

### サブネット

VPC の IP アドレスの範囲。例えば、VPC のアドレススペースが `10.0.0.0/16` であれば、そのサブネットとして `10.0.x.x` で始まるIPアドレスを使える。

### Elastic IP

インスタンスまたはネットワークインターフェイスに関連付けられるパブリック IPv4 アドレス。

### NATゲートウェイ

プライベートサブネットのインスタンスからのトラフィックをインターネットや他の AWS サービスに送信し、その応答をインスタンスに返送する。

トラフィックがインターネットに送信される場合、送信元の IPv4 アドレスは NAT デバイスのアドレスに置き換えられる。

### Client VPN

AWS リソースや、オンプレミスネットワーク内のリソースに安全にアクセスできるようにする、クライアントベースのマネージド VPN サービス。

## AWS Certificate Manager（ACM）

AWS の他サービスで利用する SSL/TLS 証明書のプロビジョニング、管理、デプロイをおこなう。

# 設計

Client VPN でプライベートサブネットにアクセスし、そこから固定IP（Elastic IP）が割り当てらた NAT ゲートウェイ（パブリックサブネット）経由でインターネットを利用します。

設計の全体像は[こちら](https://dev.classmethod.jp/cloud/aws/aws-client-vpn-with-static-ip/#toc-)の記事の「接続構成」をご確認ください。

# グローバルIPを固定する手順

それでは本題に入り、AWS Client VPN 経由でグローバル IP を固定する手順を整理します。

## 1. VPC の設定（プライベートサブネット）

### パブリックサブネットの作成

[VPC のコンソール](https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#NatGateways:sort=natGatewayId)から、VPN 用のパブリックサブネットを作成します。

今回は、デフォルトの VPC（IPv4 CIDR: `172.31.0.0/16`）に新しいサブネットを追加しました。既存のサブネットと重複しないレンジの「IPv4 CIDR ブロック」を指定しましょう。

（使用済みのIPアドレスのレンジは、[こちら](https://www.ipaddressguide.com/cidr)のサイトに既存サブネットの IPv4 CIDR を入力して確認できます。）

<img width="1440" alt="スクリーンショット 2020-01-15 10.52.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138789/933cb76b-51ae-2da8-c36b-7122352ec364.png">

### NATゲートウェイの作成

作成した パブリックサブネットに NAT ゲートウェイを追加し、Elastic IP も関連付けさせます。

**※ この Elastic IP が固定されるグローバル IP です。**
 
### ルートテーブルの作成

送信先 `0.0.0.0/0` のターゲットが作成した NAT ゲートウェイとなるルートテーブルを新規作成します。

<img width="1221" alt="スクリーンショット 2020-01-15 11.19.21 2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138789/0eb75ccc-7650-d3f7-7f46-c90c4d602932.png">

### プライベートサブネットの作成

VPN 用のパブリックサブネットと同じアベイラビリティーゾーン内にプライベートサブネットを作成し、先ほど作ったルートテーブルを紐付けます。

<img width="839" alt="スクリーンショット 2020-01-15 11.24.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138789/047dfce2-274a-1009-b5ae-ca741dfaeba5.png">

## 2. ACM の設定（証明書・キーの生成）

今回は VPN の認証オプションとして「相互認証」を利用するので、それに必要な証明書・キーを OpenVPN Easy-RSA で生成し、それらを ACM に登録します。

### OpenVPN Easy-RSA のインストール

```
git clone https://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easyrsa3
```

### 証明書の生成

```
./easyrsa init-pki
./easyrsa build-ca nopass
./easyrsa build-server-full server nopass
./easyrsa build-client-full client1.domain.tld nopass
```

### ACM への登録

[ACMコンソール](https://ap-northeast-1.console.aws.amazon.com/acm/home?region=ap-northeast-1)の「証明書のインポート」より、作成した2ペアの証明書・キーを登録します。

```:証明書本文・証明書チェーン
-----BEGIN CERTIFICATE-----
....==
-----END CERTIFICATE-----
```

```:証明書のプライベートキー
-----BEGIN PRIVATE KEY-----
....
-----END PRIVATE KEY-----
```

#### サーバ証明書 (server)

* 証明書本文 `~/easy-rsa/easyrsa3/pki/issued/server.crt`
* 証明書のプライベートキー `~/easy-rsa/easyrsa3/pki/private/server.key`
* 証明書チェーン `~/easy-rsa/easyrsa3/pki/ca.crt`

#### クライアント証明書 (client1.domain.tld)

* 証明書本文 `~/easy-rsa/easyrsa3/pki/issued/client1.domain.tld.crt`
* 証明書のプライベートキー `~/easy-rsa/easyrsa3/pki/private/client1.domain.tld.key`
* 証明書チェーン `~/easy-rsa/easyrsa3/pki/ca.crt`

## 3. Client VPN エンドポイントの設定

### Client VPN エンドポイントの作成

[VPC コンソール](https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#ClientVPNEndpoints:sort=clientVpnEndpointId)から「クライアントVPNエンドポイント」を作成します。

<img width="1440" alt="スクリーンショット 2020-01-14 21.43.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138789/944346a4-b83b-9eb1-325e-127e06e0c453.png">

* クライアント IPv4 CIDR：接続先のVPCのCIDRと被らない任意のアドレス 
* サーバ証明書：ACMに登録したサーバ証明書
* 相互認証の使用：チェック
* クライアント証明書：ACMに登録したクライアント証明書
* DNSの設定は不要

### NAT ゲートウェイへの関連付け

作成後、「Client VPN エンドポイント > 関連付け」から VPN 用に作成したプライベートサブネットに紐付けます。

### ルートテーブルの追加

「Client VPN エンドポイント > ルートテーブル」から「宛先 `0.0.0.0/0`」を追加します。

* 宛先の CIDR `0.0.0.0/0`
* ターゲット VPC サブネット ID: VPN 用に作成したプライベートサブネット

追加後のルートテーブルは次のようになります。

<img width="1200" alt="スクリーンショット 2020-01-15 14.15.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138789/d4a5d99e-c99d-5fbf-0c45-777189bb7932.png">


### 認証ルールの追加

「Client VPN エンドポイント > 認証」から認証ルールを追加します。

* アクセスを有効にする送信先ネット: 0.0.0.0/0
* アクセスを付与する対象: すべてのユーザーにアクセスを許可する

<img width="1309" alt="スクリーンショット 2020-01-15 11.39.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138789/5e8cdbb0-5a03-a169-1546-ea57640a0226.png">

### 設定ファイルのダウンロード

「Client VPN エンドポイント > クライアント設定のダウンロード」から設定ファイルを落とします。

設定ファイルをエディタで開き、クライアント証明書とキーのパスを追記します。

```:downloaded-client-config.ovpn
# 省略
cert /Users/[username]/easy-rsa/easyrsa3/pki/issued/client1.domain.tld.crt
key /Users/[username]/easy-rsa/easyrsa3/pki/private/client1.domain.tld.key
```

設定は以上です。

# 接続テスト（Tunnelblick）

VPNの接続には [Tunnelblick](https://tunnelblick.net/) を使います。

更新した設定ファイルを Tunnelblick に追加し、接続します。

接続完了後、[CMAN](https://www.cman.jp/network/support/go_access.cgi) で利用中のグローバルIPを確認し、割り当てた Elastic IP が表示されればOKです。

# 概算利用料金

同セットアップでグローバルIPを固定する場合の利用料金を考えてみます。

## 各サービス料金

（*) 利用可能になった時点から課金
（^）VPN 利用時に課金

### NAT ゲートウェイの料金

『[Amazon VPC の料金](https://aws.amazon.com/jp/vpc/pricing/)』によると、東京リージョンでの利用料金は次のとおりです。

* 利用可能な NAT ゲートウェイの時間料金：0.062USD/時 (*)
* データ処理料金：0.062USD/GB (^)

### Client VPN の料金

『[AWS VPN の料金](https://aws.amazon.com/jp/vpn/pricing/)』によると、東京リージョンでの利用料金は次のとおりです。

* Client VPN エンドポイントの時間料金：0.15USD/時・サブネットとの関連付け (*)
* Client VPN 接続料金：0.05USD/時 (^)

## セットアップした状態だと、維持費は月150ドル？！

上のとおり、NAT ゲートウェイと Client VPN には、「利用可能になった時点から課金」される金額があります。なので、利用可能な状態（active）を維持しておくと...

```
# 1日あたり
(0.062 + 0.15) * 24時間 = 5.09ドル/日
# 1月あたり
5.09 * 30日 = 152.7ドル/月 
```

**なんと、維持費だけで月152.7ドルも請求されてしまいます！**

（実際に使った場合は、これに加えて、データ処理料金と VPN 接続料金も請求されます。）

## 維持費の抑えかた: 152ドル → 3.6ドル

この高額な維持費は、**次の2つの方法で月3.6ドルまで抑えられます。**

VPN を使用していない時は：

1. NAT ゲートウェイを削除する
1. Client VPN のサブネットとの関連付けを解除する

これで NAT ゲートウェイと Client VPN の維持費はなくなります。

一方、NAT ゲートウェイを削除したことにより、Elastic IP アドレスの関連付けがなくなります。これによって、**Elastic IP アドレスの維持費が月3.6ドル発生します。**

詳細はこちら → [Elastic IP アドレス - Amazon EC2 料金表](https://aws.amazon.com/jp/ec2/pricing/on-demand/#Elastic_IP_Addresses)

```
# 1日あたり
0.005 * 24時間 = 0.12ドル/日
# 1月あたり
0.12 * 30日 = 3.6ドル/月 
```

### VPN 利用時の再セットアップ

この場合、VPN を使用する時に次のセットアップが必要です：

1. NAT ゲートウェイを再作成（Elastic IP を割り当てる）
2. プライベートサブネットのルートテーブルを更新（`0.0.0.0/0` を NAT ゲートウェイに向ける）
3. Client VPN とプライベートサブネットを関連付ける
4. Client VPN 宛先の CIDR `0.0.0.0/0` を追加

めんどくさいですが、「維持費 152ドル → 3.6ドル」を考えると許容できる作業量だと思います。

## 結局の概算利用料金

上のように維持費を抑えた場合、結局利用料をどれぐらいになるでしょうか？

例えば、再セットアップして1日8時間 VPN 接続し、2GBのデータ処理をした時の概算利用料は、1日2ドルちょっとになります。

```
0.262 * 8時間 + 0.062 * 2GB = 2.22ドル/日
```

VPN 接続しない時の Elastic IP 維持費は1日0.12ドルなので、差額コストはだいたい2ドル。

つまり、

```
3.6ドル/月 + 利用日数 * 2ドル
```

が概算利用料金の目安になります。

なので、ヘビーに利用する場合はそれなりの料金がかかります。そういったケースでは、専用の有料サービスを利用した方が良さそうです。（日本のIPでも月額1,000円ぐらいで利用できそう）

利用するタイミングが限定的であれば、この方法でグローバルIPを固定するのもアリだと思います。あとは VPC 周りの勉強になったので、そういった観点でセットアップしてみるのもいいかもしれません。

# References

* [Introducing AWS Client VPN to Securely Access AWS and On-Premises Resources](https://aws.amazon.com/jp/blogs/networking-and-content-delivery/introducing-aws-client-vpn-to-securely-access-aws-and-on-premises-resources/)
* [AWS Client VPNがTokyoに来た！ | 概要と固定IPの設定方法を解説](https://tech.smartcamp.co.jp/entry/2019/06/21/160546)
* [[AWS Client VPN] VPC を経由して固定のIPでインターネットへアクセスする](https://dev.classmethod.jp/cloud/aws/aws-client-vpn-with-static-ip/)
* [AWS VPN の料金 - AWS](https://aws.amazon.com/jp/vpn/pricing/)
* [Amazon VPC の料金 - AWS](https://aws.amazon.com/jp/vpc/pricing/)
* [Elastic IP アドレス - Amazon EC2 料金表 - AWS](https://aws.amazon.com/jp/ec2/pricing/on-demand/#Elastic_IP_Addresses)