Miserlou / Zappa

Serverless Python
https://blog.zappa.io/
MIT License
11.89k stars 1.2k forks source link

Have to reset ALB target group lambda:InvokeFunction permissions on each update #1883

Open gigi-at-zymergen opened 5 years ago

gigi-at-zymergen commented 5 years ago

Context

We use Zappa in our Jenkins CI pipelines to deploy/update Lambdas. We're using target groups in ALBs to invoke Lambdas in a hybrid environment where some rules forward requests to Lambdas, and other requests go to EC2 or k8s hosted services. It's entirely internal, and we use ALBs rather than the API Gateway to declaratively manage our hybrid routing rules. We have had to add a step to all our pipelines to reset permissions to allow InvokeFunction from ALB target groups after every update:

aws lambda add-permission --function-name ${lambda-ARN} \
--action lambda:InvokeFunction --statement-id elb1 --principal elasticloadbalancing.amazonaws.com

Is there some configuration we could use to preserve this permission from update to update? Seems related to https://github.com/Miserlou/Zappa/issues/980 , but triggering from ALB Target Groups is somewhat different than the API Gateway.

We're also not using Zappa to configure an ALB ( using an existing ALB configured externally ) so this may also be related to https://github.com/Miserlou/Zappa/issues/1832 . And permissions may get overwritten with the assumption that Zappa would be handling any ALB config.

Expected Behavior

We were expecting the InvokeFunction permissions to be preserved on update.

Actual Behavior

Any existing permissions are overwritten on update

Possible Fix

We may be unaware of an existing configuration which would preserve permissions on update, but if it doesn't exist a flag to preserve existing permissions on update would be desired.

Steps to Reproduce

  1. Deploy a simple zappa lambda (hello world)
  2. Call aws lambda add-permission --function-name ${lambda-ARN} --action lambda:InvokeFunction --statement-id elb1 --principal elasticloadbalancing.amazonaws.com
  3. configure a simple ALB with one target group to trigger the lambda
  4. Test that you can trigger the lambda by calling the endpoint through the ALB
  5. Use zappa update $VERSION_CODE -s settings.json to update the Lambda
  6. Call the endpoint through the ALB and get a 502, and lambda does not trigger
  7. Call the AWS add-permission call from step 2 again
  8. call the endpoint and get a 200 and lambda triggers

Your Environment

xealot commented 4 years ago

This is frustrating, I don't see a way to manage the ALB outside of Zappa and have the Function Policy be updated appropriately.

adam-harwood commented 6 months ago

I got halfway through opening a PR to fix this, but I think we're just going to migrate off Zappa instead. Still, dropping the change I hacked in that fixed this in case someone wants to pick it up. I changed deploy_lambda_alb in core.py to have:

        kwargs = dict(
            Action="lambda:InvokeFunction",
            FunctionName=lambda_name,
            Principal="elasticloadbalancing.amazonaws.com",
            SourceArn=target_group_arn,
            StatementId=lambda_name,
        )
        response = self.lambda_client.add_permission(**kwargs)

        # Register target group to lambda association.
        # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/elbv2.html#ElasticLoadBalancingv2.Client.register_targets
        kwargs = dict(
            TargetGroupArn=target_group_arn,
            Targets=[{"Id": lambda_arn}],
        )
        response = self.elbv2_client.register_targets(**kwargs)

The key parts being the FunctionName on the add_permission call, and then the Id on the register_targets call. For reasons I don't fully understand, the code already there wasn't adding any permission (confirmed by adding a call to get the policy in there), even though it was returning a 201. With the above change it works. The part I hadn't figured out was how to include Alias in there.

Hope this helps someone.