AWS LambdaからVPC内のRDSへ安全に接続する設定手順

はじめに

AWSを用いたサーバーレスアーキテクチャにおいて、AWS LambdaからVPC(Virtual Private Cloud)内に配置されたAmazon RDSなどのデータベースにアクセスする構成は、実務で非常によく使われます。しかし、ネットワーク設計やセキュリティグループの設定、データベース接続の管理など、正しく構築しないと「接続できない」「パフォーマンスが著しく低下する」といったトラブルの原因になります。

この記事では、初心者から中級者のインフラエンジニア向けに、LambdaからVPC内のRDS(PostgreSQL)へ安全に接続するための具体的な設定手順と、実務でのベストプラクティスをステップバイステップで解説します。

前提知識とVPC接続が必要な理由

なぜVPC接続が必要なのか?

デフォルトのLambda関数は、AWSが管理するシステムVPC上で実行され、インターネット経由でパブリックなリソースにアクセスします。しかし、企業の重要なデータを保持するRDSなどのデータベースは、セキュリティの観点からインターネット経由のアクセスを遮断し、プライベートサブネット内に配置するのが鉄則です。このプライベートなRDSに安全にアクセスするため、Lambda関数を自社VPC(プライベートサブネット)に紐づけて起動させる必要があります。

LambdaからRDS接続時の主な課題

  • セキュリティの確保: 最小限のアクセス権限(IAMおよびセキュリティグループ)の設定。
  • 外部ライブラリの利用: Pythonなどでデータベースに接続する際、標準ライブラリ以外の接続ドライバ(例:psycopg2)をLambdaに組み込む必要がある。
  • 接続オーバーヘッド: Lambdaが起動するたびにデータベース接続(コネクション)を確立すると、RDSの接続上限に達してしまう問題。

具体的な設定手順・設計方法

1. セキュリティグループの作成

LambdaとRDSの間で通信を許可するために、2つのセキュリティグループを作成します。

  • Lambda用セキュリティグループ(例: sg-lambda): インバウンドルールは不要です。アウトバウンドルールは「すべてのトラフィック」を許可します。
  • RDS用セキュリティグループ(例: sg-rds): インバウンドルールとして、上記「sg-lambda」からの、RDSのポート(PostgreSQLの場合は5432)の通信のみを許可します。

2. Lambda関数へのVPC設定とIAM権限の付与

Lambda関数がVPC内でElastic Network Interface(ENI)を作成し通信できるようにするため、Lambdaの実行ロールに適切な権限を付与する必要があります。

ロールにAWS管理ポリシーである AWSLambdaVPCAccessExecutionRole をアタッチしてください。このポリシーには以下の権限が含まれています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateNetworkInterface",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DeleteNetworkInterface"
            ],
            "Resource": "*"
        }
    ]
}

その後、Lambda関数の設定画面の「VPC」セクションから、RDSが起動しているVPC、プライベートサブネット(最低2つ推奨)、および先ほど作成した「sg-lambda」セキュリティグループを選択して保存します。

3. Lambdaレイヤーによる外部ライブラリ(psycopg2)の追加

PythonからPostgreSQLに接続するには psycopg2 ライブラリが必要です。しかし、Lambdaの標準環境には含まれていないため、Lambdaレイヤー を使用して導入します。

ローカル環境(DockerなどのLinux環境推奨)で以下のコマンドを実行し、ライブラリをパッケージングします。

# 独自のディレクトリ構成を作成
mkdir -p python/lib/python3.9/site-packages
# ライブラリをターゲットディレクトリにインストール
pip install psycopg2-binary -t python/lib/python3.9/site-packages/
# zip圧縮
zip -r psycopg2-layer.zip python/

作成した psycopg2-layer.zip をAWSコンソールの「レイヤー」からアップロードし、対象のLambda関数にアタッチします。これにより、コード内で import psycopg2 が使用可能になります。

4. Lambda関数コードの実装

接続情報を安全に管理するため、環境変数から接続情報を取得する実装を行います。また、接続の再利用(グローバルスコープでの定義)を行うことで、Lambda呼び出しごとの接続オーバーヘッドを軽減します。

import os
import psycopg2

# グローバル変数として接続オブジェクトを保持(接続の再利用)
connection = None

def get_connection():
    global connection
    if connection is None or connection.closed != 0:
        connection = psycopg2.connect(
            host=os.environ['DB_HOST'],
            database=os.environ['DB_NAME'],
            user=os.environ['DB_USER'],
            password=os.environ['DB_PASSWORD'],
            port=os.environ.get('DB_PORT', '5432')
        )
    return connection

def lambda_handler(event, context):
    try:
        conn = get_connection()
        with conn.cursor() as cur:
            cur.execute("SELECT version();")
            db_version = cur.fetchone()
            return {
                'statusCode': 200,
                'body': f"Database version: {db_version}"
            }
    except Exception as e:
        print(f"Error: {e}")
        return {
            'statusCode': 500,
            'body': "Database connection failed"
        }

実務での注意点

IPアドレスの枯渇対策

LambdaがVPC内でスケーリングすると、サブネット内のプライベートIPアドレスを消費します。サブネットのCIDRブロック(IP範囲)が小さすぎると、IPアドレスが枯渇し、Lambdaのスケールアウトが失敗します。Lambdaを配置するサブネットには、十分な大きさ(例: /24以上)のIPレンジを割り当ててください。

コールドスタートと接続オーバーヘッドの軽減

Lambdaは実行完了後も実行コンテナを一時的に保持します。データベースの接続処理(psycopg2.connect)は、ハンドラー関数の外側(グローバルスコープ)で行うか、上記コード例のようにグローバル変数を確認して再利用するように設計してください。これにより、実行ごとの接続確立を防ぎ、処理速度を大幅に向上させます。

RDS Proxyの検討

Lambdaの同時実行数が急増すると、RDSへの接続数が上限に達し「Too many connections」エラーが発生します。この問題を解決するため、LambdaとRDSの間に Amazon RDS Proxy を導入することを強く推奨します。RDS Proxyが接続プールを管理し、Lambdaの急激なスケール時にもDB接続を効率よく使い回すことができます。

まとめ

AWS LambdaからVPC内のRDSへ安全に接続するには、正しいセキュリティグループの設定、IAM権限の付与、そして接続を使い回すコード設計が不可欠です。また、実務運用を想定して、IPアドレスの設計やRDS Proxyの導入も視野に入れる必要があります。本記事の手順を参考に、セキュアで高効率なサーバーレスインフラを構築してください。

上部へスクロール