AWS Client VPN をサクッと立てて落とせるようにしておく

# 経緯

社内ネットワークのパブリック IP ベースで接続を許可しているものがあるが、
ビルの点検やオフィス移転などにより、一時的に IP が使えない状況が起きても、VPN 経由で対応をできるようにしておきたいといったケースを想定

ただし、スタンバイ状態にしておくと、接続していなくても
0.15USD x 24h x 31day x 2サブネット(接続先) で 約232USD (約2万5千円) 月額かかるので、
使わないときは停止しておきたい

# 今回前提

- 東京リージョンで利用する前提
- 今回の VPN routing の CIDR は 0.0.0.0/0 で全リクエスト VPN 経由としている
    - 本来は IP 許諾が 必要な CIDR だけに絞るほうが帯域による課金も減らせるのでおすすめ
- VPN が起動状態になるまで 10分〜15分まつのは許容
- AD は使わず証明書での認証方式とする


# 要件

- 一時的なので使っていない間は料金がかからないようにしたい
- AWSの知識がそれほどなくても簡単にVPNを使える状態、使えない状態にしたい
- オフィスの移転が起きようが常に変わらない IP を確保して、許諾したい

# サーバ構成図 (稼働時)

![vpn-start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218682/473593f6-fed8-305b-055e-3a6de2a9d3d4.png)

# サーバ構成図 (停止時)

![stop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218682/47ec49b6-c779-a851-cf8b-56707c11df85.png)

# 手順

## 準備

### 固定IP取得

```
$ aws ec2 allocate-address --domain vpc

// 以下のように表示されるので、 IP と AllocationId をメモしておく
{
    "PublicIp": "xx.xx.xx.xx",
    "PublicIpv4Pool": "amazon",
    "Domain": "vpc",
    "AllocationId": "eipalloc-00000000000000"
}
```

### ルート証明書、サーバ証明書、サーバ秘密鍵 を AWS Certificate Manager (ACM) に登録

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

$ echo 'set_var EASYRSA_KEY_SIZE 16384' > vars # 鍵長を 16384bit とする
$ echo 'set_var EASYRSA_CERT_EXPIRE 365' >> vars # 有効期限は 365日とする

$ ./easyrsa init-pki # 初期化
$ ls pki # pki フォルダ配下に必要なデータが生成される

$ ./easyrsa build-ca nopass # Common Name を入力 (ex. vpn.hapitas.jp)
$ ls -l pki/ca.crt # ルート証明書が生成される

$ ./easyrsa build-server-full server nopass # サーバ証明書・サーバ秘密鍵作成
$ ls -l pki/issued/server.crt # サーバ証明書が存在
$ ls -l pki/private/server.key # サーバ秘密鍵が存在

# pki フォルダに生成されたファイルは厳重に管理しておく

# ACM に鍵を登録
$ aws acm import-certificate \
  --certificate file://pki/issued/server.crt \
  --private-key file://pki/private/server.key \
  --certificate-chain file://pki/ca.crt \
  --region ap-northeast-1

# 以下のように表示されるのでメモしておく
{
    "CertificateArn": "arn:aws:acm:ap-northeast-1:111111111:certificate/11111-1111-1111-1111-1111111111"
}
```

### クライアント証明書、秘密鍵 (これらの情報は機密にメンバー個別に共有しておく)

```
# 先程のサーバ証明書を作ったあとの手順 (接続するメンバー分だけ作成)

$ USER=s-urabe
$ ./easyrsa build-client-full ${USER} nopass
$ mkdir -p keys/$USER
$ mv -v pki/issued/$USER.crt keys/$USER/client.crt
$ mv -v pki/private/$USER.key keys/$USER/private.key
```

### Nat インスタンス接続用 SSH 鍵作成 （普段接続することないと思いますが)

以下のコマンドの場合はキー名は vpn_nat

```
$ aws ec2 create-key-pair \
    --key-name vpn_nat \
    --query 'KeyMaterial' \
    --output text > ~/.ssh/vpn_nat.pem
```

## VPN 起動

### サーバー側構築

[gist に置いている vpn-start-cloudformation.yml](https://gist.github.com/oz-urabe/c66244d6a59295c82c0dfc39b44143c4) をダウンロードします。

yaml ファイルの中で `EIPAllocationId` `ACMArn` `SSHKeyName` の Default 値 は適当な値を設定しているので準備で取得した値を設定し、以下のコマンドを打ちます

```
aws cloudformation deploy \
  --template-file vpn-start-cloudformation.ym \
  --stack-name my-vpn
```

1５分〜20分 ほどで起動します。

### クライアント側設定

https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#ClientVPNEndpoints:sort=clientVpnEndpointId から `Download Client Configuration` を押下し、ovpn ファイルをダウンロードします。

<img width="639" alt="スクリーンショット 2020-01-28 9.55.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218682/8f6f66ca-81af-59f6-3869-2e27b1afb78e.png">

ovpn ファイルの末尾に以下を追記します

```
echo "cert client.crt" >> downloaded-client-config.ovpn
echo "key private.key" >> downloaded-client-config.ovpn
```

downloaded-client-config.ovpn ファイルを 先程 クライアント証明書 を配置した keys/$USER と同じディレクトリに配置します。（複数作った場合は複数分）
このディレクトリ構成のまま接続するメンバーに共有していきます。

macOS の場合は、 [Tunnelblick](https://tunnelblick.net/) Windows の場合は [OpenVPN GUI インストーラー](https://www.openvpn.jp/download/) を使ってインストールします。

接続し、 https://ifconfig.me などで 接続元 パブリックIP が 固定IP取得 で取得したものと同じであれば 問題ありません

## VPN 停止



[gist に置いている vpn-stop-cloudformation.yml](https://gist.github.com/oz-urabe/26b42e1c3182389752b33c1f344022a9) をダウンロードします。

yaml ファイルの中で `ACMArn` の Default 値 は適当な値を設定しているので準備で取得した値を設定し、以下のコマンドを打ちます

```
aws cloudformation deploy \
  --template-file vpn-stop-cloudformation.yml \
  --stack-name my-vpn
```

10分 ほどで終了します。
VPN 起動が必要になったときは <a href="#サーバー側構築">サーバー側構築</a> の手順を実施します。（２回目の起動は１０分ほどかかります)