Lambda and Github Webhooks

Posted: 2018-05-08 18:21:14

Related to https://developer.github.com/webhooks/ and pushing data to Lambda AWS.

I can check the token by just having this check in my handler.

const crypto = require('crypto');

exports.handler = (event, context, callback) => {
  let headers = event.headers;

  let body = event.body;

  if (typeof body === 'object') {
    body = JSON.stringify(event.body);
  }

  let github_event = headers['X-GitHub-Event'];

  if (
    github_event === undefined ||
    typeof github_event !== 'string' ||
    github_event.length < 1
  ) {
    callback(null, {
      statusCode: 400,
      body: 'Missing X-GitHub-Event'
    });
    return;
  }

  let github_signature = headers['X-Hub-Signature'];

  if (
    github_signature === undefined ||
    typeof github_signature !== 'string' ||
    !github_signature.match(/sha1=\S+/)
  ) {
    callback(null, {
      statusCode: 400,
      body: 'Missing X-Hub-Signature'
    });
  }

  let secret = process.env.SECRET;

  if (secret === undefined || secret.length < 1) {
    callback(null, {
      statusCode: 500,
      body: 'We are missing the secret in our server sorry'
    });
    return;
  }

  let signature = headers['X-Hub-Signature'];

  let computed_signature = crypto
    .createHmac('sha1', secret)
    .update(body)
    .digest('hex');

  if (`sha1=${computed_signature}` !== signature) {
    callback(null, {
      statusCode: 403,
      body: 'HMAC Output not Correct'
    });
    return;
  }

  //ready to process token
  callback(null, {
    statusCode: 204,
    body: 'OK'
  });
};

With the serverless library from AWS https://github.com/awslabs/serverless-application-model I can build a template to include this in the Resource

Resources:
  GithubSecurityWebhook:
    Type: AWS::Serverless::Function
    DependsOn:
      - Stream
    Properties:
      Runtime: nodejs8.10
      Description: >-
        This will verify that the incoming data is from Github and hashed with the key
        we are using for this environment
      Environment:
        Variables:
          SECRET: !Sub ${Secret}
          APP_ENV: !Sub ${AppEnv}
          APP_REGION: "eu-west-1"

then during the update command I can pass

SECRET=FOO

or put a .env file on the system and use the dotenv library