AWS CloudFormation에서 “다음 대상 구성을 확인할 수 없음” 오류를 방지하려면 어떻게 해야 합니까?

최종 업데이트 날짜: 2020년 9월 9일

Amazon Simple Storage Service(Amazon S3) 이벤트 알림에 대해 Amazon Simple Notification Service(Amazon SNS) 주제 또는 AWS Lambda 함수를 구독합니다. 그리고 다음 오류 메시지 "Unable to validate the following destination configurations."를 수신합니다. 내 템플릿의 S3 버킷에서 SNS 주제 정책에 대한 종속성을 설정하려고 하면 순환 종속성 확인 오류가 발생합니다.

간략한 설명

AWS CloudFormation이 종속성 순서를 처리하는 방식 때문에 Amazon S3 이벤트 알림은 S3 버킷의 속성으로 정의됩니다. 이러한 알림은 S3 버킷 리소스가 생성될 때 설정됩니다.

오류를 방지하려면 다음 순서로 리소스를 생성해야 합니다.

  1. S3 버킷이 SNS 주제를 참조하므로 SNS 주제를 생성합니다.
  2. SNS 주제 정책이 S3 버킷과 SNS 주제를 모두 참조하므로 S3 버킷을 생성합니다.

S3 이벤트 알림에 SNS 주제를 구독하기 전에 적절한 권한을 가진 주제 정책(AWS:: SNS:: TopicPolicy)을 지정해야 합니다. 구독을 생성하기 전에 해당 주제 정책이 존재해야 합니다.

다음 전략 중 하나를 시도해 "다음 대상 구성을 확인할 수 없음(Unable to validate the following destination configurations)" 오류를 방지하십시오.

  • AWS CloudFormation 템플릿에서 BucketName에 대한 값 지정
  • 스택을 생성한 다음, 스택 업데이트 수행

​해결 방법

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": { "Service": "s3.amazonaws.com" },
                        "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": { "Service": "s3.amazonaws.com" },
                        "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"
                    }
                ]
            }
        }
    }
  }
}

스택을 생성한 다음, 스택 업데이트 수행

스택 생성을 두 단계로 나눕니다. 먼저 스택을 생성하되 [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": { "Service": "s3.amazonaws.com" },
                            "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": { "Service": "s3.amazonaws.com" },
                        "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 템플릿 플립을 사용하여 AWS CloudFormation 템플릿을 JSON과 YAML 형식 간에 변환할 수 있습니다.