AWS CloudFormation で S3 イベント通知を使用するときに、「次の宛先設定を検証できません」というエラーを回避する方法を教えてください

最終更新日: 2019 年 11 月 8 日

Amazon Simple Notification Service (Amazon SNS) トピックまたは AWS Lambda 関数を Amazon Simple Storage Service (Amazon S3) イベント通知に登録します。その後、「以下の送信先設定を検証できません」というエラーが表示されます。 テンプレートの S3 バケットから SNS トピックポリシーへの依存関係を設定しようとすると、循環依存関係の検証エラーが発生します。

簡単な説明

AWS CloudFormation が依存関係の順序を処理する方法により、Amazon S3 イベント通知は S3 バケットの属性として定義されます。これらの通知は、S3 バケットリソースの作成時に確立されます。

エラーを回避するには、次の順でリソースを作成する必要があります。

  1. S3 バケットが SNS トピックを参照するため、SNS トピックを作成します。
  2. SNS トピックポリシーは S3 バケットと SNS トピックの両方を参照するため、S3 バケットを作成します。

SNS トピックを S3 イベント通知に登録する前に、適切な権限を持つトピックポリシー (AWS::SNS::TopicPolicy) を指定する必要があります。そのトピックポリシーが登録する前に存在している必要があります。

解決方法

「以下の送信先設定を検証できません」というエラーを回避するには、次のいずれかの方法をお試しください。

AWS CloudFormation テンプレートで BucketName の値を指定する

AWS CloudFormation テンプレートの S3Bucket リソースで BucketName プロパティの値を指定して、S3 バケットに静的名を使用します。これにより、SNS トピックポリシーに {"Ref": "paramBucketName"} を含める必要がなくなり、SNS トピックポリシーと Amazon S3 間の組み込み依存関係が削除されます。

次の AWS CloudFormation テンプレートの例では、BucketName プロパティにハードコードされた値 (-Bucket-Name-) を指定します。テンプレートで -Bucket-Name- のすべてのインスタンスをバケット名に置き換えます。

{
  "Resources": {
    "SNSTopic": {
        "Type": "AWS::SNS::Topic"
    },
    "SNSTopicPolicy": {
        "Type": "AWS::SNS::TopicPolicy",
        "Properties": {
            "PolicyDocument": {
                "Id": "MyTopicPolicy",
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "Statement-id",
                        "Effect": "Allow",
                        "Principal": { "AWS": "*" },
                        "Action": "sns:Publish",
                        "Resource": { "Ref": "SNSTopic" },
                        "Condition": {
                            "ArnLike": {
                                "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", "-Bucket-Name-" ]]} }
                        }
                    }
                ]
            },
            "Topics": [ { "Ref": "SNSTopic" } ]
        }
    },
    "S3Bucket": {
        "Type": "AWS::S3::Bucket",
        "DependsOn": ["SNSTopicPolicy"],
        "Properties": {
            "AccessControl": "BucketOwnerFullControl",
            "BucketName": "-Bucket-Name-",
            "NotificationConfiguration": {
                "TopicConfigurations": [
                    {
                        "Topic": { "Ref": "SNSTopic" },
                        "Event": "s3:ObjectCreated:Put"
                    }
                ]
            }
        }
    }
  }
}

注意: S3Bucket リソースには、SNSTopicPolicy に設定されている明示的な DependsOn 値があります。この属性は、テンプレートが S3Bucket リソースの前に SNSTopicPolicy リソースを作成するように指定します。

S3 バケットで同じ AWS CloudFormation テンプレートを異なる名前で使用するには、バケット名にパラメータを設定します。パラメータを使用すると、スタックの作成時にバケット名をパラメータとして渡すことによって、異なるバケット名に同じテンプレートを使用できます。

次のサンプルテンプレートを使用するには、スタックの作成時に paramBucketName パラメータとしてバケット名を渡す必要があります。

