6

I'm using CloudFormation to manage a CloudFront distribution.

On this CloudFront distribution I've associated a Lambda Edge function (without using CloudFormation).

The problem is later, when I update the CloudFront distribution with the same CloudFormation stack, it removes all Lambda Edge associations.

How to prevent that?

That's really unfortunate..

PS: Sometimes CloudFormation removes Lambda associations (when updating the Certificate ARN for exemple) and sometimes not.

Edit: I can try to use https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html but is there a less hacky way? Nope..

Edit: Same question on AWS forum https://forums.aws.amazon.com/thread.jspa?threadID=274111 (needs to be signed in)

Yves M.
  • 29,855
  • 23
  • 108
  • 144
  • 2
    I suspect the core of the problem is that CloudFormation is arguably doing the right thing -- the CloudFront [`UpdateDistribution` API action](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) is a monolithic action where all the attributes of the distribution must be specified, not just the changes. The console hides this complexity. CloudFormation is probably just changing it to be as it "should" be. – Michael - sqlbot Feb 19 '18 at 19:11
  • @michael-sqlbot Yep.. but then how should I add a Lambda association?.. that looks like an AWS "bug". I think it make sense to decorrelate Lambda association from the CloudFront distribution itself. Maybe AWS sees Lambda Edge and CloudFront as highly coupled (but that's too bad) – Yves M. Feb 20 '18 at 13:39
  • They are *very* highly coupled. In fact, that's an understatement. Lambda@Edge is part of CloudFront -- the part that is able to hook requests and responses and invoke Lambda functions. Triggers (timing and which function) are attributes of the Cache Behavior. If CloudFormation controls your distribution, it seems like you should add Lambda triggers from there, rather than directly. – Michael - sqlbot Feb 20 '18 at 18:57
  • Yes they looks highly coupled. The problem is that I have **3 Lambda@Edge** for different events (origin response, origin request, viewer response) with their own lifecycle... And also **those same 3 Lambda@Edge** are used on 5 different CloudFront distributions. I'm pretty stuck.. Maybe my architecture is going against AWS vision of Lambda@Edge :-/ – Yves M. Feb 21 '18 at 17:53

1 Answers1

0

It is possible to "deploy" new Lambda@Edge functions for CloudFront with CloudFormation.

CloudFront and Lambda@Edge requires versioned Lambda functions. So you need to make sure your CloudFront template publishes a new version on Lambda code changes, and that your Distribution uses the version alias.

See the CloudFormation template in my boilerplate Go/Lambda app for a working example:

  WebAuthFunction:
    Properties:
      AutoPublishAlias: Live
      CodeUri: ./web/handlers/auth/index.zip
      Environment: !Ref AWS::NoValue
      FunctionName: !Sub ${AWS::StackName}-WebAuthFunction
      Handler: index.handler
      Role: !GetAtt WebAuthFunctionRole.Arn
      Runtime: nodejs6.10
    Type: AWS::Serverless::Function

  WebDistribution:
    Condition: WebDomainNameSpecified
    Properties:
      DistributionConfig:
        Aliases:
          - !Ref WebDomainName
        Comment: !Sub Distribution for ${WebBucket}
        DefaultCacheBehavior:
          AllowedMethods:
            - GET
            - HEAD
          Compress: true
          ForwardedValues:
            Cookies:
              Forward: none
            QueryString: true
          LambdaFunctionAssociations:
            - !If
              - OAuthClientIdSpecified
              - EventType: viewer-request
                LambdaFunctionARN: !Ref WebAuthFunction.Version
              - !Ref AWS::NoValue
          TargetOriginId: !Ref WebBucket
          ViewerProtocolPolicy: redirect-to-https
        DefaultRootObject: index.html
        Enabled: true
        HttpVersion: http2
        Origins:
          - DomainName: !Sub ${WebBucket}.s3.amazonaws.com
            Id: !Ref WebBucket
            S3OriginConfig:
              OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${WebOriginAccessIdentity}
        PriceClass: PriceClass_All
        ViewerCertificate:
          AcmCertificateArn: !Ref WebCertificate
          SslSupportMethod: sni-only
    Type: AWS::CloudFront::Distribution
Noah Zoschke
  • 571
  • 4
  • 4
  • I'm already using a CloudFormation template to deploy my Lambda@Edge functions.. but still, when I update my CloudFront distribution (with another CloudFormation template), all associations/triggers are gone – Yves M. Mar 30 '18 at 16:10
  • 1
    You have two CloudFormation templates operating on a single CloudFront distribution? Are you using Lambda versions and aliases in CloudFormation? Take a look at this guide here, as this did the trick for me. https://github.com/awslabs/serverless-application-model/blob/master/docs/safe_lambda_deployments.rst#instant-traffic-shifting-using-lambda-aliases. Note I’m using the SAM dialect of CloudFormation – Noah Zoschke Mar 30 '18 at 16:36
  • 1
    For CloudFormation, the template is the source. So if you apply a template without the lambda association it will remove a previous association set up manually or by another template. – Noah Zoschke Mar 30 '18 at 16:40