AWS CloudFormation에서 Lambda 이벤트 알림과 관련하여 “Unable to validate the following destination configurations” 오류가 발생하지 않도록 하려면 어떻게 해야 하나요?

4분 분량
0

AWS CloudFormation 템플릿을 배포할 때 스택이 실패합니다. 그리고 “Unable to validate the following destination configurations”와 비슷한 오류가 표시됩니다.

간략한 설명

다음 리소스를 사용하여 CloudFormation 템플릿을 배포할 때 이 오류가 발생합니다.

Amazon S3는 버킷을 생성할 때 알림 구성을 검증해야 합니다. 검증은 버킷에 Lambda 함수로 이벤트를 푸시할 권한이 있는지 여부를 확인하여 수행됩니다. 권한 리소스(이 검사를 통과하려면 존재해야 함)에는 버킷 이름이 필요합니다. 즉, 권한 리소스는 버킷에 의존하고 버킷은 권한 리소스에 의존합니다.

참고: 다음 코드 예제와 비슷한 DependsOn 리소스 속성을 구현하여 이 문제를 해결하려고 하면 “Circular dependency between resources” 오류가 표시됩니다.

다음 예제는 S3 버킷 리소스와 Lambda 권한 리소스의 SourceArn 속성 간에 순환 종속성을 보여줍니다.

"Resources": {
  "MyS3BucketPermission": {
    "Type": "AWS::Lambda::Permission",
    "Properties": {
      "Action": "lambda:InvokeFunction",
      ...
      ...
      "SourceArn": {
        "Ref": "MyS3Bucket"
      }
    }
  },
  "MyS3Bucket": {
    "DependsOn" : "MyS3BucketPermission",
    ...
    ...

중요: SourceAccount 속성을 Amazon S3 이벤트 소스에 대한 Lambda 권한 리소스에 추가하는 것이 가장 좋습니다. Amazon S3의 Amazon 리소스 이름(ARN) 에는 계정 ID가 포함되어 있지 않으므로 해당 속성을 추가합니다. SourceArn 속성은 대부분의 다른 이벤트 소스에 적합하지만 Amazon S3 이벤트 소스에 대해 SourceAccount 속성을 추가하는 것이 좋습니다. 이렇게 하면 사용자가 삭제한 버킷을 다시 생성한 다음 새 버킷 소유자에게 Lambda 함수를 호출할 수 있는 모든 권한을 부여할 수 없습니다.

해결 방법

스택 파라미터와 함께 Fn::Sub 내장 함수를 사용하여 순환 종속성을 방지할 수 있습니다. 또한 Fn።Join을 사용하여 문자열을 결합할 수 있습니다.

다음 샘플 템플릿에서 S3 버킷 이름 BucketPrefixAWS::S3::BucketAWS::Lambda::Permission 리소스의 파라미터입니다.

참고: 다음 예제에서는 버킷 이름이 AWS 계정에서 이전에 사용되지 않았다고 가정합니다. 이 코드 조각과 함께 템플릿을 재사용하고자 할 경우, 매번 다른 버킷 접두사를 제공해야 합니다.

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "BucketPrefix": {
      "Type": "String",
      "Default": "test-bucket-name"
    }
  },
  "Resources": {
    "EncryptionServiceBucket": {
      "DependsOn": "LambdaInvokePermission",
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": {
          "Fn::Sub": "${BucketPrefix}-encryption-service"
        },
        "NotificationConfiguration": {
          "LambdaConfigurations": [
            {
              "Function": {
                "Fn::GetAtt": [
                  "AppendItemToListFunction",
                  "Arn"
                ]
              },
              "Event": "s3:ObjectCreated:*",
              "Filter": {
                "S3Key": {
                  "Rules": [
                    {
                      "Name": "suffix",
                      "Value": "zip"
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    },
    "LambdaInvokePermission": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "FunctionName": {
          "Fn::GetAtt": [
            "AppendItemToListFunction",
            "Arn"
          ]
        },
        "Action": "lambda:InvokeFunction",
        "Principal": "s3.amazonaws.com",
        "SourceAccount": {
          "Ref": "AWS::AccountId"
        },
        "SourceArn": { 
            "Fn::Sub": "arn:aws:s3:::${BucketPrefix}-encryption-service"
        }
      }
    },
    "AppendItemToListFunction": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Handler": "index.handler",
        "Role": {
          "Fn::GetAtt": [
            "LambdaExecutionRole",
            "Arn"
          ]
        },
        "Code": {
          "ZipFile": {
            "Fn::Join": [
              "",
              [
                "var response = require('cfn-response');",
                "exports.handler = function(event, context) {",
                " var responseData = {Value: event.ResourceProperties.List};",
                " responseData.Value.push(event.ResourceProperties.AppendedItem);",
                " response.send(event, context, response.SUCCESS, responseData);",
                "};"
              ]
            ]
          }
        },
        "Runtime": "nodejs12.x"
      }
    },
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "lambda.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/",
        "Policies": [
          {
            "PolicyName": "root",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "logs:*"
                  ],
                  "Resource": "arn:aws:logs:*:*:*"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

템플릿은 리소스를 다음 순서로 생성하기 때문에 순환 종속성을 방지합니다.

  1. AWS Identity and Access Management(IAM) 역할
  2. Lambda 함수
  3. Lambda 권한
  4. S3 버킷

이제 Amazon S3는 알림 구성을 확인하고 문제 없이 버킷을 생성할 수 있습니다.

다음 해결 방법을 시도할 수도 있습니다.

  • 알림 구성 없이 S3 버킷을 생성한 후 다음 스택 업데이트에 버킷을 추가합니다.
  • 제약이 적은 Lambda 권한을 만듭니다. 예를 들어, SourceArn을 생략하여 특정 AWS 계정에 대한 호출을 허용합니다.
  • 스택 워크플로가 끝날 때 실행할 사용자 지정 리소스를 생성합니다. 이 리소스는 다른 모든 리소스가 생성된 후 S3 버킷에 알림 구성을 추가합니다.

관련 정보

AWS CloudFormation에서 "다음 대상 구성을 검증할 수 없음" 오류가 발생하지 않도록 하려면 어떻게 해야 하나요?

AWS Lambda에서 Amazon S3 이벤트 사용

Ref

Fn::GetAtt

AWS 공식
AWS 공식업데이트됨 3년 전
댓글 없음

관련 콘텐츠