Amazon RDS インスタンスに対して CIDR の異なる複数のエンドポイントを作成する方法を検討してみた

2024.01.22

いわさです。

Amazon RDS でデータベースをホスティングする際に、コストなど何かしらの事情によって、本番環境と開発環境を同一インスタンス上の異なるデータベースとして混在させる場合が稀にあります。
この場合、本番環境と開発環境からそれぞれのクライアントで同一エンドポイントへアクセスする形となります。

この時、組織上のポリシーなどから、本番環境と開発環境のエンドポイントを分けたいというケースがありました。
RDS ではエンジンによってリードレプリカを追加してエンドポイントを増やすことは出来るのですが、今回期待するものとはちょっと違っています。
また、自由にエンドポイントを追加する機能は本日時点では無いようです。

名前解決でエンドポイントを分ける方法

まず最初に思いついたのが名前解決の仕組みを使って本番用と開発用のエンドポイントを分ける方法です。
次のように RDS のデフォルトエンドポイント宛にレコードを登録してやる感じです。

これが出来れば簡単だったのですが、今回はクライアントの NACL などで接続制限を行う必要がありました。
具体的には開発用クライアントから本番 RDS エンドポイントへの接続を拒否する必要がありました。(接続されてしえば同一インスタンス内なので、データベースユーザーで制御するなど他の分離の仕組みが必要ではあるのですが)

なので、それぞれのエンドポイントに別々の IP アドレスを割り当てる必要がありました。

NLB でエンドポイントを分ける方法

別々の IP アドレスを割り当てるということで RDS に複数の ENI をアタッチできんかなと思ったのですが、RDS では実現出来ないようです。
EC2 であれば Multi-VPC ENI というのが最近登場したので、別々の CIDR 範囲の ENI を割り当てることも出来るようになりました。

そうなると NLB (Network Load Balancer) になるのかなと思いました。
これはですね、次の記事で紹介されています。

NLB 経由で RDS への接続自体は出来ます。なので別々の CIDR のエンドポイントを用意することは出来そうです。
ただし、上記記事にて「運用の考慮点」として紹介されていますがいくつか注意事項があります。
私も実際に試してみたのですが、接続が突然切断されたりと、安定性を得るためにはそのまま NLB を配置するだけでなく、色々と設定が必要そうでした。

RDS Proxy でエンドポイントを分ける方法

RDS Proxy はどうかなと思ったのですが、知らなかったのですが RDS Proxy は任意のエンドポイントを追加する機能があります。なんと。

しかも別のネットワークを指定してエンドポイントを作成出来ますね。
仕組みとしては PrivateLink で別のネットワークへ経路を拡張しているようです。これはまさに今回やりたかったことかもしれない。

今回はたまたま良かったのですが、RDS Proxy を使う際にはリードレプリカが使えなかったりと、いくつか制限事項があるので注意が必要です。

やってみた

作成済みの RDS に RDS Proxy を作成・接続し、そこからエンドポイントを本番用、開発用のネットワークへ作成します。
注意点として RDS Proxy 自体は RDS と同じネットワークに存在している必要があります。

完成イメージはこんな感じです。(実際には PrivateLink ですし、RDS Proxy 本体を中継する形になるのですが、便宜上 RDS Proxy アイコンを使いました)

ちなみに RDS インスタンス本体はパスワード認証です。
まずは RDS Proxy を作成します。RDS Proxy ではデータベースへの接続に Secrets Manager が必須なので、RDS 接続用のシークレットを作成し RDS に関連付ける必要があります。

まずは次の状態で RDS Proxy が機能しているところまで確認しましょう。

sh-5.2$ psql -h hoge0122proxy.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com -U productadmin
Password for user productadmin:psql (15.5, server 15.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, compression: off)Type "help" for help.

productadmin=>

良さそうです。
確認出来たらエンドポイントを追加します。
事前に本番・開発用のネットワークを用意してあります。

また、RDS Proxy のエンドポイント作成時には異なる AZ のサブネットを 2 つ以上指定する必要があります。

作成出来たそれぞれのエンドポイントの名前解決を行ってみると期待どおり本番 VPC、開発 VPC の CIDR が割り当てられています。

% nslookup hoge0122proxy.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com
Server:		127.0.2.2
Address:	127.0.2.2#53

