Using Meraki’s WebHooks with Lambda

By Chaim Sanders

If you follow Meraki’s constant barrage of emails, you’ll know that they’ve added support for webhooks. Upon hearing that, you likely took a huge sigh of relief as the Meraki team took a small step towards modernizing their (quickly) aging product. If you were like me, you thought that this would allow you to quickly run through specific events and trigger activities based on their content. This it turns out, to only be partially true. Anything that was accessible via the ‘Network-wide’ -> ‘Alerts’ pane now can be sent to a webhook as well as an email. This is a great start, but will still limit you to syslog for the rest of the event information you really want.

So in spite of this slightly underwhelming beginning, let’s assume you wanted to get started processing these messages and making github tickets, or sending them to elk, or really whatever.

Well the process is fairly straightforward. Today we’ll setup Meraki+Lambda+API Gateway to fetch some grab some Meraki Webhooks.

First thing you’ll need to do is setup a Lambda function. If you’ve never done this it is dead simple. First login to your AWS console and navigate to Lambda.

Within Lambda you’ll want to create a function by clicking the big orange ‘Create function’ button.

From here we’re going to have to fill in a few options. We’ll select ‘Author from scratch’ and give our function a name. For my part I’ll choose ‘meraki-chaim-python3’ as the function name and choose Python 3.7. This is also where you can set IAM permissions for this function. Of course the standard security disclaimers apply as we’re permissioning.

Now that your function has been created you’ll have some stub code in the ‘lambda_handler’ function. We can modify this function slightly to handle what Meraki is gonna send us. Generally Meraki’s requests will be JSON encoded in a POST body. Lambda HTTP data via the event dictionary parameter passed into the lambda_handler function. Generally, we’ll be interested in the ‘Body’ key. It will look something like this:

‘body’: ‘{“alertData”:{},”alertId”:”0″,”alertType”:”Settings changed”,”occurredAt”:”2019-04-22T02:06:36.051418Z”,”organizationId”:”750799″,”organizationName”:”Personal”,”organizationUrl”:”https://n168.meraki.com/o/HnCxSd/manage/organization/overview”,”networkId”:”N_657525545596110375″,”networkName”:”Home Network”,”networkUrl”:”https://n168.meraki.com/Home-Network/n/-bwtecOc/manage/nodes/wired_status”,”sentAt”:”2019-04-22T02:06:36.089035Z”,”version”:”0.1″,”sharedSecret”:””}’, ‘isBase64Encoded’: False}

I’ll note that (for maybe security reasons??) when using Meraki’s ‘Send test webhook’ button (we’ll see this in a couple seconds) the sharedSecret parameter will never be populated, but in practice it will be sent. From a security perspective you’ll probably want to store this in AWS Secrets Manager (or equivalent).

With this in mind we should modify our Python Lambda function to something similar to the following:

Note: anything that is printed to stdout will appear in Cloudwatch, this is useful for debugging

import json

def lambda_handler(event, context):
    failure = { 'statusCode' : 403, "body": json.dumps("You have sent an invalid request") }
    success = { 'statusCode' : 200, "body" : json.dumps("Do some action here")}
    if "body" in list(event.keys()):
        body = json.loads(event['body'])
        if "sharedSecret" in list(body.keys()):
            if body["sharedSecret"] == "{MY_SHARED_SECRET}":
                print("Debug: We got a valid secret")
                return success
            else:
                print("Debug: Invalid secret provided")
                return failure
    else:
        print("Debug: There was no valid body in the HTTP request")
        return failure
    # Sanity Check
    return failure

Now that we have a Lambda function we’ll need a URL that will trigger it. This is where API Gateway comes in. This is a pretty common design pattern at this point, but in case it’s your first you’ll need to navigate to the ‘API Gateway’ service.

Here you’ll either be sheperded through the getting started wizard to make your first API, or you can click the blue ‘Create API’ button. Here we’ll make sure we’re selecting a REST API, making a ‘New API’ and that we name our API. In our case I named the API ‘Meraki Test’.

Once you select ‘Create API’ you’ll be taken to that API’s ‘Resouces’ page. You’ll want to click on the ‘Actions’ button and select ‘Create Method’

In the dropdown that appears, you’ll want to select ‘POST’ as Meraki only sends POST requests.

After you hit the checkmark you’ll be directed to a ‘Setup’ screen for this method. Here you can select the Lambda function we previously made. You’ll want to make sure to check the ‘Use Lambda Proxy Integration’ checkbox so that we get access to the body parameter from our Lambda function.

After you hit ‘Save’ you’ll next you’ll want to deploy the API. This is the part where you get the URL you’ll need to provide to Meraki in our next step. To do this selection the ‘Actions’ button and from the dropdown select ‘Deploy API’

It will ask you for a staging name, this is really up to you – I often go with ‘Production’. After you’re set, you can click ‘Deploy’.

You’ll be taken to the ‘Stages’ screen where you’ll see the URL to access your lambda function. You’ll want to copy this URL.

Our next and last step involves the Meraki. Log into your meraki console and navigate to ‘Network-wide’->’Alerts’. From here on the bottom of the page you’ll see a new ‘Webhooks’ section. Name your webhook, and provide the URL we got from API gateway. Next put the secret we specified in Lambda function in. You can click ‘Send test webhook’, in our example it will actually fail because we return a 403 when the secret is “”.

Note: You can temporarily change the lambda function to either look for an empty secret or return a 200 when there is an empty secret to verify this if you’d like. You can also just look in Cloudwatch logs to verify that the request was received, since all its looking for is a 200 status code.

On the top of the ‘Alerts’ screen you can specify the default recipients (or specify the recipients per alert type). Start by typing ‘Webhook’ and use select one of the prefilled answers.

Now that all of this is configured you’re lambda function will fire with the information provided by Meraki each time one of those events occurs.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s