VPC内LambdaからRDSへの安全な接続とRDS Proxy設定

はじめに

AWSのサーバーレスアーキテクチャにおいて、AWS LambdaからAmazon RDS(あるいはAmazon Aurora)への接続は非常によくあるユースケースです。しかし、Lambdaの急激なスケールアウトによる「DBコネクションの枯渇」や、VPC内への配置における「セキュリティ設計」に頭を悩ませるインフラエンジニアは少なくありません。

本記事では、これらの課題を解決するために実務で強く推奨される「RDS Proxy」を経由した安全かつ高効率な接続方法について、具体的な設定手順をステップバイステップで解説します。

前提知識/必要な理由

LambdaからRDSへ直接接続する場合、以下の2つの大きな課題が発生します。

  • コネクションの枯渇: Lambda関数はリクエスト数に応じて並列実行されます。各インスタンスが個別にコネクションを確立するため、データベースの最大接続数(max_connections)を容易に超過してしまいます。
  • セキュリティと認証管理: データベースのパスワードをLambdaの環境変数に直接保持することは、セキュリティベストプラクティスに反します。

これらの課題を解決するために、RDS ProxyとAWS Secrets Managerを導入します。RDS Proxyがコネクションをプールして使い回すことで枯渇を防ぎ、認証情報はSecrets Managerで安全に一元管理します。

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

ここからは、実際に構築するための具体的な手順を解説します。

ステップ1:AWS Secrets ManagerでのDBクレデンシャルの作成

まずはRDSに接続するためのユーザー名とパスワードをSecrets Managerに保存します。

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

ステップ2:RDS Proxy用のIAMロールの作成

RDS ProxyがSecrets Managerから認証情報を取得できるようにするためのIAMロールを作成します。以下の信頼ポリシーとアクセス許可ポリシーを設定してください。

信頼ポリシー(Trust Relationship):

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

アクセス許可ポリシー:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:my-rds-secret-*"
    }
  ]
}

ステップ3:RDS Proxyの作成と設定

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

  • プロキシ識別子: 任意の名前(例:my-db-proxy)
  • 対象データベース: 接続先のRDSインスタンスを選択
  • 接続資格情報(Secrets Manager): ステップ1で作成したシークレットを選択
  • IAMロール: ステップ2で作成したIAMロールを選択
  • VPCサブネット: RDSと同じVPC内の、2つ以上の可用性ゾーン(AZ)のプライベートサブネットを選択

ステップ4:Lambdaレイヤーの作成(PyMySQLの導入手順)

本手順のPythonコードでは、MySQLへの接続に外部パッケージである pymysql を使用します。Lambdaで標準提供されていないライブラリを使用するため、Lambdaレイヤーとしてパッケージ化してアップロードする必要があります。

ローカル環境(またはCloud9など)で以下のコマンドを実行し、ZIPファイルを作成します。

# 作業ディレクトリの作成
mkdir python
cd python

# パッケージを特定のフォルダにインストール
pip install pymysql -t .

# 親ディレクトリに戻り、zip圧縮
cd ..
zip -r pymysql-layer.zip python/

作成した pymysql-layer.zip をAWSコンソールの「Lambda」→「レイヤー」からアップロードし、レイヤーを作成します。その後、作成したLambda関数にこのレイヤーを紐付けます。

ステップ5:Lambda関数の作成とコードの実装

VPC内にLambda関数を配置し、以下の設定を行います。

  • VPC設定: RDS Proxyと同じVPC、およびプライベートサブネットを選択します。
  • 実行ロール: AWSLambdaVPCAccessExecutionRole ポリシーをアタッチします。

以下は、RDS Proxy経由でデータベースにクエリを実行するLambda関数のサンプルコード(Python)です。

import os
import pymysql
import boto3
import json

# Secrets Managerから認証情報を取得
def get_secret():
    secret_name = os.environ['SECRET_NAME']
    region_name = os.environ['AWS_REGION']
    client = boto3.client('secretsmanager', region_name=region_name)
    response = client.get_secret_value(SecretId=secret_name)
    return json.loads(response['SecretString'])

def lambda_handler(event, context):
    secrets = get_secret()
    
    # RDS Proxyのホスト名、ユーザー情報、DB名を設定
    db_host = os.environ['PROXY_ENDPOINT']
    db_user = secrets['username']
    db_password = secrets['password']
    db_name = os.environ['DB_NAME']
    
    try:
        # RDS Proxyへの接続確立
        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"Database version: {result[0]}"
            }
    except Exception as e:
        print(f"Error: {e}")
        return {
            'statusCode': 500,
            'body': "Connection failed"
        }
    finally:
        if 'connection' in locals():
            connection.close()

実務での注意点

  • セキュリティグループの設計: 通信元(Lambda)、RDS Proxy、RDSの三者間でセキュリティグループを正しく設定してください。具体的には、RDS Proxyのセキュリティグループで「Lambdaのセキュリティグループからのポート3306(MySQLの場合)のインバウンド」を許可し、RDS本体のセキュリティグループで「RDS Proxyのセキュリティグループからのインバウンド」のみを許可します。
  • タイムアウトの調整: LambdaがVPC内で起動する際、またはRDS Proxyへの初回接続時にわずかな遅延(コールドスタート)が発生することがあります。Lambda関数のデフォルトタイムアウト(3秒)は短すぎるため、実務では15秒〜30秒程度に引き上げることを推奨します。
  • ピン留め(Pinning)の回避: プリペアドステートメントの多用や一時テーブルの使用など、特定のSQL操作を行うとRDS Proxyのコネクションプールが特定のセッションに固定(ピン留め)され、プロキシの効果が薄れる原因になります。アプリケーション側のSQL実装にも注意を払いましょう。

まとめ

VPC内のLambdaからRDSへ接続する際、RDS Proxyを挟む設計は、高負荷な実務環境において必須と言えるベストプラクティスです。Secrets Managerを組み合わせることで、認証情報のハードコードを排除し、安全でスケーラブルなサーバーレスアーキテクチャを実現できます。本手順を参考に、堅牢なインフラ環境を構築してください。

上部へスクロール