LambdaからRDS Proxy経由でRDSに安全接続する設定手順

はじめに

AWSサーバーレスアーキテクチャにおいて、AWS LambdaからAmazon RDS(Aurora)に接続するシステムは一般的です。しかし、Lambdaが急激にスケールアウトした際、データベースの最大コネクション数(接続数)の上限に達し、接続エラー(Too many connections)を引き起こす問題が実務で頻発します。本記事では、この課題を解決する「RDS Proxy」を導入し、セキュアかつ安定した接続を確立するための具体的な設定手順を解説します。

前提知識/必要な理由

Lambdaはイベント駆動で並行実行されるため、アクセスが急増すると数千ものインスタンスが同時に立ち上がります。各インスタンスが個別にDBコネクションを張ると、RDSの制限を超えてしまいます。RDS Proxyを中間に配置することで、以下のメリットが得られます。

  • コネクションプール機能:DBコネクションを再利用し、接続オーバーヘッドを削減。
  • セキュリティの向上:データベースの認証情報をSecrets Managerで管理し、コードへのハードコードを防止。
  • 高可用性:データベースのフェイルオーバー発生時、接続の切り替えを高速化(ダウンタイムの低減)。

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

今回は、VPC環境内のAurora PostgreSQLに、LambdaからRDS Proxy経由で安全に接続する構成を例に解説します。

1. Secrets ManagerでDB認証情報を登録する

RDS Proxyはデータベース接続の際、AWS Secrets Managerからパスワードを取得します。

  1. Secrets Managerコンソールを開き、「新しいシークレットを保存する」をクリックします。
  2. シークレットのタイプで「RDSデータベースの資格情報」を選択し、ユーザー名とパスワードを入力します。
  3. 対象のRDSデータベースインスタンスを選択し、名前を付けて保存します(例:my-rds-secret)。

2. RDS Proxy用IAMロールの作成

RDS ProxyがSecrets Managerから認証情報を読み取るための権限(IAMロール)を作成します。

以下の信頼ポリシーを持つIAMロールを作成し、Secrets Managerの読み取りポリシー(secretsmanager:GetSecretValue)をアタッチします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "rds.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

3. RDS Proxyの構築

RDSコンソールから「プロキシ」を選択し、プロキシを作成します。

  • プロキシ識別子: 任意の名前(例:my-db-proxy)
  • エンジンファミリー: PostgreSQL (または MySQL)
  • 対象データベース: 接続先のRDS/Auroraを指定
  • 認証: 手順1で作成したSecrets Managerのシークレットを選択し、手順2のIAMロールを指定
  • VPC: RDSが所属するVPCと同じVPC、および2つ以上のサブネットを選択

4. セキュリティグループの設定

接続元(Lambda)、中間(RDS Proxy)、接続先(RDS)のセキュリティグループ(SG)のインバウンド・アウトバウンド通信を相互に許可します。

  • Lambda用SG: アウトバウンドですべてのトラフィックを許可。
  • RDS Proxy用SG: インバウンドで「Lambda用SG」からのポート5432(PostgreSQL)を許可。
  • RDS用SG: インバウンドで「RDS Proxy用SG」からのポート5432を許可。

5. Lambda関数の作成と接続の実装

Lambda関数をRDS Proxyと同じVPCのサブネット内に配置します(最低2つのAZのサブネットを指定)。

次に、Pythonを用いた接続コードを記述します。ここでは外部ライブラリ psycopg2 を使用します。

【補足】psycopg2 の導入手順

Lambdaの標準ランタイムには psycopg2 は含まれていないため、事前にLambdaレイヤーなどで追加する必要があります。以下の手順でLinux環境用(AWS Lambda実行環境と互換性のあるもの)のバイナリパッケージを導入してください。

# ローカルでLambdaレイヤー用のディレクトリを作成
mkdir -p python/lib/python3.9/site-packages
cd python/lib/python3.9/site-packages

# AWS Lambda用の互換パッケージである psycopg2-binary をインストール
pip install psycopg2-binary -t .

# zip圧縮してAWS Lambdaのレイヤーとしてアップロード
cd ../../../../
zip -r psycopg2-layer.zip python/

作成した psycopg2-layer.zip をAWS Lambdaコンソールの「レイヤー」から登録し、対象のLambda関数にアタッチします。

Pythonによる接続コード例

import os
import psycopg2

def lambda_handler(event, context):
    # 環境変数からRDS Proxyの接続情報を取得
    db_host = os.environ['DB_PROXY_ENDPOINT']
    db_name = os.environ['DB_NAME']
    db_user = os.environ['DB_USER']
    db_password = os.environ['DB_PASSWORD']

    try:
        # RDS Proxyのエンドポイントへ接続
        conn = psycopg2.connect(
            host=db_host,
            database=db_name,
            user=db_user,
            password=db_password,
            port=5432,
            connect_timeout=5
        )
        cursor = conn.cursor()
        cursor.execute("SELECT version();")
        db_version = cursor.fetchone()
        
        cursor.close()
        conn.close()
        
        return {
            'statusCode': 200,
            'body': f"Successfully connected! DB Version: {db_version}"
        }
    except Exception as e:
        print(f"ERROR: Connection failed. {e}")
        raise e

実務での注意点

  • ピン留め(Pinning)の回避: SQL内で一時テーブルの作成やセッションレベルの変数設定(SETコマンドなど)を行うと、RDS Proxyはコネクションの共有を停止し、特定のクライアントに固定(ピン留め)してしまいます。これによりコネクションプールが無効化されるため、極力セッション依存の操作は避けてください。
  • 適切なタイムアウト設計: Lambda関数の実行タイムアウト値は、DB接続試行時間よりも長く設定してください。また、RDS Proxyの「クライアント接続の維持時間」を適切に調整し、不要な接続が残り続けないように設計します。
  • IAMデータベース認証の活用: Secrets Managerによるパスワード認証のほか、IAM認証をRDS Proxyに設定することで、パスワード管理を不要にし、より強固なセキュリティを担保することも可能です。

まとめ

LambdaとRDSを連携させる実務では、RDS Proxyの導入が不可欠と言えます。VPC、セキュリティグループ、Secrets Managerを正しく連携させ、ピン留めを回避する実装を行うことで、急激なアクセス増に対しても安定した、高可用性で堅牢なサーバーレスバックエンドが構築できます。ぜひ実務の設計に取り入れてみてください。

上部へスクロール