all blog posts


Defining a Scheduled Lambda in CloudFormation

AWS Lambda is a super powerful Function as a Service (FaaS) technology provided by Amazon. It's quite easy to set up a scheduled Lambda function in the AWS Console, but in CloudFormation you might run into some issues. This blog post offers a quick copy-and-pastable example.

Four resources

To successfully set up a scheduled Lambda function you need four resources:

  • An IAM Role for the Lambda function
  • A Lambda function
  • A scheduled event rule
  • A Lambda permission that allows the function to be executed by the event rule

The full CloudFormation stack containing these resources looks like this:

{
    "Resources": {
        "LambdaExecutionRole": {
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Statement": [
                        {
                            "Action": [
                                "sts:AssumeRole"
                            ],
                            "Effect": "Allow",
                            "Principal": {
                                "Service": [
                                    "lambda.amazonaws.com"
                                ]
                            }
                        }
                    ],
                    "Version": "2012-10-17"
                },
                "Path": "/",
                "Policies": [
                    {
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Action": "s3:*",
                                    "Effect": "Allow",
                                    "Resource": "*"
                                }
                            ]
                        },
                        "PolicyName": "root"
                    }
                ]
            },
            "Type": "AWS::IAM::Role"
        },
        "LambdaFunction": {
            "Properties": {
                "Code": {
                    "S3Bucket": "your-bucket",
                    "S3Key": "your-file.zip"
                },
                "Handler": "index.lambda_handler",
                "MemorySize": 128,
                "Role": {
                    "Fn::GetAtt": [
                        "LambdaExecutionRole",
                        "Arn"
                    ]
                },
                "Runtime": "python3.7",
                "Timeout": 60
            },
            "Type": "AWS::Lambda::Function"
        },
        "LambdaFunctionSchedule": {
            "Properties": {
                "ScheduleExpression": "cron(00 * * * ? *)",
                "Targets": [
                    {
                        "Arn": {
                            "Fn::GetAtt": [
                                "LambdaFunction",
                                "Arn"
                            ]
                        },
                        "Id": "1"
                    }
                ]
            },
            "Type": "AWS::Events::Rule"
        },
        "LambdaFunctionCwPermission": {
            "Properties": {
                "Action": "lambda:InvokeFunction",
                "FunctionName": {
                    "Fn::GetAtt": [
                        "LambdaFunction",
                        "Arn"
                    ]
                },
                "Principal": "events.amazonaws.com",
                "SourceArn": {
                    "Fn::GetAtt": [
                        "LambdaFunctionSchedule",
                        "Arn"
                    ]
                }
            },
            "Type": "AWS::Lambda::Permission"
        }
    }
}

Let's look at them one by one. The LambdaExecutionRole has no dependencies and could be deployed as a standalone resource. If you were to do that, it would simply appear as an IAM Role in the IAM Console. In this case, it's configured with full S3 permissions.

The LambdaFunction resource is the actual function. It uses a file from an S3 bucket you define as its source. This particular function has a timeout of 60 seconds and is configured to use a maximum of 128MB of RAM.

The LambdaFunctionSchedule is where it gets interesting. This resource has a schedule (defined as cron or as a rate) and one or more targets. Its resource type is AWS::Events::Rule. You could deploy this resource and it would run every hour. When it runs, it would try to execute the Lambda Function as defined in the Targets parameter. However, it would fail to do so, until you deploy the final resource.

The LambdaFunctionCwPermission resource is what makes everything tick. It allows the Lambda function to be executed by the CloudWatch Events Rule. To achieve this, the Action is set to lambda:InvokeFunction, the FunctionName is a reference to the Lambda function's ARN, and the SourceArn is a reference to the CloudWatch Events Rule.

Deploy this stack in CloudFormation, and your Lambda function would look like this:

Lambda Permissions

And that's all you need! If you have any questions or remarks about this blog post, reach out to me on Twitter.


Related blog posts


all blog posts