다음 리소스를 사용하여 템플릿을 배포할 경우 AWS CloudFormation 스택 생성이 실패합니다.

  1. AWS Lambda 함수 리소스.
  2. Lambda 함수를 참조하는 NotificationConfiguration 속성과 Amazon S3 버킷 리소스.
  3. Lambda 함수 및 S3 버킷과 일치하는 FunctionNameSourceArn 속성과 함께 Lambda 권한 리소스.
    주의: S3 이벤트 소스를 위해 SourceAccount 속성을 Lambda 권한 리소스에 추가하는 것이 모범 사례입니다. S3 Amazon 리소스 이름(ARN)이 계정 ID를 포함하지 않기 때문입니다. SourceArn 속성은 기타 대부분의 이벤트 소스에 적합하지만 S3 이벤트 소스에 SourceAccount 속성을 추가하여 다른 사람이 이 버킷을 다시 만든 경우에만 버킷을 삭제하고 버킷의 새로운 소유자가 모든 권한을 사용하여 Lambda 함수를 호출할 수 있습니다.

스택이 실패한 경우, 다음과 비슷한 오류가 발생합니다.

Unable to validate the following destination configurations

버킷을 생성할 경우, S3는 버킷이 Lambda 함수로 이벤트를 푸시할 수 있는 권한 여부를 확인하여 알림 구성을 확인해야 합니다. 권한 리소스(이 검사를 통과해야 함)에는 버킷 이름이 필요합니다. 따라서 권한 리소스는 버킷에 따라 다르며 버킷도 권한 리소스에 따라 다릅니다.

주의: 다음과 비슷한 DependsOn 리소스 속성을 실행하여 이 문제를 해결하고자 할 경우, 다음과 같은 오류 메시지가 표시됩니다.

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

DependsOn 리소스 속성 오류:

Circular dependency between resources

이 예제에서 S3 버킷 리소스 및 Lambda 권한 리소스의 SourceArn 속성 사이의 순환 종속성이 있습니다. 리소스 둘 다 존재하지 않을뿐더러 한 리소스는 다른 리소스 없이 생성될 수 없기 때문입니다.

이 문제가 발생하면 스택 파라미터와 함께 Fn::Join 내장 함수를 사용하여 순환 종속성을 피할 수 있습니다.

"BucketPrefix"이라는 버킷 이름이 파라미터로써 "AWS::S3::Bucket" 및 "AWS::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::Join": [
            "",
            [
              "arn:aws:s3:::",
              {
                "Fn::Sub": "${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": "nodejs4.3"
      }
    },
    "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. IAM 역할
  2. Lambda 함수
  3. Lambda 권한
  4. S3 버킷

이러한 접근으로 S3를 허용하여 알림 구성을 확인하고 문제없이 버킷을 생성합니다.

가능한 다른 해결 방법은 다음과 같습니다.

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

페이지 내용이 도움이 되었습니까? | 아니요

AWS 지원 지식 센터로 돌아가기

도움이 필요하십니까? AWS 지원 센터를 방문하십시오.

게시 날짜: 2017-10-03

업데이트됨: 2018-09-06