Search code examples
amazon-web-servicesaws-lambdaaws-cloudformation

How to create a new version of a Lambda function using CloudFormation?


I'm trying to create a new version of a Lambda function using CloudFormation.

I want to have multiple versions of the same Lambda function so that I can (a) point aliases at different versions - like DEV and PROD - and (b) be able to roll back to an earlier version

This is the definition of my Lambda version:

LambdaVersion:
  Type: AWS::Lambda::Version
  Properties:
    FunctionName:
      Ref: LambdaFunction

A version gets created when running "aws cloudformation create-stack" but the subsequent "aws cloudformation update-stack" commands don't do anything. There are no new Lambda versions created.

I'm trying to get a new version of the Lambda function created after I upload new zip file to S3 and then run "update-stack". Can I do it with CloudFormation? Is AWS::Lambda::Version really broken (as mentioned here https://github.com/hashicorp/terraform/issues/6067#issuecomment-211708071) or am I just not getting something?

Update 1/11/17 Official reply from Amazon support: "...for any new version to be published you need to define an addition (sic) AWS::Lambda::Version resource..."

AWS CloudFormation/Lambda team, if you're reading this - this is unacceptable. Fix it.


Solution

  • AWS::Lambda::Version is not useful. You have to add a new resource for every Lambda version. If you want to publish a new version for every Cloudformation update, you have to hack the system.

    I solved this issue creating a Lambda backed custom resource which is triggered for every deployment. Inside this Lambda, I am creating a new version for the Lambda function given in parameter.

    For the Lambda's source you can check http://serverless-arch-eu-west-1.s3.amazonaws.com/serverless.zip

    Here is the example Cloudformation using this Deployment Lambda function (You might need some modification):

    {
      "AWSTemplateFormatVersion": "2010-09-09",
      "Parameters": {
        "DeploymentTime": {
          "Type": "String",
          "Description": "It is a timestamp value which shows the deployment time. Used to rotate sources."
        }
      },
      "Resources": {
        "LambdaFunctionToBeVersioned": {
          "Type": "AWS::Lambda::Function",
           ## HERE DEFINE YOUR LAMBDA AS USUAL ##
        },
        "DeploymentLambdaRole": {
          "Type": "AWS::IAM::Role",
          "Properties": {
            "AssumeRolePolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Principal": {
                    "Service": [
                      "lambda.amazonaws.com"
                    ]
                  },
                  "Action": [
                    "sts:AssumeRole"
                  ]
                }
              ]
            },
            "Path": "/",
            "ManagedPolicyArns": [
              "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
            ],
            "Policies": [
              {
                "PolicyName": "LambdaExecutionPolicy",
                "PolicyDocument": {
                  "Version": "2012-10-17",
                  "Statement": [
                    {
                      "Effect": "Allow",
                      "Action": [
                        "lambda:PublishVersion"
                      ],
                      "Resource": [
                        "*"
                      ]
                    }
                  ]
                }
              }
            ]
          }
        },
        "DeploymentLambda": {
          "Type": "AWS::Lambda::Function",
          "Properties": {
            "Role": {
              "Fn::GetAtt": [
                "DeploymentLambdaRole",
                "Arn"
              ]
            },
            "Handler": "serverless.handler",
            "Runtime": "nodejs4.3",
            "Code": {
              "S3Bucket": {
                "Fn::Sub": "serverless-arch-${AWS::Region}"
              },
              "S3Key": "serverless.zip"
            }
          }
        },
        "LambdaVersion": {
          "Type": "Custom::LambdaVersion",
          "Properties": {
            "ServiceToken": {
              "Fn::GetAtt": [
                "DeploymentLambda",
                "Arn"
              ]
            },
            "FunctionName": {
              "Ref": "LambdaFunctionToBeVersioned"
            },
            "DeploymentTime": {
              "Ref": "DeploymentTime"
            }
          }
        }
      }
    }
    

    (Disclaimer: This code is a part of my book, for more information about Lambda & API Gateway you can check: https://www.amazon.com/Building-Serverless-Architectures-Cagatay-Gurturk/dp/1787129195)