0
0

LambdaとRDSのセキュアな接続 ~SSL/TLS証明書の選択と実装~

Last updated at Posted at 2023-11-23

最近、アーキテクチャにRDSのリードレプリカを組み込む作業を行ったのですが、Lambda(NestJS)からRDS(リードレプリカ)へのSSL/TLS接続を設定する際、以下のエラーメッセージが表示されました。

Error: self-signed certificate in certificate chain

この問題の原因と解決方法を備忘録として残します。

原因

単純に、使用する証明書が不適切だったのが原因でした。

RDS Proxyを介する場合の証明書

元々の構成では、Lambda(NestJS)からRDS Proxyを経由してRDS(プライマリ)に接続しており、この場合にはAmazonRootCA1.pem証明書を使用していました。

RDS Proxyを使用する際には、AWSが提供するAmazonRootCA1.pemというルート証明書が重要です。この証明書は、RDS Proxyの身元確認と通信の暗号化を保証するために用いられます。

Lambda(NestJS) → RDS Proxy → RDS(プライマリ)

RDS(リードレプリカ)への直接接続

今回新たに追加したRDS(リードレプリカ)への接続では、RDS Proxyを介さず直接Lambdaから接続する必要がありました(RDS Proxyは主に書き込み操作の負荷を軽減し、接続管理を効率化するために使用されますが、読み取り専用のリードレプリカではこれが必要ないため、直接接続を選択しました)。

この直接接続では、リージョンに特化したap-northeast-1-bundle.pem(~-bundle.pem)証明書が必要でした。

Lambda(NestJS) → RDS(リードレプリカ)

解決方法

この問題を解決するために、RDS(リードレプリカ)への接続で適切なSSL/TLS証明書を使用しました。

AWSの公式ページに証明書のバンドルap-northeast-1-bundle.pemがあったので、それを参照し直すことでエラーが解消されました。

補足:証明書の読み込み方法(NestJS)

アプリケーション(NestJS)でのSSL/TLS証明書の読み込みは、AWS S3から証明書を取得する形で実装しました。

S3からの証明書取得処理

S3CertificatesServiceクラスを定義し、AWS SDKを使用してS3にアクセスします。このクラスでは、指定されたバケットとキーから証明書を取得するgetCertificateFromS3メソッドを提供します。

import { Injectable } from '@nestjs/common'
import * as AWS from 'aws-sdk'

@Injectable()
export class S3CertificatesService {
  private s3: AWS.S3

  constructor() {
    this.s3 = new AWS.S3()
  }

  async getCertificateFromS3(bucket: string, key: string): Promise<string> {
    const params = {
      Bucket: bucket,
      Key: key
    }

    const data = await this.s3.getObject(params).promise()

    if (data.Body) {
      return data.Body.toString()
    }

    throw new Error('Failed to retrieve certificate from S3. Body is undefined.')
  }
}

DB接続設定

DBへの接続設定では、上記サービスを利用してS3から証明書を取得し、DB接続の設定に適用します。ここではap-northeast-1-bundle.pem証明書を取得し、DB(MySQL)へのSSL接続に使用しています。

    const certificate = await s3CertificatesService.getCertificateFromS3('rds-certificates', 'ap-northeast-1-bundle.pem')
    const dbConfig = {
      type: 'mysql',
      host: '',
      port: 3306,
      username: '',
      database: '',
      password: '',
      ssl: {
        ca: certificate,
        rejectUnauthorized: true
      }
    }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0