はじめに
AWSのサーバーレスアーキテクチャ設計において、AWS LambdaからAmazon RDS(リレーショナルデータベース)に接続する構成は非常によく使われます。しかし、ネットワーク設定やセキュリティグループ(SG)の設定が正しく行われていないと、データベースが外部に露出してしまったり、逆にLambdaからRDSに接続できずにタイムアウトエラーが発生したりします。
この記事では、セキュリティのベストプラクティスに則り、Lambdaからプライベートサブネット内のRDSに安全に接続するためのVPC設定とセキュリティグループの手順をステップバイステップで解説します。
前提知識/必要な理由
デフォルトのLambdaとVPC内リソースの通信
デフォルト状態のLambda関数は、AWSが管理するシステムVPC上で動作するため、インターネット経由のアクセスは可能ですが、お客様独自のVPC内にあるプライベートなRDSに直接アクセスすることはできません。安全に接続するためには、Lambda関数を「VPC接続モード(VPC Lambda)」として起動し、RDSと同じVPC(またはルーティングが可能なVPC)のプライベートサブネットに配置する必要があります。
セキュリティグループの相互参照(最小特権の原則)
セキュリティを担保するために、RDSのセキュリティグループでは「不特定のIPアドレスからの接続」を許可するのではなく、「特定のセキュリティグループ(この場合はLambda用のセキュリティグループ)がアタッチされたリソースからの接続のみ」を許可する設定(相互参照)を行います。これにより、不要なポートの開放を防ぎ、安全性を極限まで高めることができます。
具体的な設定手順・設計方法
ステップ1:セキュリティグループの作成と設定
まず、Lambda用とRDS用にそれぞれ個別のセキュリティグループを作成します。
1. Lambda用のセキュリティグループ(例: sg-lambda-access)
- インバウンドルール: なし(Lambdaはトリガーによって起動するのみなので、外部からのインバウンド通信は不要です)
- アウトバウンドルール: すべてのトラフィックを許可(またはRDSのアウトバウンド先のみに制限)
2. RDS用のセキュリティグループ(例: sg-rds-db)
- インバウンドルール:
- タイプ: PostgreSQL(5432)または MySQL/Aurora(3306)※使用するDBに合わせる
- ソース: カスタム > 「sg-lambda-access」のセキュリティグループID
- アウトバウンドルール: デフォルトのまま(または不要なら削除)
ステップ2:IAMロールへの権限追加
Lambda関数がVPCに接続してネットワークインターフェース(ENI)を生成・管理できるようにするため、Lambdaの実行ロールに AWSLambdaVPCAccessExecutionRole 管理ポリシーをアタッチします。
このポリシーには、以下の基本的なEC2アクションが含まれています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
"ec2:AssignPrivateIpAddresses",
"ec2:UnassignPrivateIpAddresses"
],
"Resource": "*"
}
]
}
ステップ3:Lambda関数のVPC設定
AWS管理コンソールから対象のLambda関数を開き、以下の設定を行います。
- 「設定」タブから「VPC」を選択し、「編集」をクリックします。
- RDSが配置されているのと同じVPCを選択します。
- サブネットには、冗長性を確保するために2つ以上のプライベートサブネットを選択します。
- セキュリティグループには、ステップ1で作成した 「sg-lambda-access」 を選択します。
- 「保存」をクリックします(反映までに数十秒かかります)。
ステップ4:接続確認用のPythonスクリプトとパッケージ導入
LambdaからRDS(MySQL)への接続を確認するためのテスト用Pythonコードです。外部パッケージとして PyMySQL を使用します。
外部ライブラリ(PyMySQL)の導入手順
標準ライブラリ以外を使用するため、ローカル環境でパッケージをインストールしてZIP形式に固めるか、Lambdaレイヤーを使用する必要があります。ここでは簡単なローカルでのパッケージ化手順を紹介します。
# 作業用ディレクトリの作成と移動
mkdir lambda_function
cd lambda_function
# PyMySQLパッケージをカレントディレクトリにインストール
pip install pymysql -t .
# Lambda関数のメインコード(lambda_function.py)を作成し、以下を記述
# (記述後、ディレクトリ全体をzip圧縮してLambdaにアップロードします)
接続用Pythonコード(lambda_function.py)
import os
import pymysql
# 環境変数から接続情報を取得
DB_HOST = os.environ['DB_HOST']
DB_USER = os.environ['DB_USER']
DB_PASSWORD = os.environ['DB_PASSWORD']
DB_NAME = os.environ['DB_NAME']
def lambda_handler(event, context):
try:
# RDSへの接続試行
connection = pymysql.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME,
connect_timeout=5
)
print("SUCCESS: Connection to RDS succeeded")
with connection.cursor() as cursor:
cursor.execute("SELECT version();")
result = cursor.fetchone()
print(f"Database version: {result}")
connection.close()
return {
'statusCode': 200,
'body': 'Database connection successful!'
}
except Exception as e:
print(f"ERROR: {e}")
return {
'statusCode': 500,
'body': f'Database connection failed: {str(e)}'
}
実務での注意点
1. プライベートIPアドレスの枯渇防止
VPC内のLambdaは、起動時にサブネット内のIPアドレス(Hyperplane ENI)を使用します。Lambdaの同時実行数が増加しても耐えられるよう、Lambdaを配置するプライベートサブネットには十分な大きさのCIDRブロック(例: /24以上)を割り当てておくように設計してください。
2. インターネット通信が必要な場合
VPC設定を有効にしたLambdaは、デフォルトではインターネットへ直接アクセスできなくなります。Lambdaから外部APIの呼び出しなどを行う必要がある場合は、Lambdaが配置されているプライベートサブネットのルートテーブルにNAT Gatewayを経由するルートを追加する必要があります。
3. DB接続のクローズとコネクションプーリング
Lambdaはミリ秒単位でスケールするため、リクエストが急増するとRDSの最大接続数(Max Connections)を使い果たしてしまうことがあります。実務の運用では、Lambdaハンドラーの外部で接続を保持する設計にするか、Amazon RDS Proxyを導入してコネクションを効率的に管理することを強く推奨します。
まとめ
AWS LambdaからRDSへの安全な接続には、適切なVPC配置と、セキュリティグループの相互参照設定が不可欠です。本記事の手順に従うことで、DBポートをインターネットに公開することなく、セキュアなサーバーレスアプリケーションを構築することができます。本番運用の際は、IPアドレスの設計やRDS Proxyの導入も合わせて検討してください。