Amazon AppFlow カスタムコネクタで使用する Lambda 関数を VPC Lambda にする場合は Secrets Manager への通信経路を確保する必要がある

VPC Lambda にするときはもろもろのネットワークの経路を意識する必要がありますね

コンバンハ、千葉(幸)です。

先日、AppFlow カスタムコネクタを使用して MySQL から S3 へデータ転送してみました。

ここで行ったのは以下構成です。カスタムコネクタに紐づける Lambda 関数を非 VPC でセットアップしたので、接続元となる Aurora MySQL をパブリックアクセス可能にして検証しました。

この Aurora MySQL をプライベートサブネットに配置するパターンも試してみるか、ということでやってみました。

まとめ

  • 接続先がプライベートサブネットにある場合、カスタムコネクタ用 Lambda 関数を VPC に関連づける必要がある
    • Lambda 関数が VPC 上から AWS Secrets Manager にアクセスできる必要がある
    • Lamnda 関数から VPC 上から AppFLow にアクセスできる必要はない

今回やってみる構成

以下の構成でやってみます。Aurora MySQL をプライベートにし、カスタムコネクタ用 Lambda 関数を VPC Lambda にしたのが主な変更点です。

↑上記を実現するために AWS Secrets Manager 向けの VPC エンドポイントを追加します。なお、Lambda 関数から AppFlow への通信は特に考慮する必要はありません。 *1

なお、リソースは前回構築した分をできる限り再利用します。以下のように変更を加えつつ必要に応じて新規作成して進めていきます。

1. Lambda 関数を VPC Lambda に変更

前回デプロイ済みの Lambda 関数の VPC 設定を編集し、プライベートサブネットに関連付けていきます。

関連付けを行うことで Hyperplane ENI が生成されるので、Lambda 関数にはその権限が必要になります。許可が必要なアクションは以下の通りです。

  • ec2:CreateNetworkInterface
  • ec2:DescribeNetworkInterfaces
  • ec2:DeleteNetworkInterface

今回はそれらの許可を含む AWS 管理ポリシーAWSLambdaVPCAccessExecutionRoleを Lambda 関数用ロールにアタッチすることで対応しました。


ちなみに必要な権限が無い状態で VPC との関連付けを行うと以下のエラーが発生します。

The provided execution role does not have permissions to call CreateNetworkInterface on EC2


今回は VPC との関連付け設定を以下のように行いました。

  • Aurora MySQL と同じ VPC のプライベートサブネットを指定
  • SecuriryGroup ルール
    • インバウンド:なし
    • アウトバウンド:0.0.0.0/0へのすべてのトラフィックを許可

Appflow_custom_VPC_Lambda

2. Aurora DB クラスターのパブリックアクセスを無効に

前回はパブリックアクセス可能で構成していた DB クラスターのパブリックアクセスを無効に変更します。

冒頭の構成図では配置サブネットをパブリックサブネットからプライベートサブネットに変更したように表現しましたが、そこまではしないことにします。


もしサブネットも変更したい、という場合には以下のような手順で実現できます。


DB クラスターのパブリックアクセスを無効にしました。これで「配置先はパブリックサブネットだが DB インスタンス用 ENI にはパブリック IP アドレスが付与されていないのでパブリックアクセスできない」状態になりました。

Appflow__RDS_Management_Console

なお、SecuriryGroup のルールは以下の通り構成しています。

  • インバウンド:Lambda 関数用 SecuriryGroup からの TCP 3306 を許可
  • アウトバウンド:なし

番外編:この時点で AppFlow 接続を作成する

本来はこの後に VPC エンドポイントを作成するのですが、それが無い状態で AppFlow のカスタムコネクタ接続を作成するとどうなるのかを確認します。

コネクタ画面から「新しいコネクタを登録」を押下します。

Appflow_vpc_Amazon_AppFlow

紐づける Lambda 関数、コネクタのラベルを指定し登録します。

AppFLow_coustom_connector_Amazon_AppFlow

出来上がったコネクタに「接続(コネクタプロファイル)」を作成します。

Appflow_vpc_jdbc_Amazon_AppFlow

各種設定値を入れ「接続する」を押下します。

接続の作成が失敗しました。

Appflow_error_Amazon_AppFlow

接続 jdbc-vpc-connector-profile の作成中にエラーが発生しました。

