Come posso correggere la dipendenza circolare tra un'autorizzazione AWS Lambda e le risorse del gruppo target in AWS CloudFormation?
Voglio correggere la dipendenza circolare tra un'autorizzazione AWS Lambda (AWS::Lambda::Permission) e le risorse del gruppo target (AWS::ElasticLoadBalancingV2::TargetGroup) in AWS CloudFormation.
Risoluzione
Una dipendenza circolare può verificarsi quando si configura un AWS::ElasticLoadBalancingV2::TargetGroup con un target della funzione Lambda e una risorsa AWS::Lambda::Permission associata. Tale situazione si verifica a causa delle seguenti interdipendenze:
Per registrare una funzione Lambda come target utilizzando la sua proprietà Target, l’AWS::ElasticLoadBalancingV2::TargetGroup richiede l’AWS::Lambda::Permission per consentire a Elastic Load Balancing di invocare la funzione Lambda.
Inoltre, l’AWS::Lambda::Permission richiede l'ARN dell’AWS::ElasticLoadBalancingV2::TargetGroup nella sua proprietà SourceArn per limitare le autorizzazioni di invocazione a gruppi target specifici.
In questo caso, l’AWS::ElasticLoadBalancingV2::TargetGroup non può essere creato completamente senza l’AWS::Lambda::Permission. Ma l’AWS::Lambda::Permission non può essere creata senza l'ARN dell’AWS::ElasticLoadBalancingV2::TargetGroup. Di conseguenza, CloudFormation non è in grado di determinare la risorsa da creare per prima. Si tratta di un errore di dipendenza circolare.
Per risolvere la dipendenza circolare, sostituisci la proprietà Target dell’AWS::ElasticLoadBalancingV2::TargetGroup con una risorsa personalizzata supportata da Lambda per registrare la funzione Lambda come target.
Utilizza una risorsa personalizzata supportata da Lambda per registrare la tua funzione Lambda come target nel tuo gruppo target
Utilizza un modello CloudFormation per definire una risorsa personalizzata supportata da Lambda per registrare la tua funzione Lambda come target nel tuo gruppo target.
Tieni presente i seguenti fattori quando crei il modello:
- Il modello CloudFormation include un esempio di funzione Lambda HelloWorld e risorse ELBv2come riferimento.
- Questo modello fornisce una funzione Lambda RegisterTargetsFunction aggiuntiva con un ruolo di esecuzione associato e una risorsa personalizzata. La risorsa personalizzata invoca la funzione Lambda ogni volta che la risorsa personalizzata viene creata, aggiornata o eliminata.
- Durante la creazione della risorsa personalizzata, la funzione Lambda RegisterTargetsFunction registra la funzione Lambda definita come target nel gruppo target fornito. Durante l'eliminazione della risorsa personalizzata, la funzione annulla la registrazione del target.
- Puoi modificare il modello con il tuo codice.
- Il modello utilizza risorse personalizzate supportate da AWS Lambda e presuppone che tu conosca le best practice e la risoluzione dei problemi di Lambda.
Crea il tuo modello CloudFormation
Per creare il tuo modello CloudFormation, utilizza il seguente esempio:
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
Utilizza il tuo modello CloudFormation per creare il tuo stack CloudFormation
- Salva il modello che hai creato come file YAML.
- Utilizza AWS CLI o la console CloudFormation per creare uno stack.
Nota: se ricevi messaggi di errore durante l'esecuzione dei comandi dell'interfaccia della linea di comando AWS (AWS CLI), consulta Troubleshoot AWS CLI errors. Inoltre, assicurati di utilizzare la versione più recente di AWS CLI. - Utilizza i parametri dello stack VpCId, Subnets e TargetGroupName per specificare l’Amazon Virtual Private Cloud (Amazon VPC), le sottoreti e il nome del gruppo target desiderati.
- Dopo che lo stack ha raggiunto lo stato CREATE_COMPLETE, vai alla sezione Output della console AWS CloudFormation per verificare la presenza del seguente messaggio:
"Successfully Added Lambda(arn:aws:lambda:<region>:<account_id>:function:<function_name>) as Target" - Controlla il gruppo target per verificare che il target sia stato registrato.
- Argomenti
- Management & Governance
- Lingua
- Italiano

Contenuto pertinente
AWS UFFICIALEAggiornata 4 anni fa