インターネットに閉じられたVPCにVPN接続

# インターネットに閉じられたVPCにVPN接続 

## 背景など

たまには、セキュアなVPCがしたいですよね。
とくにVPCへインターネットからの接続が不要な場合（データ処理系など）IGW・NATの用意が不要で面倒ですね。
でも接続ができないとVPC内の設定やテストなどが難しい。

じゃ、そのときにBASTIONサーバ・IGW・NATをやめて、VPNClientで接続すればいいじゃん。

## VPNってなんだっけ？

VirtualPrivateNetwork  (VPN)は、セキュアな接続が可能になります。
SSHも同様のものですが、SSHするために、EC2/NAT/IGWの導入が必要になります。

どっちがいいかといわれると、管理が楽、設置が簡単なものを優先します。

でも正直、この場合、どっちも一緒かな。
じゃ、コストみると、VPN Clientの方が高い印象です。

VPN Clientの場合、下記のものに対して下記されます：

- AWS Client VPN endpoint association (クライエントVPNエンドポイントアソシエーション)
    -  $0.15/h (ap-northeast-1 TOKYO)
- AWS Client VPN connection (クライエントVPN接続）
    - $0.10/h/connection (ap-northeast-1 TOKYO)


Vs NAT/IGW/EIP/EC2:

- NAT Gateway 
    - $0.062 (ap-northeast-1 TOKYO)/h
- EIP
    - $0.005 (ap-northeast-1 TOKYO)/h
- EC2 t2.micro:
    - $0.0152/h

ということで、ケース　バイ　ケースにしましょう。
今回使うニーズは、DX(DirectConnect)と同様な接続したいので、VPN ClientがNAT/IGW経由より、DXに近いかなと思ってやってみました。


## Prerequisites

- AWS Account
- Linux(like) System
    - こちらでUBUNTU 18.04でやっています
- awscli



## OpenVPN用の証明書とキーを用意

0. ローカルで作業DIRを作成:

    ```bash
    mkdir ~/prepare-aws-vpn-client
    ```

1. OpenVPN/easy-rsaを取得:
    
    > [OpenVPN/easy-rsa](https://github.com/OpenVPN/easy-rsa) がRSAキーや証明書用意する作業を楽にしてくれるツール

    ```bash
    cd ~/prepare-aws-vpn-client
    git clone https://github.com/OpenVPN/easy-rsa.git
    ```


2. Public Key Infrastructure (PKI) を作成

    ```bash
    cd easy-rsa/easyrsa3
    
    # run `easyrsa init-pki` to build the PublicKeyInfrastructure (PKI)
    ./easyrsa init-pki
    ```

3. 証明書作成用のCertificate Authority (CA)を構築:
 
    ```bash
    ./easyrsa build-ca nopass

    # Enter, "rcs-vpn-ca" for Common Name.
    Common Name (eg: your user, host, or server name) [Easy-RSA CA]:rcs-vpn-ca

    CA creation complete and you may now import and sign cert requests.
    Your new CA certificate file for publishing is at:
    ~/prepare-aws-client-vpn/easy-rsa/easyrsa3/pki/ca.crt
    ```

4. サーバ用とクライエント用の証明書とキーを作成:

    ```bash
    # create server private key for signing and certificate
    ./easyrsa build-server-full server nopass

    # create client private key for signing and certificate
    ./easyrsa build-client-full client1.vpn.tld nopass

    ```

5. 作業が楽になるよう、サーバ・クライエントの証明書とキーを収集:

    ```bash
    mkdir /tmp/aws-vpn/
    
    # copy CA certificate
    cp pki/ca.crt /tmp/aws-vpn/

    # collect server cert/key
    cp pki/issued/server.crt /tmp/aws-vpn/
    cp pki/private/server.key /tmp/aws-vpn/
    
    # collect cliet cert/key
    cp pki/issued/client1.vpn.tld.crt /tmp/aws-vpn/
    cp pki/private/client1.vpn.tld.key /tmp/aws-vpn/

    # check certs/keys were successfully copied
    ls -lrt /tmp/aws-vpn/
    ```

## AWS ACMに作成したサーバ・クライエントの証明書とキーをインポート:

0. awscli用のプロファイル `AWS_PROFILE`　を設定:

    ```bash
    export AWS_PROFILE={YOUR APPROPRIATE AWS PROFILE}
    ```

1. AWS ACMに作成したサーバの証明書とキーをインポート:

    ```bash
    aws acm import-certificate --certificate file:///tmp/aws-vpn/server.crt --private-key file:///tmp/aws-vpn/server.key --certificate-chain file:///tmp/aws-vpn/ca.crt
    ```

2. AWS ACMに作成したクライエントの証明書とキーをインポート:

    ```bash
    aws acm import-certificate --certificate file:///tmp/aws-vpn/client1.vpn.tld.crt --private-key file:///tmp/aws-vpn/client1.vpn.tld.key --certificate-chain file:///tmp/aws-vpn/ca.crt
    ```

3. AWS ACMに正しくインポートできたかを確認:

    ```bash
    aws acm list-certificates
    # both server & client1.vpn.tld should be displayed in the output
    ```

4. VPN接続ログ用のCloudwatch LogGroup/LogStreamを作成:

    ```bash
    aws logs create-log-group --log-group-name vpn-client-logs
    aws logs create-log-stream --log-group-name vpn-client-logs --log-stream-name connections
    ```


5. クライエントVPNエンドポイントを作成:

    ```bash
    aws ec2 create-client-vpn-endpoint --client-cidr-block "10.0.208.0/22" \
        --server-certificate-arn $(aws acm list-certificates --query 'CertificateSummaryList[?DomainName==`server`].CertificateArn' --output text) \
        --authentication-options Type=certificate-authentication,MutualAuthentication={ClientRootCertificateChainArn=$(aws acm list-certificates --query 'CertificateSummaryList[?DomainName==`client1.vpn.tld`].CertificateArn' --output text)} \ 
        --connection-log-options Enabled=true,CloudwatchLogGroup=vpn-client-logs,CloudwatchLogStream=connections
    ```

6. VPCにクライエントVPNエンドポイントをアソシエイト:

    > NOTE: 少なくともVPCに'public'のTagValueが存在すると想定
    > 1 クライエントVPNエンドポイントのみが存在と想定

    ```bash
    export RCS_VPCID={YOUR TARGET VPC}
    aws ec2 associate-client-vpn-target-network \
        --client-vpn-endpoint-id $(aws ec2 describe-client-vpn-endpoints --query 'ClientVpnEndpoints[0].ClientVpnEndpointId' --output text) \
        --subnet-id $(aws ec2 describe-subnets --query 'Subnets[?VpcId==`'$RCS_VPCID'` && Tags[?Value==`public`]].SubnetId | [0]' --output text)
    ```

7. VPCのセグメント（10.0.0.0/16）にVPNエンドポイントの接続を許可:

    > NOTE: Defined CIDR here is specific to prepared VPC, may need to update in your case.

    ```bash
    aws ec2 authorize-client-vpn-ingress \
        --client-vpn-endpoint-id $(aws ec2 describe-client-vpn-endpoints --query 'ClientVpnEndpoints[0].ClientVpnEndpointId' --output text) \
        --target-network-cidr "10.0.0.0/16" \
        --authorize-all-groups
    ```

8. ローカルPCでクライエントVPNエンドポイント用のクライエント設定ファイルをダウンロード:

    > NOTE: 1 クライエントVPNエンドポイントのみが存在と想定

    ```
    aws ec2 export-client-vpn-client-configuration --client-vpn-endpoint-id $(aws ec2 describe-client-vpn-endpoints --query 'ClientVpnEndpoints[0].ClientVpnEndpointId' --output text) \
        --query 'ClientConfiguration' --output text > ~/client-configuration.ovpn
    ```

9. ローカルにあるクライエントの証明書とキー情報をクライエント設定ファイル（*.ovpn）に追加:

    ```bash
    echo "cert /tmp/aws-vpn/client1.vpn.tld.crt" >> ~/client-configuration.ovpn
    echo "key /tmp/aws-vpn/client1.vpn.tld.key" >> ~/client-configuration.ovpn 
    ```

##  VPN(openvpn)で接続

0. `openvpn` をインストール (ubuntu):

    ```bash
    sudo apt install openvpn
    ```

1. クライエント設定ファイル（*.ovpn）を使って、VPNで接続:

    ```
    sudo openvpn --config ~/client-configuration.ovpn
    ```