はじめに
AWSを実務で利用する際、サーバーレスアーキテクチャの核となる「AWS Lambda」から、プライベートネットワーク(VPC)内にある「Amazon RDS」などのデータベースにアクセスしたいケースは頻繁に発生します。しかし、デフォルト設定のLambdaはVPC外に配置されているため、適切なネットワーク設計とセキュリティ設定を行わなければ通信できません。
この記事では、LambdaからVPC内のRDS(PostgreSQL)へ、セキュリティを担保しつつ安全に接続するための具体的な設定手順と、実務でハマりやすいポイントをステップバイステップで解説します。
前提知識/必要な理由
RDSなどのデータベースは、機密性の高いデータを扱うため、インターネットから直接アクセスできないプライベートサブネットに配置するのが原則です。このセキュアな環境にあるRDSにLambdaから接続するためには、Lambda関数自体を同一VPC(またはピアリングされたVPC)内に配置(VPC Lambda化)する必要があります。
VPC Lambda化を行うことで、LambdaはVPC内のプライベートIPアドレスを持ち、インターネットを経由せずにRDSと直接セキュアに通信できるようになります。また、通信を制御するために、双方のリソースに適切な「セキュリティグループ」を設定することが不可欠です。
具体的な設定手順・設計方法
今回は、Pythonを用いてVPC内のRDS(PostgreSQL)に安全に接続するシステムを構築します。大まかな手順は以下の通りです。
1. セキュリティグループの設計・作成
まずは、LambdaとRDSの間で安全に通信を行うためのセキュリティグループ(SG)を2つ作成します。
- Lambda用セキュリティグループ(例: sg-lambda):アウトバウンド(送信)はすべてのトラフィックを許可し、インバウンド(受信)は空にします。
- RDS用セキュリティグループ(例: sg-rds):インバウンドルールに、上記の「sg-lambda」からの、Port 5432(PostgreSQLのデフォルトポート)のアクセスのみを許可するように設定します。
2. Lambda関数の作成とVPC設定
AWS管理コンソールからLambda関数を作成し、VPC設定を行います。
- Lambda関数の作成時、または作成後の「設定」タブ > 「VPC」から「編集」を選択します。
- RDSが配置されているVPC、およびプライベートサブネットを2つ以上(高可用性のため)選択します。
- 上記で作成した「Lambda用セキュリティグループ(sg-lambda)」をアタッチします。
3. 外部ライブラリ(psycopg2)のLambdaレイヤー適用
PythonからPostgreSQLに接続するにはpsycopg2ライブラリが必要ですが、Lambdaの標準環境には含まれていません。そのため、Lambdaレイヤーとしてアップロードして導入します。
以下のコマンドを実行して、Lambdaの実行環境(例:Python 3.9 / Linux)と互換性のあるライブラリパッケージ(psycopg2-binary)をローカルでビルドし、zipに固めてレイヤーとして登録します。
# 作業用ディレクトリの作成
mkdir -p python/lib/python3.9/site-packages
cd python/lib/python3.9/site-packages
# LambdaのOS(Amazon Linux 2など)と互換性のあるバイナリをインストール
pip install --platform manylinux2014_x86_64 --only-binary=:all: psycopg2-binary -t .
# zip圧縮
cd ../../../
zip -r psycopg2-layer.zip python/
作成されたpsycopg2-layer.zipをAWS Lambdaのコンソールから「レイヤー」として登録し、作成したLambda関数にアタッチします。
4. 接続用Lambdaコードの実装
準備が整ったら、以下の接続確認用のPythonコードをLambda関数(lambda_function.py)に記述してテストを実行します。データベースの接続情報は、Lambda環境変数に登録して呼び出します。
import os
import psycopg2
def lambda_handler(event, context):
# 環境変数から接続情報を取得
db_host = os.environ['DB_HOST']
db_name = os.environ['DB_NAME']
db_user = os.environ['DB_USER']
db_password = os.environ['DB_PASSWORD']
try:
# RDSに接続
conn = psycopg2.connect(
host=db_host,
database=db_name,
user=db_user,
password=db_password,
connect_timeout=5
)
cur = conn.cursor()
cur.execute("SELECT version();")
db_version = cur.fetchone()
cur.close()
conn.close()
return {
'statusCode': 200,
'body': f"接続成功!データベースバージョン: {db_version[0]}"
}
except Exception as e:
print(f"接続エラー: {e}")
return {
'statusCode': 500,
'body': "データベースへの接続に失敗しました。"
}
実務での注意点
- ENI(Elastic Network Interface)の作成オーバーヘッド(コールドスタート):現在のAWS仕様では改善されていますが、初回起動時にはVPC内にENIが作成されるため、起動が数十秒遅延することがあります。重要なAPIなど、低レイテンシーが求められるシステムでは「プロビジョニングされた同時実行(Provisioned Concurrency)」の利用を検討してください。
- データベースのコネクション管理:Lambdaは並行して多数のインスタンスが起動するため、何も対策をしないとRDSの最大接続数(Max Connections)をすぐに超過してしまいます。実務では、接続をプールして効率化する「Amazon RDS Proxy」の導入を強く推奨します。
- インターネットへの通信経路:VPC内に配置されたLambdaは、そのままでは外部のAPIやS3などのパブリックサービスと通信できません。インターネットアクセスが必要な場合は、サブネットのルートテーブルにNAT Gatewayを設定する必要があります。
まとめ
AWS LambdaからVPC内のRDSへの接続は、インフラ設計において基礎でありながら、セキュリティの観点から非常に重要なポイントです。セキュリティグループを厳密に制限し、psycopg2などの外部パッケージをレイヤー機能でスマートに管理することで、保守性の高いセキュアなサーバーレスシステムを構築できます。実務で設計する際は、さらにコネクション制限への対策としてRDS Proxyの併用も考慮に入れましょう。