{
  "Parameters": {
    "paramBucketName": {
      "Type": "String",
      "Description": "Bucket Name"
    }
  },
  "Resources": {
    "SNSTopic": {
        "Type": "AWS::SNS::Topic"
    },
    "SNSTopicPolicy": {
        "Type": "AWS::SNS::TopicPolicy",
        "Properties": {
            "PolicyDocument": {
                "Id": "MyTopicPolicy",
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "Statement-id",
                        "Effect": "Allow",
                        "Principal": { "AWS": "*" },
                        "Action": "sns:Publish",
                        "Resource": { "Ref": "SNSTopic" },
                        "Condition": {
                            "ArnLike": {
                                "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", {"Ref": "paramBucketName"} ]]} }
                        }
                    }
                ]
            },
            "Topics": [ { "Ref": "SNSTopic" } ]
        }
    },
    "S3Bucket": {
        "Type": "AWS::S3::Bucket",
        "DependsOn": ["SNSTopicPolicy"],
        "Properties": {
            "AccessControl": "BucketOwnerFullControl",
            "BucketName": {"Ref": "paramBucketName"},
            "NotificationConfiguration": {
                "TopicConfigurations": [
                    {
                        "Topic": { "Ref": "SNSTopic" },
                        "Event": "s3:ObjectCreated:Put"
                    }
                ]
            }
        }
    }
  }
}

スタックを作成し、スタック更新を実行する

スタックの作成を 2 つのステージに分割します。まず、スタックを作成します。ただし、S3Bucket リソースで NotificationConfiguration プロパティを指定してはいけません。次に、スタックの更新を実行して S3 イベント通知を追加します。これにより、SNS トピックポリシーが作成される前に S3 イベント通知を設定する必要がなくなります。

1.    SNS トピックポリシーを含むすべてのリソースを作成します。次の例を参照してください。

{
    "Resources": {
        "SNSTopic": {
            "Type": "AWS::SNS::Topic"
        },
        "SNSTopicPolicy": {
            "Type": "AWS::SNS::TopicPolicy",
            "Properties": {
                "PolicyDocument": {
                    "Id": "MyTopicPolicy",
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Sid": "Statement-id",
                            "Effect": "Allow",
                            "Principal": { "AWS": "*" },
                            "Action": "sns:Publish",
                            "Resource": { "Ref": "SNSTopic" },
                            "Condition": {
                                "ArnLike": {
                                    "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3Bucket" } ] ]
                                    }
                                }
                            }
                        }
                    ]
                },
                "Topics": [ { "Ref": "SNSTopic" } ]
            }
        },
        "S3Bucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "AccessControl": "BucketOwnerFullControl"
            }
        }
    }
}

2.    スタックを更新して S3 イベント通知を追加します。次の例を参照してください。

{
  "Resources": {
        "SNSTopic": {
        "Type": "AWS::SNS::Topic"
    },
    "SNSTopicPolicy": {
        "Type": "AWS::SNS::TopicPolicy",
        "Properties": {
            "PolicyDocument": {
                "Id": "MyTopicPolicy",
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "Statement-id",
                        "Effect": "Allow",
                        "Principal": { "AWS": "*" },
                        "Action": "sns:Publish",
                        "Resource": { "Ref": "SNSTopic" },
                        "Condition": {
                            "ArnLike": {
                                "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3Bucket" } ] ]
                                }
                            }
                        }
                    }
                ]
            },
            "Topics": [ { "Ref": "SNSTopic" } ]
        }
    },
    "S3Bucket": {
        "Type": "AWS::S3::Bucket",
        "Properties": {
            "AccessControl": "BucketOwnerFullControl",
            "NotificationConfiguration": {
                "TopicConfigurations": [
                    {
                        "Topic": { "Ref": "SNSTopic" },
                        "Event": "s3:ObjectCreated:Put"
                    }
                ]
            }
        }
    }
  }
}

注意: AWS CloudFormation テンプレートは JSON 形式と YAML 形式の間で変換できます。