Aiven に AWS Client VPN 経由でセキュアに接続する

Aiven へ VPN 経由でセキュアに接続するための内容です。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ウィスキー、シガー、パイプをこよなく愛する大栗です。

クライアント PC からクラウド上のデータベースに直接接続しようとするとセキュリティ面で不安になりますよね。ユーザー ID とパスワードだけの認証だとインターネットでパブリックに公開するのはためらわれるのでセキュアなネットワークを経由してデータベース(今回は Aiven を使用)に接続しようと思います。

Aiven と AWS Client VPN のネットワーク概要

以下のような概要になります。AWS Client VPN を経由するので AWS に VPC を作成して Aiven とピアリング接続を行います。また VPN の認証は相互認証とします。

今回は自分の VPC の CIDR を172.16.0.0/16、Aiven の CIDR を10.1.0.0/20で設定しています。

やってみた

まずは、Aiven と AWS の VPC をピアリング接続します。

以下のエントリを参考に、1. Aiven の VPC を作成する4. Aiven サービスを作成するを行います。

次に AWS の VPC に Client VPN の設定を実施します。

まずは Client VPN 用のログ出力先を作成します。

CloudWatch のロググループの画面からロググループを作成をクリックします。

ロググループの名称を設定して作成をクリックします。ここでは/aiven/cvpnとしました。

次にログストリームを作成します。先ほど作成したロググループのリンクをクリックします。

ログストリームを作成をクリックします。

ログストリーム名を入力してCreateをクリックします。ここではconnection-logとしました。

次に VPN の認証のための証明書を作成します。

ドキュメントの手順通りに相互認証のための証明書を作成します。

OpenVPN easy-rsa リポジトリをクローンします。

$ git clone https://github.com/OpenVPN/easy-rsa.git
Cloning into 'easy-rsa'...
remote: Enumerating objects: 2095, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 2095 (delta 3), reused 4 (delta 0), pack-reused 2082
Receiving objects: 100% (2095/2095), 11.72 MiB | 10.37 MiB/s, done.
Resolving deltas: 100% (916/916), done.

easy-rsa のディレクトリへ移動します。

$ cd easy-rsa/easyrsa3

新しい PKI 環境を初期化します。

$ ./easyrsa init-pki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /file/to/path/easy-rsa/easyrsa3/pki

新しい認証局 (CA) を構築します。途中入力を求められますが。今回はコモンネームをデフォルト(そのまま決定)にしています。

$ ./easyrsa build-ca nopass
Using SSL: openssl OpenSSL 1.0.2k-fips  26 Jan 2017
Generating RSA private key, 2048 bit long modulus
..........................+++
......................................+++
e is 65537 (0x10001)
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: #

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/file/to/path/easy-rsa/easyrsa3/pki/ca.crt

サーバー証明書とキーを生成します。

$ ./easyrsa build-server-full server nopass
Using SSL: openssl OpenSSL 1.0.2k-fips  26 Jan 2017
Generating a 2048 bit RSA private key
............................+++
..........................+++
writing new private key to '/file/to/path/easy-rsa/easyrsa3/pki/easy-rsa-1507.Tkprxk/tmp.iOdaW7'
-----
Using configuration from /file/to/path/easy-rsa/easyrsa3/pki/easy-rsa-1507.Tkprxk/tmp.4Y2U0b
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Apr 24 08:32:16 2024 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

クライアント証明書とキーを生成します。

$ ./easyrsa build-client-full client1.domain.tld nopass
Using SSL: openssl OpenSSL 1.0.2k-fips  26 Jan 2017
Generating a 2048 bit RSA private key
.............+++
...........................................+++
writing new private key to '/file/to/path/easy-rsa/easyrsa3/pki/easy-rsa-1725.nMAe8A/tmp.b5n1Tf'
-----
Using configuration from /file/to/path/easy-rsa/easyrsa3/pki/easy-rsa-1725.nMAe8A/tmp.6rVkpl
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'client1.domain.tld'
Certificate is to be certified until Apr 24 08:33:34 2024 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

証明書類を別ディレクトリにコピーします。

mkdir ~/aiven-vpn/
cp pki/ca.crt ~/aiven-vpn/
cp pki/issued/server.crt ~/aiven-vpn/
cp pki/private/server.key ~/aiven-vpn/
cp pki/issued/client1.domain.tld.crt ~/aiven-vpn
cp pki/private/client1.domain.tld.key ~/aiven-vpn/
cd ~/aiven-vpn/

サーバー証明書を ACM へアップロードします。

$ aws acm import-certificate --certificate fileb://server.crt --private-key fileb://server.key --certificate-chain fileb://ca.crt
{
    "CertificateArn": "arn:aws:acm:ap-northeast-1:123456789012:certificate/a1b2c3d4-1234-abcd-1234-1a2b3c4d5e6f"
}

クライアント証明書を ACM へアップロードします。