Error while communicating to connector: Failed to validate Connection while attempting "ValidateCredentials with CustomConnector" with connector failure The request failed because the service Source JDBCConnector returned the following error: Details: Client execution did not complete before the specified timeout configuration.. (Service: null; Status Code: 400; Error Code: Client; Request ID: null; Proxy: null)

接続の作成時に指定した各種情報は、AppFlow により自動的にシークレットに登録されます。そのシークレットの情報をカスタムコネクタ用 Lambda 関数が取得して接続の作成が完了するのですが、現状の構成だとネットワーク的に到達できていないのでエラーになっています。

Appflow_jdbc_Secrets_Manager

↑接続の作成が失敗すると、このシークレットも自動的に削除されます。

3. VPC エンドポイントの作成

ということで正しい手順に戻り、AWS Secrets Manager 向けの VPC エンドポイントを作成します。

以下のように作成しました。

  • サービス名:com.amazonaws.ap-northeast-1.secretsmanager
  • 配置サブネット:Lambda 関数と同一のサブネット
  • プライベート DNS 名:有効
  • IP アドレスタイプ:Ipv4
  • SecuriryGroup ルール:
    • インバウンド:Lambda 関数の SecuriryGroup からの TCP 443 を許可
    • アウトバウンド:なし
  • エンドポイントポリシー:フルアクセス

AppFlow_VPC_endpoint_secrets

なお、プライベート DNS 名が有効に機能するために、VPC のパラメータで以下設定がどちらとも有効になっている必要があることに注意してください。

  • DNS ホスト名
  • DNS 解決

(参考)インターフェイス VPC エンドポイント (AWS PrivateLink) - Amazon Virtual Private Cloud

4. AppFlow フローの作成・実行

先ほど「番外編」として確認した手順に則り以下を作成します。

  • カスタムコネクタ
  • 接続(コネクタプロパティ)

手順 3 を経た後であれば、以下の通り正常に作成が完了しました。

Appflow_vpc_Amazon_AppFlow_create

この「接続」を用いたフローを作成していきます。

とは言えこの後のフローの作成〜実行の手順は前回のエントリとほぼ同じなので、詳細は割愛します。

手順 2 で送信元として先ほど作成した接続を指定しています。

Appflow_flow_create

その他はほぼデフォルトでフローを作成し、作成後に実行を行いました。

AppFlow_run_Amazon_AppFlow

↑正常に実行が完了され、MySQL 上のデータが S3 にオブジェクトとして格納されました。

カスタムコネクタ用 Lambda 関数を VPC Lambda にした場合の動作確認ができました。

ちなみに:接続作成時に実際に接続している訳ではない

フロー作成時、送信元でオブジェクトを選択する際にエラーが発生したことがありました。

Appflow_object_error_Amazon_AppFlow

認証中 でエラーが発生しました

Error while communicating to connector: The request failed because the service Source JDBCConnector returned the following error: Details: Connector failed with error Unhandled.

よくよく確認してみると「接続」作成時のパスワードの値を誤っていたことが分かり、接続を作成し直してフローの設定を行いました。

接続の作成自体は正常に完了しており、フローに設定する際に初めて認証情報が正しくないことが判明しました。つまり送信元(今回では DB クラスター)に実際に接続を試みるのはフローの設定時だということが分かります。

なんなら全ての項目に適当な文字列を入力しても「接続」の作成は成功します。ここで確認されているのは「Lambda 関数が、自動的に生成された Secrets Manager シークレットの値を取得できるか」のみのようでした。

これはコネクタによって変わる部分だと思いますので、あくまで一例として捉えておいてください。

終わりに

Amazon AppFlow カスタムコネクタ用の Lambda 関数を VPC Lambda にする際には AWS Secrets Manager にアクセスできるようにしておく必要がある、という話でした。

今回は VPC エンドポイントを作成して対応しましたが、NAT Gateway を用いることでも実現できるかと思います。

カスタムコネクタを使用する際には、コネクタとしての接続先(今回で言えば DB クラスター)だけでなく Secrets への経路も含めて考慮してください。

以上、 チバユキ (@batchicchi) がお送りしました。

脚注

  1. 構成図では Lambda が VPC に配置されているように表現していますが、実際には「Lambda 関数の実体は専用の VPC に存在し、カスタマー管理の VPC に Hyperplane ENI を経由してアクセスする」状態です。AWS が管理する Lambda 専用 VPC から AppFlow に対していい感じに裏で連携してくれている気がします。