How to Enable/Disable a Lambda Trigger on a Schedule

By Zac Charles

So, you have a genuinely valid reason, you’re interested in a short-term fix, or you only started reading from here: how can you enable and disable an event source mapping on a schedule?

Let’s look at an “only do work at night” scenario where we want our event source mapping to be enabled every night between 01:00 and 06:00.

Enabling and disabling

Lambda’s UpdateEventSourceMapping API action is used to enable/disable. This action takes the UUID of an event source mapping and everything else is optional. We’re only interested in updating the Enabled property.

At 01:00 we want to call this action and set Enabled to true.
At 06:00 we want to call it again and set Enabled to false.

Scheduling

CloudWatch Events Rules and self-triggering EventBridge Rules can be used for recurring actions like we want. These two are actually the same underlying service, but EventBridge provides more features and is the preferred way to manage events, so we’ll use that.

EventBridge Rules support cron expressions with a minute-level granularity. Websites like crontab.guru are helpful for building these arcane expressions. You can also use the EventBridge console to preview the next 10 times the rule will trigger. Note that EventBridge scheulde expressions are in UTC.

We want to schedule enabling for 0 1 * * ? * (01:00 UTC everyday).
We want to schedule disabling for 0 6 * * ? * (06:00 UTC everyday).

The missing piece

EventBridge can’t call the UpdateEventSourceMapping action directly, so we need some sort of glue in between. Infrastructure automation is one of Lambda’s selling points and Lambda can be targetted by EventBridge, so it’s an obvious choice. We’ll look at that first, then an interesting alternative.

Lambda

This option involves writing a small function that calls the Lambda API to enable or disable the event source mapping.

In my proof of concept, I made a basic Node.js function that takes an event source mapping UUID and a new value for Enabled, then simply calls updateEventSourceMapping. This code is basic enough to be included inline in a CloudFormation template which simplifies deployment.

The function’s execution role needs the lambda:UpdateEventSourceMapping action for any event source mapping it will be used for. You could have one function per event source mapping if you want to grant least privilege. You must also grant EventBridge permission to invoke your new function.

EventBridge rule targets can be configured with a constant JSON text value that will be passed to the function. For the example below, I found the UUID by running list-event-source-mappings (try using the AWS CloudShell).

Pros and cons

This approach is simple, cheap, and uses Lambda for one of its intended purposes. If you’re used to operating Lambda functions, then you’ll have no trouble here.

On the other hand, any extra code you deploy is a liability since each line could contain a bug.

I think the pros outweigh the cons and that this is a perfectly reasonable implementation. Having said that, let’s look at the other solution.

API Gateway

As of writing, API Gateway can act as a proxy for 104 other AWS services. These service integrations are very flexible, allowing you to call actions on the other services without writing code, including UpdateEventSourceMapping.

To work out how to configure the service integration, you look at the Request Syntax section of the action documentation. Specifically, we’re interested the:

  • HTTP method: PUT,
  • Path: /2015-03-31/event-source-mappings/UUID,
  • Headers: Content-type: application/json, and
  • Body: { "Enabled": boolean }

There are many different ways to configure API Gateway based on how you want to call it and how generic/reusable it should be. You could use query string parameters, headers, or a body mapping template, for example.

In my proof of concept, I included the event source mapping UUID in the path override, set the HTTP method to PUT, and kept content handling as its default so EventBridge can vary the body based on whether I’m enabling or disabling.

Over in EventBridge, we need to make some changes:

  • Set the rule target to be API Gateway.
  • Configure the right API, Deployment Stage, and Integration Target.
  • Add a header with key Content-Type and value application/json.
  • Change the constant JSON text. This will now be used for HTTP body and be proxied to UpdateEventSourceMapping, so it must suit the Lambda API:

Security

API Gateway supports three different endpoint types; edge-optimized, regional, and private. There is no point using an edge-optimised endpoint since both EventBridge and Lambda are regional. Since EventBridge doesn’t support private API endpoints, we should use a regional endpoint.

Regional endpoints are publicly accessible by default and obviously we don’t want anyone on the internet being able to enable or disable anything. Luckily, this is easy to solve by enabling IAM authorization in API Gateway.

With Authorization set to AWS_IAM, calls to the API now need to be signed with AWS credentials. Unless you additionally configure a Resource Policy, the credentials must be from the same account and allow execute-api:Invoke on the API.

Once configured with an IAM role similar the one below, EventBridge will handle signing requests and be able to invoke your API again.

With this configuration, your API is secured by IAM basically the same way the underlying Lambda API is.

Pros and cons

Using an API Gateway service integration instead of a Lambda means you aren’t deploying any extra code. It’s still serverless, so you aren’t paying anything between invocations. Once you understand service integrations, this solution is just as simple, if not simpler, than the Lambda option.

Per request, API Gateway REST APIs are more expensive than Lambda functions, but we’re talking fractions of a cent per month here. Speaking of pricing, note that you’re not charged for requests that fail authorization.

Example code

In both the Lambda and API Gateway solutions, you may want to do a little more before calling them production worthy. For example, error handling, logging, alarms, tuning the EventBridge retry policy, etc.

I’ve created a GitHub repository with an example CloudFormation template for each of the two solutions. The templates both create an example function with an SQS event source mapping that gets enabled at 01:00 UTC and disabled at 06:00 UTC. lambda-option-cf.yml implements the Lambda solution, and apigateway-option-cf.yml implements the API Gateway one.