Non-authoritative answer:
hoge0122proxy.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com	canonical name = vpce-0a0f1f8bc24ad347a-0unx3j33.vpce-svc-0fc8494a423dc749d.ap-northeast-1.vpce.amazonaws.com.
Name:	vpce-0a0f1f8bc24ad347a-0unx3j33.vpce-svc-0fc8494a423dc749d.ap-northeast-1.vpce.amazonaws.com
Address: 192.168.133.208
Name:	vpce-0a0f1f8bc24ad347a-0unx3j33.vpce-svc-0fc8494a423dc749d.ap-northeast-1.vpce.amazonaws.com
Address: 192.168.157.137

% nslookup product.endpoint.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com
Server:		127.0.2.2
Address:	127.0.2.2#53

Non-authoritative answer:
product.endpoint.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com	canonical name = vpce-029084c96578cf721-hxybqkmg.vpce-svc-0cc2e7d14f73f38b8.ap-northeast-1.vpce.amazonaws.com.
Name:	vpce-029084c96578cf721-hxybqkmg.vpce-svc-0cc2e7d14f73f38b8.ap-northeast-1.vpce.amazonaws.com
Address: 10.1.128.107
Name:	vpce-029084c96578cf721-hxybqkmg.vpce-svc-0cc2e7d14f73f38b8.ap-northeast-1.vpce.amazonaws.com
Address: 10.1.150.104

% nslookup develop.endpoint.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com
Server:		127.0.2.2
Address:	127.0.2.2#53

Non-authoritative answer:
develop.endpoint.proxy-cpnu9ipu74g4.ap-northeast-1.rds.amazonaws.com	canonical name = vpce-02fb7eeecbd10b907-6bi1xqzf.vpce-svc-0cc2e7d14f73f38b8.ap-northeast-1.vpce.amazonaws.com.
Name:	vpce-02fb7eeecbd10b907-6bi1xqzf.vpce-svc-0cc2e7d14f73f38b8.ap-northeast-1.vpce.amazonaws.com
Address: 10.2.141.44
Name:	vpce-02fb7eeecbd10b907-6bi1xqzf.vpce-svc-0cc2e7d14f73f38b8.ap-northeast-1.vpce.amazonaws.com
Address: 10.2.152.175

あとはそれぞれのクライアントで CIDR 制限など行いつつ接続テストを行ってみます。
次は本番想定のネットワークに存在するクライアントから接続した場合です。

本番用の RDS Proxy エンドポイントには接続が出来て、開発用の RDS Proxy エンドポイントへの接続はタイムアウトとなりました。

逆に開発用のクライアントからは本番用エンドポイントへの接続がタイムアウトになりました。

RDS Proxy のシークレットをうまく切り替えることでデータベース接続時のユーザーを切り替えれるかなとも思ったのですが、今回の仕組みは RDS Proxy 本体から PrivateLink でエンドポイントが拡張されている感じなので、シークレットなどはエンドポイント全体で共用する形となります。

料金について

RDS Proxy の料金とエンドポイント追加の料金を気にする必要があります。
RDS Proxy の料金は接続先のデータベースの vCPU ごとの時間あたりの料金となっています。

追加のエンドポイントについては RDS Proxy としては料金は発生しないのですが、PrivateLink の料金が発生します。
PrivateLink はプロビジョニングされている間ずっと料金が発生するのに加えて、エンドポイントが処理するデータ量に応じた従量課金となっています。

試しに RDS for PostgreSQL の r5.2xlarge あたりで試算してみました。
通常だと 880.14 USD/月の料金ですが、RDS Proxy + 追加エンドポイント 2 つだと 1,026.14 USD/月(データ処理量含まず)となりました。内訳としては RDS + Proxy で 985.26 USD/月、Private Link で 40.88 USD/月です。2 割増しくらいですかね。

さいごに

本日は Amazon RDS インスタンスに対して CIDR の異なる複数のエンドポイントを作成する方法を検討してみました。

RDS Proxy でエンドポイント追加出来るのは知らなかったです。こういったネットワーク分離的な目的での使い方も出来ますね。
RDS Proxy が採用出来ないシーンもあると思うのですが、NLB と違って考慮事項少なそうで、AWS の機能にお任せしやすいというか、心理的にだいぶ採用しやすいです。