S3 イベント通知へ Lambda トリガーを設定するときに不明なエラー「Unable to validate the following destination configurations」とメッセージが出るときの対処方法

2021.01.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

困っていた内容

S3 イベント通知へ Lambda 関数を追加すると以下のエラーが出ます。どうすれば S3 イベント通知へ Lambda 関数を追加できますか?

S3 コンソール

不明なエラー
予期しないエラーが発生しました。

API レスポンス
Unable to validate the following destination configurations

AWS CLI

$ aws s3api put-bucket-notification-configuration \
    --cli-input-json file://config.json
An error occurred (InvalidArgument) when calling the PutBucketNotificationConfiguration operation: Unable to validate the following destination configurations

どう対応すればいいの?

Lambda 関数に付与されたリソースベースのポリシーを確認してください。リソースベースのポリシーは Lambda コンソールや AWS CLI で確認できます。

Lambda コンソール

[関数] > [アクセス権限タブ] の順に遷移すると見れます。

AWS CLI

$ aws lambda get-policy \
    --function-name <対象の関数名> \
    | jq '.Policy | fromjson'
{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "123456789012_event_permissions_from_<バケット名>_for_<Lambda 関数名>",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:ap-northeast-1:<Lambda 関数がある AWS アカウント ID>:function:<対象の関数名>",
      "Condition": {
        "StringEquals": {
          "AWS:SourceAccount": "<S3 バケットがある AWS アカウント ID>"
        },
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:s3:::<バケット名>"
        }
      }
    }
  ]
}

S3 イベントの対象となる Lambda 関数すべてに上記リソースベースのポリシーが存在しない場合は、以下どちらかの対応をしてください。

  • S3 コンソールの S3 イベント通知からリソースベースのポリシーが存在しない Lambda 関数を削除し、再度 Lambda 関数を登録する(対象が不明な場合はすべてのイベント通知を登録しなおす)
  • AWS CLI で下記コマンドを実行する
$ aws lambda add-permission \
    --function-name <関数名> \
    --principal s3.amazonaws.com \
    --statement-id <S3EventTrigger など任意のリソースベースのポリシーの識別子> \
    --action "lambda:InvokeFunction" \
    --source-arn arn:aws:s3:::<S3 バケット名> \
    --source-account <S3 バケットがある AWS アカウント ID>

S3 イベントに含まれるすべての Lambda 関数に適切なリソースベースのポリシーを付与した後、再度 S3 イベント通知へ Lambda 関数を追加するとエラーが解消されます。

リソースベースのポリシーの仕組み

Lambda には 2 つの権限設定があります。

  • IAM ロール: Lambda 関数から AWS サービスへアクセスするための権限
  • リソースベースのポリシー: AWS サービスから Lambda 関数へアクセスするための権限

Lambda はイベント駆動で呼び出されますので、どの呼び出し元(トリガー)を信頼するか、リソースベースのポリシーで個別に設定できます。

注意点として、AWS マネジメントコンソールからイベントの対象に Lambda 関数を追加すると、自動でリソースベースのポリシーが作成されます。すべての操作をマネジメントコンソールで行うと、この問題は発生しません。

CloudFormation を含む AWS API、AWS CLI や SDK で Lambda のトリガーイベントを追加するときは、事前にリソースベースのポリシーを追加する必要があります。CloudFormation でリソースベースのポリシーを修正したい場合は、文末の参考資料の AWS::Lambda::Permission ドキュメントを参考にしてください。

[おまけ] 再現手順

これまで説明した挙動をどうすれば再現できるか?(筆者のように事象を再現したい)と思われた方向けの Tips です。

AWS マネジメントコンソールは自動で良い感じにリソースベースのポリシーを追加してくれる親切設計なので、再現するには一工夫必要です。以下の手順通り実施すれば再現できます。

  1. 作成手段問わず Lambda 関数を 2 つ作成(A, B と呼ぶ)
  2. S3 コンソールのバケット詳細画面で [プロパティ] タブを開く
  3. [イベント通知を作成] ボタンをクリック
  4. [Lambda 関数] 欄にAを指定(その他は適当に入力)
  5. [変更の保存] ボタンをクリック
  6. 後述のコマンド例を実施
  7. 「2. 3.」を繰り返す
  8. [Lambda 関数] 欄にBを指定(その他は適当に入力)
  9. [変更の保存] ボタンをクリックで事象再現

コマンド例

$ FunctionName=<A の関数名>

$ Sid=$(aws lambda get-policy \
    --function-name $FunctionName \
    | jq '.Policy | fromjson' \
    | jq '.Statement[].Sid' \
    | sed 's/"//g')

$ aws lambda remove-permission \
    --function-name $FunctionName \
    --statement-id $Sid

参考資料