Help us improve the AWS re:Post Knowledge Center by sharing your feedback in a brief survey. Your input can influence how we create and update our content to better support your AWS journey.
AWS CloudFormation에서 AWS Lambda 권한과 대상 그룹 리소스 간의 순환 종속성을 수정하려면 어떻게 해야 합니까?
AWS CloudFormation에서 AWS Lambda 권한(AWS::Lambda::Permission)과 대상 그룹 리소스(AWS::ElasticLoadBalancingV2::TargetGroup) 간의 순환 종속성을 수정하려고 합니다.
해결 방법
Lambda 함수 대상 및 관련 AWS::Lambda::Permission 리소스를 사용하여 AWS::ElasticLoadBalancingV2::TargetGroup을 구성할 때 순환 종속성이 발생할 수 있습니다. 이 상황은 다음과 같은 상호 종속성으로 인해 발생합니다.
대상 속성을 사용하여 Lambda 함수를 대상으로 등록하려면 AWS::ElasticLoadBalancingV2::TargetGroup에 Elastic Load Balancing이 Lambda 함수를 호출하도록 허용할 수 있는 AWS::Lambda::Permission이 필요합니다.
또한 AWS::Lambda::Permission을 사용하려면 SourceArn 속성에 AWS::ElasticLoadBalancingV2::TargetGroup의 ARN이 있어야 호출 권한을 특정 대상 그룹으로 제한할 수 있습니다.
이 경우 AWS::Lambda::Permission 없이는 AWS::ElasticLoadBalancingV2::TargetGroup을 완전히 생성할 수 없습니다. 그러나 AWS::ElasticLoadBalancingV2::TargetGroup의 ARN이 없으면 AWS::Lambda::Permission을 생성할 수 없습니다. 따라서 CloudFormation은 먼저 생성할 리소스를 결정할 수 없습니다. 이러한 상황이 순환 종속성 오류입니다.
이 순환 종속성을 수정하려면 AWS::ElasticLoadBalancingV2::TargetGroup 대상 속성을 Lambda 지원 사용자 지정 리소스로 대체하여 Lambda 함수를 대상으로 등록하십시오.
Lambda 지원 사용자 지정 리소스를 사용하여 Lambda 함수를 대상 그룹의 대상으로 등록
CloudFormation 템플릿을 사용해 Lambda 지원 사용자 지정 리소스를 정의하여 Lambda 함수를 대상 그룹의 대상으로 등록합니다.
템플릿을 만들 때 다음 요소를 염두에 두십시오.
- CloudFormation 템플릿에는 HelloWorld Lambda 함수 예시와 참조용 ELBv2 리소스가 포함되어 있습니다.
- 이 템플릿은 추가 RegisterTargetsFunction Lambda 함수와 관련 실행 역할 및 사용자 지정 리소스를 제공합니다. 사용자 지정 리소스는 사용자 지정 리소스가 생성, 업데이트 또는 삭제될 때마다 Lambda 함수를 호출합니다.
- 사용자 지정 리소스 생성 중에 RegisterTargetsFunction Lambda 함수는 정의된 Lambda 함수를 제공된 대상 그룹의 대상으로 등록합니다. 사용자 지정 리소스를 삭제하는 동안 함수는 대상의 등록을 취소합니다.
- 자체 코드로 템플릿을 수정할 수 있습니다.
- 이 템플릿은 AWS Lambda 지원 사용자 지정 리소스를 사용하며 사용자가 Lambda의 모범 사례 및 문제 해결에 익숙하다고 가정합니다.
CloudFormation 템플릿 생성
CloudFormation 템플릿을 생성하려면 다음 예제를 사용하십시오.
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AWSTemplateFormatVersion: 2010-09-09 Description: HelloWorld Lambda function template for Application Load Balancer Lambda as target Parameters: # VPC in which the LoadBalancer and the LoadBalancer SecurityGroup will be created VpcId: Type: AWS::EC2::VPC::Id # Subnets in which the LoadBalancer will be created. Subnets: Type: List<AWS::EC2::Subnet::Id> # Name of the TargetGroup TargetGroupName: Type: String Default: 'MyTargets' Resources: 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: AllowRegisterAndDeregisterTargets PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'elasticloadbalancing:RegisterTargets' Resource: !GetAtt TargetGroup.TargetGroupArn - Effect: Allow Action: - 'elasticloadbalancing:DeregisterTargets' Resource: '*' # Lambda function which displays an HTML page with "Hello from Lambda!" message upon invocation HelloWorldFunction: Type: 'AWS::Lambda::Function' Properties: Code: ZipFile: | def lambda_handler(event, context): return { "statusCode": 200, "statusDescription": "HTTP OK", "isBase64Encoded": False, "headers": { "Content-Type": "text/html" }, "body": "<h1>Hello from Lambda!</h1>" } MemorySize: 128 Handler: index.lambda_handler Timeout: 30 Runtime: python3.12 Role: !GetAtt LambdaExecutionRole.Arn LoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing Subnets: !Ref Subnets SecurityGroups: - !Ref LoadBalancerSecurityGroup HttpListener: Type: 'AWS::ElasticLoadBalancingV2::Listener' Properties: DefaultActions: - TargetGroupArn: !Ref TargetGroup Type: forward LoadBalancerArn: !Ref LoadBalancer Port: 80 Protocol: HTTP LoadBalancerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTP to client host VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 HelloWorldFunctionInvokePermission: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt HelloWorldFunction.Arn Action: 'lambda:InvokeFunction' Principal: elasticloadbalancing.amazonaws.com SourceArn: !GetAtt TargetGroup.TargetGroupArn TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Ref TargetGroupName TargetType: lambda # Custom resource for Lambda function - "RegisterTargetsFunction" RegisterTargets: DependsOn: [TargetGroup, HelloWorldFunctionInvokePermission] Type: Custom::RegisterTargets Properties: ServiceToken: !GetAtt RegisterTargetsFunction.Arn ServiceTimeout: 15 # Input parameters for the Lambda function LambdaFunctionARN: !GetAtt HelloWorldFunction.Arn TargetGroupARN: !GetAtt TargetGroup.TargetGroupArn # Lambda function that performs RegisterTargets API call RegisterTargetsFunction: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import logging import boto3, json, botocore import cfnresponse #Define logging properties for 'logging' log = logging.getLogger() log.setLevel(logging.INFO) #Main Lambda function to be executed def lambda_handler(event, context): try: # print the event type sent from cloudformation log.info ("'" + str(event['RequestType']) + "' event was sent from CFN") # Input Parameters TargetGroupARN = event['ResourceProperties']['TargetGroupARN'] LambdaFunctionARN = event['ResourceProperties']['LambdaFunctionARN'] log.info("TargetGroup ARN value is:" + TargetGroupARN) log.info("Lambda Function ARN value is:" + LambdaFunctionARN) responseData = {} # ELBV2 initilize client = boto3.client('elbv2') # Initilize Vars response = '' error_msg = '' if event['RequestType'] == "Create" or event['RequestType'] == "Update": # Make the RegisterTargets API call try: response = client.register_targets( TargetGroupArn=TargetGroupARN, Targets=[ { 'Id': LambdaFunctionARN }, ] ) except botocore.exceptions.ClientError as e: error_msg = str(e) if error_msg: log.info("Error Occured:" + error_msg) response_msg = error_msg # SIGNAL BACK TO CLOUDFORMATION log.info("Trying to signal FAILURE back to cloudformation.") responseData = {"Message" : response_msg, "Function" : context.log_stream_name} cfnresponse.send(event, context, cfnresponse.FAILED, responseData) else: response_msg = "Successfully registered Lambda(" + LambdaFunctionARN + ") as Target" log.info(response_msg) # SIGNAL BACK TO CLOUDFORMATION log.info("Trying to signal SUCCESS back to cloudformation.") responseData = {"Message" : response_msg, "Function" : context.log_stream_name} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData) # log the end of the create event log.info ("End of '" + str(event['RequestType']) + "' Event") elif "Delete" in str(event['RequestType']): # Make the DeregisterTargets API call try: response = client.deregister_targets( TargetGroupArn=TargetGroupARN, Targets=[ { 'Id': LambdaFunctionARN }, ] ) except botocore.exceptions.ClientError as e: error_msg = str(e) if error_msg: log.info("Error Occured:" + error_msg) response_msg = error_msg # SIGNAL BACK TO CLOUDFORMATION log.info("Trying to signal FAILURE back to cloudformation.") responseData = {"Message" : response_msg, "Function" : context.log_stream_name} cfnresponse.send(event, context, cfnresponse.FAILED, responseData) else: response_msg = "Successfully deregistered Lambda(" + LambdaFunctionARN + ") as Target" log.info(response_msg) # SIGNAL BACK TO CLOUDFORMATION log.info("Trying to signal SUCCESS back to cloudformation.") responseData = {"Message" : response_msg, "Function" : context.log_stream_name} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData) # log the end of the create event log.info ("End of '" + str(event['RequestType']) + "' Event") else: log.info ("RequestType sent from cloudformation is invalid.") log.info ("Was expecting 'Create', 'Update' or 'Delete' RequestType(s).") log.info ("The detected RequestType is : '" + str(event['RequestType']) + "'") # SIGNAL BACK TO CLOUDFORMATION log.info("Trying to signal FAILURE back to cloudformation due to invalid request type.") responseData={"Function" : context.log_stream_name} cfnresponse.send(event, context, cfnresponse.FAILED, responseData) except Exception as e: log.info ("Function failed due to the following error:") print (e) # SIGNAL BACK TO CLOUDFORMATION log.info("Trying to signal FAILURE back to cloudformation due to the error.") responseData={"Function" : context.log_stream_name} cfnresponse.send(event, context, cfnresponse.FAILED, responseData) Handler: index.lambda_handler Role: !GetAtt LambdaExecutionRole.Arn Runtime: python3.12 Timeout: '15' Outputs: Message: Description: Message returned from Lambda Value: !GetAtt - RegisterTargets - Message
CloudFormation 템플릿을 사용하여 CloudFormation 스택 구축
- 생성한 템플릿을 YAML 파일로 저장합니다.
- AWS CLI 또는 CloudFormation 콘솔을 사용하여 스택을 생성합니다.
참고: AWS Command Line Interface(AWS CLI) 명령 실행 시 오류가 발생하는 경우, AWS CLI 오류 문제 해결을 참고하세요. 또한 최신 AWS CLI 버전을 사용하고 있는지 확인하십시오. - VpcId, Subnets, TargetGroupName 스택 파라미터를 사용하여 원하는 Amazon Virtual Private Cloud(Amazon VPC), 서브넷 및 대상 그룹 이름을 지정합니다.
- 스택이 CREATE_COMPLETE 상태에 도달하면 AWS CloudFormation 콘솔의 출력 섹션으로 이동하여 다음 메시지를 확인합니다.
"Successfully Added Lambda(arn:aws:lambda:<region>:<account_id>:function:<function_name>) as Target" - 대상 그룹을 검사하여 대상이 등록되었는지 확인합니다.
- 언어
- 한국어

관련 콘텐츠
- 질문됨 2년 전