LambdaからVPC内のRDSへ安全に接続する手順と設計の注意点

はじめに

AWSのサーバーレスアーキテクチャを構築する際、AWS LambdaからVPC(Virtual Private Cloud)内にあるAmazon RDS(リレーショナルデータベース)へ接続する構成は、多くの実務プロジェクトで採用されています。しかし、ネットワーク設計やセキュリティグループの設定を誤ると、データベースが外部に露出したり、Lambdaがインターネット経由の外部APIにアクセスできなくなったりするトラブルが発生します。

本記事では、初心者から中級者のインフラエンジニア向けに、LambdaからVPC内のRDSへ安全かつ最適に接続するための設定手順と、実務で絶対に押さえるべき設計上の注意点をステップバイステップで解説します。

前提知識/必要な理由

デフォルトの状態では、Lambda関数はAWSが管理するシステム用のVPC(非公開ネットワーク)で実行され、インターネット経由でリソースにアクセスします。一方で、企業の重要データを保持するRDSは、セキュリティ上の理由からパブリックアクセスを禁止し、プライベートサブネット内に配置するのが鉄則です。

このプライベートなRDSにLambdaからアクセスするためには、「Lambda関数を特定のVPC(およびプライベートサブネット)に関連付ける」必要があります。これにより、LambdaはVPC内部のプライベートIPアドレスを持ち、VPCネットワークを経由して安全にRDSと通信できるようになります。

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

ステップ1:セキュリティグループの作成と設定

LambdaとRDSの間の通信を制御するために、それぞれ専用のセキュリティグループを作成します。これがセキュリティの最小権限の原則における最重要ポイントです。

  • Lambda用セキュリティグループ(例: sg-lambda)
    • インバウンドルール:なし(Lambdaは外部からの直接接続を受け付けないため)
    • アウトバウンドルール:すべてのトラフィックを許可(またはRDSへの宛先ポートのみに制限)
  • RDS用セキュリティグループ(例: sg-rds)
    • インバウンドルール:ソースに「sg-lambda」を指定し、データベースのポート(例: MySQLの場合はTCP 3306)を許可
    • アウトバウンドルール:デフォルトのままで可

ステップ2:Lambda関数のVPC設定

AWS管理コンソールまたはAWS CLIから、Lambda関数にVPCを設定します。

  1. 対象のLambda関数の設定タブから「一般設定」>「VPC」の「編集」をクリックします。
  2. RDSが配置されているのと同じVPCを選択します。
  3. 可用性を確保するため、異なるアベイラビリティーゾーン(AZ)にある少なくとも2つ以上のプライベートサブネットを選択します。
  4. セキュリティグループとして、ステップ1で作成した「sg-lambda」を選択して保存します。

ステップ3:DB接続用ライブラリの準備とLambdaレイヤーの作成

PythonからMySQL(RDS)に接続する場合、標準ライブラリ以外(pymysqlなど)を使用することが一般的です。ここでは、Lambdaレイヤーを使って外部パッケージを導入する手順を解説します。

ローカル環境(LinuxやmacOS、またはDocker環境)で以下のコマンドを実行し、ライブラリをZIP化してアップロードする準備をします。

# 1. 作業ディレクトリの作成
mkdir -p python/lib/python3.9/site-packages

# 2. pymysqlライブラリをターゲットディレクトリにインストール
pip install pymysql -t python/lib/python3.9/site-packages/

# 3. ZIPファイルにアーカイブ
zip -r pymysql-layer.zip python/

作成した pymysql-layer.zip をAWS Lambdaの「レイヤー」として登録し、対象のLambda関数に紐付けます。これにより、関数コード内でライブラリが利用可能になります。

ステップ4:Lambda関数コードの実装

以下は、VPC内のRDS(MySQL)に対して接続確認を行うPythonのサンプルコードです。

import os
import pymysql

# 環境変数から接続情報を取得(実務ではSecrets Managerの利用を推奨)
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
        )
        with connection.cursor() as cursor:
            # 簡易な疎通確認クエリの実行
            cursor.execute("SELECT VERSION()")
            result = cursor.fetchone()
            return {
                'statusCode': 200,
                'body': f"Connection successful! Database version: {result[0]}"
            }
    except Exception as e:
        print(f"Error connecting to database: {e}")
        return {
            'statusCode': 500,
            'body': "Database connection failed."
        }
    finally:
        if 'connection' in locals() and connection.open:
            connection.close()

実務での注意点

1. インターネット通信が必要な場合のルート設計

LambdaをVPC内に配置すると、デフォルトではインターネット上の外部APIや他のAWSサービス(S3、DynamoDB、Systems Managerなど)にアクセスできなくなります。外部通信が必要な場合は、必ず以下の構成をとってください。

  • Lambdaをプライベートサブネットに配置する。
  • パブリックサブネットにNAT Gatewayを配置し、プライベートサブネットのルートテーブルにNAT Gateway経由のデフォルトルート(0.0.0.0/0)を追加する。
  • または、不要なインターネット通信を避け、AWS PrivateLink(VPCエンドポイント)を配置する。

2. コネクション急増によるデータベース枯渇対策

Lambdaはリクエスト数に応じて自動的にスケーリング(並行実行)します。Lambdaの同時実行数が急増すると、RDSの最大コネクション数を超過し、接続エラー(Too many connections)を誘発します。これを防ぐために、実務ではAmazon RDS Proxyの導入を強く推奨します。RDS Proxyがコネクションをプールし、LambdaとRDS間の負荷を大幅に軽減します。

まとめ

LambdaからVPC内のRDSへの接続は、セキュリティグループの適切な「相互参照」と、マルチAZを考慮したプライベートサブネットの指定が設計の基本です。さらに実務においては、NAT GatewayのコストやRDS Proxyによるコネクション管理まで踏み込んで設計することが、安定したインフラ構築の鍵となります。本記事の手順を参考に、セキュアで高可用なシステムを構築してください。

上部へスクロール