マルチアカウント環境でTransitGatewayを経由してVPC LambdaからRDSにデータを登録してみた
はじめに
最近2つのアカウント間でTransit Gatewayを介してVPC LambdaからRDSへデータを登録したいことがありました。
特別な要件がなければ異なるアカウントのVPC間の通信はVPC PeeringやPrivateLinkを使って接続する方法が簡単かつコストも安く済みます。
ただ、企業のセキュリティ要件等でTransit Gatewayを経由することを求められることもあるかと思います。
Transit Gatewayを使う構成で私が気にしていたポイントはVPC LambdaからRDSへアクセスする際に名前解決の仕組みなどを別途設ける必要があるのか、ないのかという点が気になりました。
Transit Gatewayでアカウント間のEC2を接続するといったブログは見かけますが、VPC LambdaからRDSへデータを登録するブログが見当たらなかったのでやってみました。
先に結論
先に結論を言うと、アカウントを跨いだVPC Lambda→RDSのアクセスに特別な名前解決の仕組みは不要でした。
以下の設定が正しく設定されていれば通信が可能でした。
- VPCのDNS解決が有効になっている
- Transit Gatewayのルーティング
- セキュリティグルール
構成
構成図はこんな感じになります。
この構成でLambdaからRDSにデータ登録できるのかやってみます。
Transit Gatewayの構築作業はこちらのブログを参考にさせて頂きました。
詳細は上記のブログに書かれているので、この記事ではTransit GatewayおよびRAMによる共有箇所は大枠のみ書いていきます。
事前準備
ネットワークは以下のものをすでに準備済みとします。
どちらのVPCも「DNS 解決」を有効化しています。
アカウントAのVPC(Lambda側)
項目 | 値 |
---|---|
VPC CIDR | 10.0.0.0/16 |
Sunet CIDR | 10.0.128.0/28 |
アカウントBのVPC B(RDS側)
項目 | 値 |
---|---|
VPC CIDR | 10.1.0.0/16 |
Sunet CIDR | 10.1.128.0/28 |
正確にはアカウントBのVPCにはRDSサブネットグループ作成用にサブネットが2つ必要ですが、今回は使用しないので記載しておりません。
Transit Gateway作成
アカウントAの作業
まずはTransit Gatewayを作成します。
Transit Gateway > Transit Gatewayを作成 の順に進みます。
アタッチメントの承認作業が面倒なので、「共有アタッチメントを自動承認」をONにしています。
他はデフォルトのままTransit Gatewayを作成します。
アタッチメント作成(アカウントA)
アカウントAの作業
次にTransit Gatewayのアタッチメントを作成します。
Transit Gateway アタッチメント > Transit Gateway アタッチメントを作成 の順に進みます。
名前タグ、Transit Gateway ID, VPC IDを適宜入力してアタッチメントを作成します。
サブネットはアカウントAのプライベートサブネットに配置しています。
Resource Access Managerでリソース共有
アカウントAの作業
次にアカウントAのResource Access Managerを使ってアカウントBにTransit Gatewayを共有します。
Resource Access Manager > リソース共有を作成の順に進みます。
アカウントIDを入力して「追加」をクリックすると、選択されたプリンシパル一覧に追加したアカウントが表示されます。
これでアカウントBにTransit Gatewayを共有できました。
共有の承諾
アカウントBの作業
次はアカウントBでの作業になります。
アカウントAで共有したTransit GatewayをアカウントBで承諾します。
Resource Access Manager > リソースの共有 の順に進み、アカウントAで作成したRAMを選択します。
「リソース共有を承認」をクリックします。
これでアカウントAのTransit Gatewayに繋がるアタッチメントをアカウントBから作成できるようになりました。
アタッチメント作成(アカウントB)
アカウントBの作業
次にアカウントBでアタッチメントを作成します。
(共有アタッチメントを自動承諾を無効にしている場合、この後アカウントAでアタッチメント作成を承諾する必要があります。)
ルート追加
アカウントA, Bの作業
アカウントA, アカウントBそれぞれのサブネットでTransit Gatewayへのルートを追加します。
これでネットワークの設定は完了しました。
それではVPC LambdaとRDSを作成して、疎通できるのか確認したいと思います。
RDS
RDSのエンドポイントをコピーしておきます。
これは次に作成するLambdaのRDS_HOSTという環境変数に代入します。
セキュリティグループ
RDSのセキュリティグループはVPC Lambdaが配置されたVPCのCIDRからのインバウンドを許可しています。
(より厳密に通信を制限する場合はサブネットのCIDR範囲を指定してください)
プロトコル | ポート | ソース |
---|---|---|
TCP | 3306 (RDSのデフォルトポート) | 10.0.0.0/16 |
VPC Lambda
LambdaはRDS(mysql)にテストデータを登録するVPC Lambdaを用意しました。
VPCに配置する以外はデフォルトの設定で作成しています。
コードは次のとおりです。
RDSの接続情報は環境変数に入れています。
import json
import pymysql
import os
def lambda_handler(event, context):
# RDS接続
connection = pymysql.connect(
host=os.environ['RDS_HOST'],
user=os.environ['RDS_USERNAME'],
password=os.environ['RDS_PASSWORD'],
db=os.environ['RDS_DATABASE']
)
try:
with connection.cursor() as cursor:
# テーブル作成
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50))")
# サンプルデータ挿入
cursor.execute("INSERT INTO users (name) VALUES ('テストユーザー')")
connection.commit()
return {'statusCode': 200, 'body': 'データ登録完了'}
finally:
connection.close()
環境変数は以下を設定しています。
それぞれ必要な情報はアカウントBのRDSから取得しています。
キー | 値 |
---|---|
RDS_HOST | <RDSのエンドポイント> |
RDS_USERNAME | <user_name> |
RDS_PASSWORD | <password> |
RDS_DATABASE | <RDSのDB識別子> |
セキュリティグループ
LambdaのセキュリティグループはRDSに対するアウトバウンドのみ設定しています。
プロトコル | ポート | 送信先 |
---|---|---|
TCP | 3306 (RDSのデフォルトポート) | 10.1.0.0/16 |
LambdaとRDSの準備が整ったので、あとはLambdaを実行するだけです。
疎通確認
それではLambdaを実行してDBの中身を確認します。
(DBの中身を確認する用のEC2を別途立てて確認しています)
mysql> SHOW TABLES;
+--------------------+
| Tables_in_sampledb |
+--------------------+
| users |
+--------------------+
1 row in set (0.00 sec)
mysql> SHOW columns FROM users;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
データが登録されていますね。
まとめ
それぞれのアカウントで
- VPCのDNS解決を有効化、
- Transit Gatewayのルーティング
- セキュリティグループ
を正しく設定した上で、LambdaからRDSのエンドポイントにアクセスするだけ。ということがわかりました。
私が気になっていた名前解決の部分もRoute53 プライベートホストゾーンなどは不要でした。
どうしてもTransit Gateway経由でVPC LambdaからRDSへデータ登録したい!という場合には参考にしてみてください。