AWSのClient VPNを用いた社内固定IPインターンネットアクセスの構築

# 背景
受託案件において実際に構築したサービスの本番環境へのアクセスが会社のルータのIPで制限されており、リモートからの作業に支障をきたすことが多々ありました。そこでClient VPNを用いて相互認証を行い、認証が通った後に固定のIPからインターネットへアクセスできるようにすることで、その固定IPを制限から解除すればリモートからでも本番環境にアクセスできるようにしました。

# 目次
1. [全体構成](#全体構成)
1. [認証方法](#認証方法)
1. [構築の流れ](#構築の流れ)
1. [証明書の発行](#証明書の発行)
1. [ACMにサーバ証明書をアップロード](#acmにサーバ証明書をアップロード)
1. [証明書の配布](#証明書の配布)
1. [クライアントの設定](#クライアントの設定)
1. [証明書の運用](#証明書の運用)
1. [参考文献](#参考文献)


<!-- 各チャプター -->
<a id="#全体構成"></a>
# 全体構成
こちらの記事と構成は全く同じです。
一番重要なのはNATに固定IPを紐付けて、全てのクライアントがそこを経由することで同じIPからのインターネットアクセスになるということです！ただ、どんな人でもその固定IPにアクセスできると困るので、その前にClient VPNを用いて認証を行うということです。

https://dev.classmethod.jp/articles/aws-client-vpn-with-static-ip/

IPやルートテーブルの一例

```
- VPC(IPv4 CIDR: 192.168.0.0/16)
    - サブネット
        - パブリックサブネット（192.168.2.0/24）
            - ルートテーブル（192.168.0.0/16→local, 0.0.0.0/0→igw）
            - NATを配置
                - EIP: xxx.xxx.xxx.xxx, プライベート IP アドレス: 192.168.2.163
        - プライベートサブネット（192.168.1.0/24）
            - ルートテーブル（192.168.0.0/16→local, 0.0.0.0/0→nat)
    - クライアント VPN エンドポイント
        - IPv4 CIDR: 192.168.4.0/22
        - 関連づけられたサブネット: プライベートサブネット
        - ルートテーブル
            - 192.168.0.0/16: プライベートサブネット
            - 0.0.0.0/0: プライベートサブネット
```

<a id="#認証方法"></a>
# 認証方法
[認証方法の種類](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-authentication.html#mutual)
> 認証は AWS クラウドへの最初のエントリポイントで実装されます。クライアントがクライアント VPN エンドポイントへの接続を許可されているかどうかを判断するために使用されます。認証が成功すると、クライアントはクライアント VPN エンドポイントに接続して VPN セッションを確立します。認証が失敗すると、接続は拒否され、クライアントは VPN セッションを確立できなくなります。

> クライアント VPN では、次のタイプのクライアント認証を使用できます。
Active Directory 認証 (ユーザーベース)
相互認証 (証明書ベース)
シングルサインオン (SAML ベースのフェデレーション認証) (ユーザーベース)

今回用いた認証方法は相互認証です!

```
- 相互認証
    - 相互認証では、証明書を使用してクライアントとサーバー間の認証を実行します。
    - 証明書にはサーバー証明書とクライアント証明書の２種類に分けられて、サーバー証明書は一つでいいけど、クライアント証明書は人数分増えていく
    - サーバー証明書をACMにアップロードする（エンドポイント作成時に必要だから）
        - ここで言うサーバー証明証はサーバー証明書とそのキー、ルート証明書を合わせたもの
    - クライアント証明書はACMにアップロードしなくていい（サーバー証明書とクライアント証明書を同じ認証局で今回は作成しているので）
        - エンドポイント作成時にクライアント証明書にサーバー証明書を選択したあげればOK
        - ちなみに自分で認証局を作成するのをオレオレ認証局って言います
    - クライアント証明書はクライアントに配布する（この時に設定ファイルも一緒に配布する）
```

認証局を自前で建てるのか、厳格に審査された信用できる認証局を使用するかで悩みました。
セキュリティ的には圧倒的に厳格に審査された信用できる認証局を使用すべきなのですが、AWSでプライベート認証局（CA）を1つ建てると毎月4万円はするので無しになりました。そもそも相互認証ではなく、Active Directory認証を用いる手もありましたが、オレオレ認証局を用いた相互認証の方がまだセキュリティー的に安全なのではないかと考え、オレオレ認証局での相互認証で構築することなりました。ここら辺について詳しい方がいれば教えてください。

<a id="#構築の流れ"></a>
# 構築の流れ

```
- 主な流れ
  - 証明書の発行
  - ACMにサーバ証明書をアップロード
  - クライアントVPNエンドポイントの作成と各種設定
  - エンドポイントから設定ファイルをダウンロード
  - クライアントにクライアント証明書とそのキー、設定ファイルを配布
  - クライアントにVPN接続のクライアントアプリケーションを入れてもらい、配布したものとそのアプリでVPN接続してもらう
  - 接続しているIPがNATに紐づく固定IPになっていたら大成功
```

Client VPNエンドポイントの作成方法はこの記事では説明していないので、他記事を参考にして頂ければなと。

<a id="#証明書の発行"></a>
# 証明書の発行
- 証明書を発行するためのツール
    - EasyRSA-3.0.7
    - これ使えば認証局の作成から証明書の発行が超絶簡単にできる
    - Open SSLを用いる方法もあリました。
   
- 発行方法
EasyRSA-3.0.7の公式ドキュメントに書いてある通りです。
[AWS公式](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-authentication.html#mutual)

```
$ wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.7/EasyRSA-3.0.7.tgz
$ tar zxfv EasyRSA-3.0.7.tgz
$ cd EasyRSA-3.0.7

新しい PKI 環境を初期化します。
$ ./easyrsa init-pki

# 認証局の作成
# nopassオプションを使用するとパスフレーズを追加しなくてよくするオプション
$ ./easyrsa build-ca nopass

# サーバー証明書の作成
$ ./easyrsa build-server-full server nopass 

# クライアント証明書の作成
# クライアント証明書はクライアントごとに分けるので、名前にするとわかりやすいと思います。
$ ./easyrsa build-client-full isao.katsuoka.tld nopass 

# 証明書だけを集めたフォルダを作っておくといいかもです。
$ mkdir ~/vpn_folder/
$ cp pki/ca.crt ~/vpn_folder/
$ cp pki/issued/server.crt ~/vpn_folder/
$ cp pki/private/server.key ~/vpn_folder/
$ cp pki/issued/isao.katsuoka.tld.crt ~/vpn_folder/
$ cp pki/private/isao.katsuoka.tld.key ~/vpn_folder/
$ cd ~/vpn_folder/
```

- 次からはサーバ証明書やルート証明書は発行しなくていいので、以下を名前を変えて人数分実行すればいい

```
$ cd ~/EasyRSA-3.0.7
$ ./easyrsa build-client-full yuki.tanaka.tld nopass
$ cp pki/issued/isao.katsuoka.tld.crt ~/vpn_folder/
$ cp pki/private/isao.katsuoka.tld.key ~/vpn_folder/
$ cd ~/vpn_folder/
```

- 証明書が保存される場所をまとめてみました。

```
- 保存場所
    - CA証明書
        - pki/ca.crt
    - 証明書（クライアント証明書とサーバー証明書）
        - pki/issued/
            - isao.katsuoka.tld.crt
            - server.crt
    - 証明書のキー
        - pki/private/
            - ca.key
            - isao.katsuoka.tld.key
            - server.key
```

<a id="#ACMにサーバ証明書をアップロード"></a>
# ACMにサーバ証明書をアップロード
アップロードの方法として画面ぽちぽちする方法と、AWS CLIを用いる方法がありますが、今回はAWS CLIを用いる方法を説明したいと思います。

```
$ cd ~/vpn_folder/
$ aws acm import-certificate \
  --certificate file://server.crt \
  --private-key file://server.key \
  --certificate-chain file://ca.crt \
  --region ap-northeast-2

↓アップロードエラー出たので、file:// -> fileb://に変更する
https://zenn.dev/hohner/articles/310453a1121c9b

$ aws acm import-certificate \
  --certificate fileb://server.crt \
  --private-key fileb://server.key \
  --certificate-chain fileb://ca.crt \
  --region ap-northeast-2
```

- 注意点
    - サーバー証明書のアップロードはクライアントVPNエンドポイントを作成する時の最初の１回だけ必要
    - クライアント証明書のアップロードはオレオレ認証局だから必要ない（エンドポイント作成時にクライアント証明書を選択する必要があるが、その時はサーバー証明書を選択すれば良い）

また、完全に余談になりますが、awspを入れるとプロファイルの切り替えが簡単になるので
もし入れてなかったら入れてみてください！！

[AWS CLIのプロファイルを簡単切り替え](https://dev.classmethod.jp/articles/aws-cli-switch-profile/)

<a id="#証明書の配布"></a>
# 証明書の配布

```
- クライアントVPNエンドポイントの管理画面から「クライアント設定のダウンロード」を押して設定ファイル（downloaded-client-config.ovpn）を取得
- 配布するファイル
    - クライアント証明書とそのキー（isao.katsuoka.tld.crt, isao.katsuoka.tld.key)
    - OVPNファイル(downloaded-client-config.ovpn)←名前は変えてもいい
- この3つのファイルをzip化して送る
```

<a id="#クライアントの設定"></a>
# クライアントの設定

- VPNのクライアントアプリケーションのインストール
    - Macの場合→Tunnelblick
        - [Macの場合(Tunnelblickの設定)](https://dev.classmethod.jp/articles/openvpn24-aws/#toc-15)
        - [Tunnelblick公式ドキュメント](https://tunnelblick.net/downloads.html)
    - Windowsの場合→vpnux
        - ただ、自分はWindowsを使っていないので設定方法がわかりません。

- Tunnelblickの使い方
    - 一言で言えば、downloaded-client-config.ovpnに証明書とそのキーを読み込ませてあげればいい
        - 具体的にはcertタグとkeyタグを作成して、そこに証明書とそのキーの情報を差し込む。

⇩設定の一例

```bash
    client
    dev tun
    proto udp
    remote cvpn-endpoint-xxxxxxxxxxxx.prod.clientvpn.ap-northeast-x.amazonaws.com 443
    remote-random-hostname
    resolv-retry infinite
    nobind
    remote-cert-tls server
    cipher AES-256-GCM
    verb 3
    <ca>
    -----BEGIN CERTIFICATE-----
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    -----END CERTIFICATE-----

    </ca>

    <cert>
    -----BEGIN CERTIFICATE-----
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    -----END CERTIFICATE-----
    </cert>

    <key>
    -----BEGIN PRIVATE KEY-----
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    cccccccccccccccccccccccccccccccccccccccccccccccccccccc
    -----END PRIVATE KEY-----
    </key>

    reneg-sec 0
```

<a id="#証明書の運用"></a>
# 証明書の運用
- 証明書の失効
    - [特定クライアントのクライアント VPN エンドポイントへのアクセスを取り消すにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/client-vpn-revoke-access-specific-client/)
    - 失効リストをオレオレ認証局で作成して、Client VPNエンドポイントにインポート
- 証明書の有効期限
    - デフォルトで825日
    - 100年に変更もできる
        - [【Client VPN】OpenVPN easy-rsaでサーバ証明書の有効期限を100年にする](https://blog.denet.co.jp/easy-rsa_validity/)
    - 証明書の有効期限が切れたらクライアントに再配布が必要！

<a id="#参考文献"></a>
# 参考文献
- [[AWS Client VPN] VPC を経由して固定のIPでインターネットへアクセスする](https://dev.classmethod.jp/articles/aws-client-vpn-with-static-ip/)
- [相互認証　AWS公式ドキュメント](https://docs.aws.amazon.com/ja_jp/vpn/latest/clientvpn-admin/client-authentication.html#mutual)
- [AWS CLIのプロファイルを簡単切り替え](https://dev.classmethod.jp/articles/aws-cli-switch-profile/)
- [Macの場合(Tunnelblickの設定)](https://dev.classmethod.jp/articles/openvpn24-aws/#toc-15)
- [Tunnelblick公式ドキュメント](https://tunnelblick.net/downloads.html)
- [【Client VPN】OpenVPN easy-rsaでサーバ証明書の有効期限を100年にする](https://blog.denet.co.jp/easy-rsa_validity/)
- [特定クライアントのクライアント VPN エンドポイントへのアクセスを取り消すにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/client-vpn-revoke-access-specific-client/)