$ aws acm import-certificate --certificate fileb://client1.domain.tld.crt --private-key fileb://client1.domain.tld.key --certificate-chain fileb://ca.crt
{
    "CertificateArn": "arn:aws:acm:ap-northeast-1:123456789012:certificate/1a2b3c4d-abcd-1234-abcd-a1b2c3d4e5f6"
}

次に Client VPN のエンドポイントを作成します。

VPC のクライアント VPN エンドポイントの画面からクライアント VPN エンドポイントの作成をクリックします。

名前タグに任意の名称を設定します。ここではaiven-cvpnとしています。また、クライアント IPv4 CIDR では、各 VPC やローカルマシンがアクセスしない IP アドレス帯をせっています。ここでは100.64.0.0/22を設定します(100.64.0.0/22 は ISP Shared Address ですが、もし影響がある場合は別のものに変更してください)。

サーバー証明書 ARN は、先程アップロードしたサーバー証明書の ARN を設定します。クライアント証明書 ARN は、アップロードしたクライアント証明書の ARN を設定します。

接続の詳細を確認するためクライアント接続の詳細を記録しますか?はいを設定して、CloudWatch Logs ロググループ名と CloudWatch Logs ログストリーム名に作成したものを設定します。

スプリットトンネルを有効にするをチェックして、クライアント VPN エンドポイントの作成をクリックします。

Client VPN のエンドポイントが作成されました。

次のクライアント VPN エンドポイントをサブネットと関連付けます。

作成したクライアント VPN エンドポイントを選択して、関連付けタブを表示します。ここで関連付けをクリックします。

エンドポイントを関連付ける VPC とサブネットを選択して、関連付けをクリックします。

これでクライアント VPN エンドポイントがサブネットに関連付けられました。

次に認証ルールを設定します。まずは、接続している VPC を追加します。

認証タブで受信の承認をクリックします。

アクセスを有効にする送信先ネットに接続している VPC の CIDR(ここでは 172.16.0.0/16)を入力して認証ルールの追加をクリックします。

認証ルールが追加されました。

次に Aiven 側の VPC の CIDR の認証ルールを追加します。先程と同様に受信の承認クリックします。

アクセスを有効にする送信先ネットに Aiven の VPC の CIDR(ここでは 10.1.0.0/20)を入力して認証ルールの追加をクリックします。

認証ルールが追加されました。

クライアント VPN エンドポイントのルートテーブルも追加します。ルートテーブルタブでルートの作成をクリックします。

ルート送信先に Aiven の VPC の CIDR を入力して、ターゲット VPC サブネット ID にクライアント VPN エンドポイントを設定しているサブネットを選択します。そしてルートの作成をクリックします。

クライアント設定のテンプレートファイルをダウンロードします。クライアント設定のダウンロードをクリックします。

対象のクライアント VPN エンドポイントか確認してダウンロードをクリックします。するとdownloaded-client-config.ovpnをダウンロードします。

downloaded-client-config.ovpnを編集していきます。downloaded-client-config.ovpnの末尾に``タグを追加して、中身はclient1.domain.tld.crtの最後の証明書部分を入力します。

<cert>
-----BEGIN CERTIFICATE-----
・
# client1.domain.tld.crt の内容
・
-----END CERTIFICATE-----
</cert>

さらにdownloaded-client-config.ovpnの末尾に追加します。``タグを追加して、中身はclient1.domain.tld.keyの内容を入力して保存します。

<key>
-----BEGIN PRIVATE KEY-----
・
# client1.domain.tld.key の内容
・
-----END PRIVATE KEY-----
</key>

最後にクライアント側の設定を行います。

AWS Client VPN のダウンロードページからご自身の環境にあった AWS Client VPN for Desktop をダウンロードします。Linux 版ではインストールドキュメントが表示されますので、内容に従いインストールします。

ダウンロードしたファイルを実行してインストールを進めます。

使用許諾契約も内容を確認しましょう。

インストールが終わったら AWS VPN Client を実行します。

メニューの [ファイル] > [プロファイルを管理] を選択します。

プロファイルを追加をクリックします。

表示名を入力します。ここではAiven VPNとします、VPN 設定ファイルに編集したdownloaded-client-config.ovpnを指定してプロファイルを追加をクリックします。

完了をクリックします。

Aiven VPNを選択して接続をクリックします。

これで VPN 経由で Aiven にネットワークが繋がりました。

psql で接続してみます。

% psql -h pg-vpn-1-hajime-ff19.aivencloud.com -p 12492 -U avnadmin -d defaultdb
Password for user avnadmin:  # パスワードを入力
psql (14.1, server 13.5)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

defaultdb=> select inet_server_addr();
 inet_server_addr
------------------
 10.1.5.171
(1 row)

このように VPN 経由で安全に Aiven へ接続が可能になりました。

最後に

Aiven と言いながらはネットワークに関するエントリーでした。本内容は基本的にクライアント VPN 経由で VPC Peering した先へアクセスする時に設定になっています。ポイントとしては、認証ルールとルートテーブルにピアリング先の CIDR を追加することです。

AWS の場合にセキュアに接続する手順を書いたので、次は Google Cloud 版も書いてみようかと思います。