Секрет Github Webhooks с AWS API Gateway

Я пытаюсь заставить Github Webhook запустить AWS Lambda, который у меня есть. Лучший способ понять, как это сделать, — использовать AWS API Gateway, проблема в безопасности.

Github Webhooks отправит секрет только с вызовом POST.

Я не могу найти способ использовать AWS API Gateway для проверки этой подписи. Или где я могу добавить этот функционал.

Я предполагаю, что могу написать Авторизатор AWS Lambda. Но это много кода в разных местах, начиная видеть необходимость в serverless фреймворке.

Какая-нибудь более простая настройка в AWS, о которой я не знаю для этого?


person Kyle Calica-St    schedule 26.09.2019    source источник


Ответы (2)


Пришел сюда, потому что пытался интегрировать веб-хук Github с лямбдой AWS и столкнулся с той же проблемой, что и OP. На момент написания я считаю, что лучшим решением является включение кода проверки в основную лямбду, как предлагали другие.

В компьютерном блоге AWS за сентябрь 2017 года:

Функции Lambda расширенного авторизатора запросов получают объект события, аналогичный интеграции с прокси. Он содержит всю информацию о запросе, кроме тела.

Источник: Использование расширенных авторизаторов запросов в Amazon API Gateway (amazon.com)

Вы не можете выполнить HMAC в соответствии с рекомендациями Github, потому что лямбда-выражения авторизатора AWS не дают вам доступа к телу HTTP-запроса, который необходим для сравнения дайджестов.

Это позор, потому что HMAC кажется довольно стандартным способом защиты конечной точки, которая отвечает на веб-перехватчик. См., например, этот пост в блоге, Что можно и чего нельзя делать с веб-перехватчиками: что мы узнали после интеграции +100 API (restful.io). Twitter и Stripe делают нечто подобное:

Чтобы описанный выше подход работал, если вы используете шлюз API, вам необходимо убедиться, что заголовок, содержащий хеш-подпись, пересылается как часть аргумента event в лямбда-выражение. Для этого следуйте этим инструкциям: Как мне передавать пользовательские заголовки через Amazon API Gateway в функцию AWS Lambda, используя пользовательскую интеграцию Lambda для дальнейшей обработки? (amazon.com)

person Oscar Barlow    schedule 08.11.2019
comment
На самом деле, я только что был на конференции, разговаривал с менеджером по продукту AWS Authorizer, и он был разочарован, узнав, что сам не может этого сделать именно из-за того, что вы здесь сказали (нет доступа к полезной нагрузке для хеширования), его ответ был сделать это в лямбде. Немного грустно, что вы не можете использовать их систему в соответствии с их лучшими практиками. Это был потрясающий ответ, и вы заслужили этот ответ! Спасибо, надеюсь, мы поможем многим другим, пока AWS не придумает лучший способ справиться с этим. - person Kyle Calica-St; 08.11.2019

Я не смог найти способ сделать это с помощью API Gateway. Я проверил в LAMBDA, используя (Python).

Общий обзор: вычислите подпись HMAC с помощью GITHUB_SECRET, затем сравните с подписью, переданной из Github.

Вы можете, очевидно, упростить, намеренно многословно для удобства чтения. Возможно, есть лучшие способы, но я не нашел.

Убедитесь, что ваш Webhook настроен для application/json. Надеюсь, это поможет кому-то другому.

import logging
import json
import hmac
import hashlib
import re
from urllib.parse import unquote

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

GITHUB_SECRET = 'SECRET FROM GITHUB CONSOLE'


def lambda_handler(event, context):
    logger.info("Lambda execution starting up...")

    incoming_signature = re.sub(r'^sha1=', '', event['headers']['X-Hub-Signature'])
    incoming_payload = unquote(re.sub(r'^payload=', '', event['body']))
    calculated_signature = calculate_signature(GITHUB_SECRET, incoming_payload.encode('utf-8'))

    if incoming_signature != calculated_signature:
        logger.error('Unauthorized attempt')
        return {
            'statusCode': 403,
            'body': json.dumps('Forbidden')
        }

    logger.info('Request successfully authorized')

    # do stuff in Lambda

    return {
        'statusCode': 200,
        'body': json.dumps(f'Work in progress')
    }


def calculate_signature(github_signature, githhub_payload):
    signature_bytes = bytes(github_signature, 'utf-8')
    digest = hmac.new(key=signature_bytes, msg=githhub_payload, digestmod=hashlib.sha1)
    signature = digest.hexdigest()
    return signature
person Justin Daines    schedule 30.09.2019
comment
спасибо, что поделились этим! да, на самом деле у меня есть то, что вы написали для проверки, в отдельной лямбде, но мне нужно, чтобы она возвращала политику и идентификатор принципала, я очень запутался в том, какую политику AWS я должен отправлять? Политика, разрешающая шлюз API или фактическую лямбду, которую я хочу использовать в фоновом режиме. - person Kyle Calica-St; 30.09.2019
comment
Это было то, над чем я работал дальше. Вышеприведенное предполагает, что авторизация будет выполнена встроенной, а затем запущен лямбда-код (все в пределах одной лямбда-выражения). Я поделюсь, когда у меня будет время, чтобы заставить лямбда вернуть политику IAM и идентификатор принципала. - person Justin Daines; 01.10.2019
comment
здесь возникает ошибка :( [ERROR] TypeError: ожидаемая строка или байтовый объект Traceback (последний последний вызов): файл /var/task/lambda_function.py, строка 21, в lambda_handler incoming_payload = unquote(re.sub(r '^payload=', '', event['body-json'])) Файл /var/lang/lib/python3.8/re.py, строка 208, в подпункте return _compile(шаблон, флаги).sub( repl, строка, количество) - person raitisd; 20.11.2019