はじめに
AWSを実務で利用する際、「AWS LambdaからVPC(Virtual Private Cloud)内にあるAmazon RDSやAmazon ElastiCacheに安全に接続したい」という要件は頻繁に発生します。しかし、デフォルト設定のLambdaはVPC外(AWSが管理するシステム用のネットワーク)で実行されるため、プライベートなリソースにアクセスできません。
本記事では、初心者から中級者のインフラエンジニア向けに、LambdaをVPC内で安全に動作させる「VPC Lambda」の具体的な設定手順、RDS(PostgreSQL)への接続コード例、そして実務で必ず直面する注意点をステップバイステップで解説します。
前提知識/必要な理由
VPC Lambdaとは
Lambda関数にVPCのサブネットとセキュリティグループの情報を紐付けることで、Lambda関数にENI(Elastic Network Interface)が作成され、VPC内部のリソースとして通信できるようになる機能です。
なぜ設定が必要なのか
RDSやElastiCacheなどのデータベースやキャッシュサーバーは、セキュリティの観点からインターネットに公開せず、VPC内のプライベートサブネットに配置するのが鉄則です。VPC Lambdaを設定しない限り、LambdaからこれらのリソースへプライベートIPアドレスを介した安全な通信を行うことはできません。
具体的な設定手順・設計方法
1. IAMロール(実行ロール)の作成
VPC Lambdaを動作させるには、LambdaがVPC内にネットワークインターフェース(ENI)を作成・管理するための権限が必要です。以下の手順でIAMロールを作成します。
- AWSマネジメントコンソールでIAMを開きます。
- 「ロールの作成」をクリックし、信頼されたエンティティタイプで「AWSサービス」、ユースケースで「Lambda」を選択します。
- 許可ポリシーの追加画面で、AWS管理ポリシーである
AWSLambdaVPCAccessExecutionRoleを検索し、チェックを入れます。 - 任意のロール名(例:
my-vpc-lambda-role)を入力してロールを作成します。
2. セキュリティグループの設計
通信の送信元(Lambda)と送信先(RDS等)のセキュリティグループを以下のように設計・作成します。
Lambda用のセキュリティグループ(例: sg-lambda)
- インバウンドルール: なし(セキュリティの最小特権原則に基づく)
- アウトバウンドルール: すべてのトラフィック(または、送信先RDSのポート宛てのみ)
RDS用のセキュリティグループ(例: sg-rds)
- インバウンドルール:
- タイプ: PostgreSQL(5432ポート)
- ソース: カスタム(「sg-lambda」を指定)
- アウトバウンドルール: 任意
3. 外部ライブラリ(psycopg2)の導入手順
今回はPythonからPostgreSQLに接続するため、標準外ライブラリである psycopg2 を使用します。Lambdaでこれを動作させるには、Linux環境用にコンパイルされたバイナリを含むLambdaレイヤーを作成して適用する必要があります。
ローカル(またはEC2などのLinux環境)で以下のコマンドを実行し、レイヤー用のZIPファイルを作成します。
mkdir -p python
pip install psycopg2-binary -t python/
zip -r psycopg2-layer.zip python/
作成した psycopg2-layer.zip をAWSコンソールの「Lambda」>「レイヤー」からアップロードし、作成したLambda関数にレイヤーとして追加してください。
4. Lambda関数の作成とVPC設定
- Lambdaコンソールを開き、「関数の作成」をクリックします。
- ランタイムに「Python 3.x」を選択し、先ほど作成した
my-vpc-lambda-roleを実行ロールに指定します。 - 「詳細設定」を展開し、「VPCを有効化」にチェックを入れます。
- 接続対象のリソースと同じVPCを選択します。
- サブネットには、必ずプライベートサブネット(最低2つ以上のマルチAZ構成)を選択してください。
- セキュリティグループには、手順2で作成した
sg-lambdaを指定します。
5. 接続テスト用のPythonコード例
Lambda関数のコードエディタに以下のプログラムを貼り付け、環境変数(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD)を設定してテストを実行します。
import os
import psycopg2
def lambda_handler(event, context):
try:
# 環境変数から接続情報を取得
connection = psycopg2.connect(
host=os.environ['DB_HOST'],
database=os.environ['DB_NAME'],
user=os.environ['DB_USER'],
password=os.environ['DB_PASSWORD'],
connect_timeout=5
)
cursor = connection.cursor()
cursor.execute("SELECT version();")
db_version = cursor.fetchone()
cursor.close()
connection.close()
return {
'statusCode': 200,
'body': f"Connection successful! PostgreSQL version: {db_version[0]}"
}
except Exception as e:
print(f"Error connecting to database: {e}")
return {
'statusCode': 500,
'body': "Connection failed."
}
実務での注意点
1. インターネット通信にはNAT Gatewayが必要
VPC Lambdaをプライベートサブネットに配置すると、インターネットへの直接通信ができなくなります。Slackへの通知や外部APIの呼び出しを行う場合は、サブネットのルートテーブルに NAT Gateway または NAT インスタンス を経由するルートを設定する必要があります。
2. IPアドレスの枯渇に注意する
VPC Lambdaはスケーリングに伴い、サブネット内のプライベートIPアドレスを消費します(Hyperplane ENIが共有されるため以前より消費量は大幅に改善されましたが、依然として考慮は必要です)。サブネット設計時には、IPアドレス帯(CIDR)に十分な余裕を持たせてください。
3. タイムアウト値の設計
DBへのネットワーク接続に失敗した場合、デフォルトのタイムアウト設定(3秒)ではエラーハンドリングが適切に行われないことがあります。Lambdaの関数タイムアウト値を10秒〜15秒程度に引き上げ、接続処理(connect_timeout)にも適切なタイムアウトを設定しましょう。
まとめ
AWS LambdaからVPC内のRDSなどのリソースに安全に接続するための「VPC Lambda」の構築手順を解説しました。
実務では、単に接続できることだけでなく、セキュリティグループによる最小特権アクセスの制御、NAT Gatewayの有無によるインターネット通信の可否、そしてIPアドレス枯渇を考慮したサブネット設計が極めて重要です。本手順を参考に、セキュアで可用性の高いサーバーレスインフラを設計・構築してください。