Some thoughts on using AWS Lambda with Slack Webhooks

extremely accurate visualization of why this might be useful

Using Lambda as the endpoint for your Slack webhooks is a real simple task, but there’s some little things that can kind of make it a pain for a privacy or security conscious use case (or perhaps if you just don’t want, or need, to learn the ins-and-outs of the AWS suite of products, and just need it to work, and work quickly; and an anti-abuse check like the following may suffice). This is not the most secure, or most production-worthy approach, but it works if you have common tasks that just need a baseline level of validation.

The main thing I ran into was how to authenticate; the API Gateway and Lambda can integrate with things like IAM, and other authentication methods, however, on the Slack-side of things, actually using it is another story. There’s an old trick, but probably the easiest, to locking this down a little bit from the program level.

When you create a webhook, you’re given a token, and that token is passed with the POST request (along with other relevant data) to the AWS API Gateway for an outgoing webhook. The simplest way is just to (in this example, clumsily) match that token:

So, you’ll see a couple of things happening here:

  1. from the event object, we’re just grabbing the body of that object, and checking it for a response_url , channel_name, and token parameter in the POST request. This bit only requires that the API Gateway be configured to connect to a Lambda task (where you’ll get the URL for your webhook to POST to): https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started.html#getting-started-new-post

https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started.html#getting-started-new-post

  1. The channel_name and token are compared to environmental variables you’ll set in Lambda:

This will allow you to a) ensure that the request came from your Slack team, and b) that it was initiated from an acceptable channel.

You can, with this approach for example, lock it down further by setting a group users (Lambda can integrate with RDS, for example, where you might store a list of users, etc. or just compare, again, to an environmental variable) that can be matched to the user object, etc.

3. After checking that all of the parameters you wish to check were passed, and match the environmental variables set when you created the job, it proceeds to the actual meat of your function.

There are way better ways of implementing this sort of check, but for something quick and dirty (Lambda has much more sophisticated integration with the API gateway that can help you out if there’s anything else you need to be doing) this is effective if you’re just looking to validate before kicking off a job that isn’t terribly dynamic.

Some examples of relatively static jobs, but could be kicked-off on demand using this method could be things like triggering automated calls (via services like Twilio) to your org’s on-call engineer (drawing their attention to Slack, rather than an issue defined in monitoring), or generating backups of a known set of data (to, again, a Lambda-friendly integratabtle service like S3), or even just pulling data down from a third-party service, and sending to the requested user with the response_url as seen in the example above, and define a function like this to handle it:

It’s neither terribly complicated, nor sophisticated, but it’ll get the job done effectively in adding some peace of mind to low-priority, but somewhat regular jobs that make need to get run on-demand through Slack.