이 자습서에서는 Lambda 함수 URL을 생성하여 웹후크 엔드포인트를 구현합니다. 웹후크는 HTTP를 사용하여 애플리케이션 간에 데이터를 자동으로 전송하는 경량형 이벤트 기반 통신입니다. 웹후크를 사용하면 다른 시스템에서 발생하는 이벤트(예: 새 고객의 웹 사이트 가입, 결제 처리, 파일 업로드)에 대한 즉각적인 업데이트를 받을 수 있습니다.
Lambda를 활용하면 Lambda 함수 URL 또는 API Gateway를 사용하여 웹후크를 구현할 수 있습니다. 함수 URL은 고급 권한 부여 또는 요청 검증 같은 기능이 필요하지 않은 간단한 웹후크에 적합합니다.
작은 정보
특정한 사용 사례에 가장 적합한 방법을 잘 모르는 경우 HTTP 요청을 사용하여 Lambda 함수를 간접 호출하는 메서드 선택 섹션을 참조하세요.
사전 조건
이 자습서를 완료하려면 로컬 시스템에 Python(버전 3.8 이상) 또는 Node.js(버전 18 이상)가 설치되어 있어야 합니다.
HTTP 요청을 사용하여 엔드포인트를 테스트할 수 있도록 자습서에서는 curl
Lambda 함수 생성
HTTP 요청이 웹후크 엔드포인트로 전송될 때 실행되는 Lambda 함수를 우선 생성합니다. 이 예제에서 전송 애플리케이션은 결제가 제출될 때마다 업데이트를 전송하며 결제 성공 여부를 HTTP 요청 본문에 표시합니다. Lambda 함수는 요청을 구문 분석하고 결제 상태에 따라 조치를 취합니다. 이 예제에서는 코드가 결제의 주문 ID만 인쇄하지만, 실제 애플리케이션에서는 주문을 데이터베이스에 추가하거나 알림을 전송할 수 있습니다.
또한 이 함수는 웹후크, 해시 기반 메시지 인증(HMAC)에 사용되는 가장 일반적인 인증 방법을 구현합니다. 이 방법을 사용하면 발신 및 수신 애플리케이션 두 가지 모두가 보안 키를 공유합니다. 전송 애플리케이션은 해싱 알고리즘을 사용하여 메시지 콘텐츠와 함께 이 키를 사용하여 고유한 서명을 생성하며, 웹후크 요청 내에 서명을 HTTP 헤더로 포함합니다. 그런 다음 수신 애플리케이션이 이 단계를 반복하여 보안 키를 사용해 서명을 생성하며, 결과 값을 요청 헤더에 전송된 서명과 비교합니다. 결과가 일치하면 요청이 정상적인 것으로 간주됩니다.
Python 또는 Node.js 런타임과 함께 Lambda 콘솔을 사용하여 함수를 생성합니다.
Lambda 함수 생성
Lambda 콘솔의 함수 페이지
를 엽니다. -
다음을 수행하여 기본 'Hello world' 함수를 생성합니다.
-
함수 생성을 선택합니다.
-
새로 작성을 선택합니다.
-
[함수 이름(Function name)]에
myLambdaWebhook
을 입력합니다. -
런타임에서 Python 3.13을 선택합니다.
-
함수 생성을 선택합니다.
-
-
코드 소스 창에서 다음을 복사하고 붙여 넣어 기존 코드를 바꿉니다.
import json import hmac import hashlib import os def lambda_handler(event, context): # Get the webhook secret from environment variables webhook_secret = os.environ['WEBHOOK_SECRET'] # Verify the webhook signature if not verify_signature(event, webhook_secret): return { 'statusCode': 401, 'body': json.dumps({'error': 'Invalid signature'}) } try: # Parse the webhook payload payload = json.loads(event['body']) # Handle different event types event_type = payload.get('type') if event_type == 'payment.success': # Handle successful payment order_id = payload.get('orderId') print(f"Processing successful payment for order {order_id}") # Add your business logic here # For example, update database, send notifications, etc. elif event_type == 'payment.failed': # Handle failed payment order_id = payload.get('orderId') print(f"Processing failed payment for order {order_id}") # Add your business logic here else: print(f"Received unhandled event type: {event_type}") # Return success response return { 'statusCode': 200, 'body': json.dumps({'received': True}) } except json.JSONDecodeError: return { 'statusCode': 400, 'body': json.dumps({'error': 'Invalid JSON payload'}) } except Exception as e: print(f"Error processing webhook: {e}") return { 'statusCode': 500, 'body': json.dumps({'error': 'Internal server error'}) } def verify_signature(event, webhook_secret): """ Verify the webhook signature using HMAC """ try: # Get the signature from headers signature = event['headers'].get('x-webhook-signature') if not signature: print("Error: Missing webhook signature in headers") return False # Get the raw body (return an empty string if the body key doesn't exist) body = event.get('body', '') # Create HMAC using the secret key expected_signature = hmac.new( webhook_secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256 ).hexdigest() # Compare the expected signature with the received signature to authenticate the message is_valid = hmac.compare_digest(signature, expected_signature) if not is_valid: print(f"Error: Invalid signature. Received: {signature}, Expected: {expected_signature}") return False return True except Exception as e: print(f"Error verifying signature: {e}") return False
-
배포 섹션에서 배포를 선택하여 함수의 코드를 업데이트하세요.
보안 암호 키 생성
Lambda 함수는 웹후크 요청을 인증할 수 있도록 호출 애플리케이션과 공유하는 보안 키를 사용합니다. 이 예제에서는 키가 환경 변수에 저장됩니다. 프로덕션 애플리케이션에서는 보다 안전한 옵션으로 AWS Secrets Manager를 사용하는 것이 좋습니다. Secrets Manager를 사용하여 보안 암호 키를 저장하는 방법에 대한 자세한 내용은 AWS Secrets Manager 사용 설명서의 Create an AWS Secrets Manager secret 및 Get secrets from AWS Secrets Manager 섹션을 참조하세요.
웹후크 보안 암호 키 생성 및 저장
-
암호화 보안 난수 생성기를 사용하여 긴 무작위 문자열을 생성합니다. Python 또는 Node.js에서 다음 코드 조각을 사용하여 32자 보안 암호를 생성 및 인쇄하거나, 원하는 방법을 사용할 수 있습니다.
예 보안 암호를 생성하는 코드
import secrets webhook_secret = secrets.token_urlsafe(32) print(webhook_secret)
-
다음을 수행하여 생성된 문자열을 함수의 환경 변수로 저장합니다.
-
함수에 대한 구성 페이지에서 환경 변수를 선택합니다.
-
편집을 선택합니다.
-
Add environment variable(환경 변수 추가)을 선택합니다.
-
키에서
WEBHOOK_SECRET
을 입력한 다음, 값에서 이전 단계에서 생성한 보안 암호를 입력합니다. -
Save(저장)를 선택합니다.
-
자습서의 뒷부분에서 이 보안 암호를 다시 사용하여 함수를 테스트해야 하므로 이 보안 암호를 지금 메모해 두세요.
함수 URL 엔드포인트 생성
Lambda 함수 URL을 사용하여 웹후크의 엔드포인트를 생성합니다. 인증 유형 NONE
을 사용하여 퍼블릭 액세스 권한이 있는 엔드포인트를 생성하면 URL이 있는 누구나 함수를 간접적으로 호출할 수 있습니다. 함수 URL에 대한 액세스 권한 제어를 자세히 알아보려면 Lambda 함수 URL에 대한 액세스 제어 섹션을 참조하세요. 웹후크에 대한 고급 인증 옵션이 필요한 경우 API Gateway를 사용하는 것이 좋습니다.
함수 URL 엔드포인트 생성
-
함수의 구성 탭에서 함수 URL을 선택합니다.
-
함수 URL 생성(Create function URL)을 선택합니다.
-
인증 유형에서 없음을 선택합니다.
-
Save(저장)를 선택합니다.
방금 생성한 함수 URL의 엔드포인트가 함수 URL 창에 표시됩니다. 자습서의 뒷부분에서 사용할 엔드포인트를 복사합니다.
콘솔에서 함수 테스트
HTTP 요청을 사용하여 URL 엔드포인트를 사용하여 함수를 간접적으로 호출하려면 우선 콘솔에서 이를 테스트하여 코드가 예상대로 작동하는지 확인합니다.
콘솔에서 함수를 확인하려면 먼저 다음과 같은 테스트 JSON 페이로드를 통해 자습서 앞부분에서 생성한 보안 암호를 사용하여 웹후크 서명을 계산합니다.
{
"type": "payment.success",
"orderId": "1234",
"amount": "99.99"
}
다음과 같은 Python 또는 Node.js 코드 예제 중 하나를 사용해 고유한 보안 암호를 이용하여 웹후크 서명을 계산합니다.
웹후크 서명 계산
-
다음 코드를
calculate_signature.py
라는 이름의 파일에 저장합니다. 코드의 웹후크 보안 암호를 원하는 고유한 값으로 바꿉니다.import secrets import hmac import json import hashlib webhook_secret = "
arlbSDCP86n_1H90s0fL_Qb2NAHBIBQOyGI0X4Zay4M
" body = json.dumps({"type": "payment.success", "orderId": "1234", "amount": "99.99"}) signature = hmac.new( webhook_secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256 ).hexdigest() print(signature) -
코드를 저장한 디렉터리에서 다음 명령을 실행하여 서명을 계산합니다. 코드가 출력하는 서명을 복사합니다.
python calculate_signature.py
이제 콘솔에서 테스트 HTTP 요청을 사용하여 함수 코드를 테스트할 수 있습니다.
콘솔에서 함수 테스트
-
함수의 코드 탭을 선택합니다.
-
테스트 이벤트 섹션에서 새로운 테스트 이벤트 생성을 선택합니다.
-
Event Name(이벤트 이름)에
myEvent
를 입력합니다. -
다음을 복사하여 이벤트 JSON 창에 붙여 넣어 기존 JSON을 바꿉니다. 웹후크 서명을 이전 단계에서 계산한 값으로 바꿉니다.
{ "headers": { "Content-Type": "application/json", "x-webhook-signature": "
2d672e7a0423fab740fbc040e801d1241f2df32d2ffd8989617a599486553e2a
" }, "body": "{\"type\": \"payment.success\", \"orderId\": \"1234\", \"amount\": \"99.99\"}" } -
Save(저장)를 선택합니다.
-
간접 호출를 선택합니다.
다음과 유사한 출력 화면이 표시되어야 합니다.
Status: Succeeded Test Event Name: myEvent Response: { "statusCode": 200, "body": "{\"received\": true}" } Function Logs: START RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6 Version: $LATEST Processing successful payment for order 1234 END RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6 REPORT RequestId: 50cc0788-d70e-453a-9a22-ceaa210e8ac6 Duration: 1.55 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 36 MB Init Duration: 136.32 ms
HTTP 요청을 사용하여 함수 테스트
curl 명령줄 도구를 사용하여 웹후크 엔드포인트를 테스트합니다.
HTTP 요청을 사용하여 함수 테스트
-
터미널 또는 쉘 프로그램에서 다음 curl 명령을 실행합니다. URL을 고유한 함수 URL 엔드포인트의 값으로 바꾸고, 웹후크 서명을 고유한 보안 키를 사용하여 계산한 서명으로 바꿉니다.
curl -X POST
https://ryqgmbx5xjzxahif6frvzikpre0bpvpf.lambda-url.us-west-2.on.aws/
\ -H "Content-Type: application/json" \ -H "x-webhook-signature:d5f52b76ffba65ff60ea73da67bdf1fc5825d4db56b5d3ffa0b64b7cb85ef48b
" \ -d '{"type": "payment.success", "orderId": "1234", "amount": "99.99"}'다음 결과가 표시됩니다.
{"received": true}
-
함수의 CloudWatch 로그를 검사해 다음을 수행하여 페이로드를 올바르게 구문 분석했는지 확인합니다.
-
Amazon CloudWatch 콘솔에서 로그 그룹
페이지를 엽니다. -
함수의 로그 그룹(
/aws/lambda/myLambdaWebhook
)을 선택합니다. -
최신 로그 스트림을 선택합니다.
함수의 로그에서 다음과 유사한 출력 화면이 표시되어야 합니다.
Processing successful payment for order 1234
-
-
다음 curl 명령을 실행하여 코드가 잘못된 서명을 감지하는지 확인합니다. URL을 고유한 함수 URL 엔드포인트로 바꿉니다.
curl -X POST
https://ryqgmbx5xjzxahif6frvzikpre0bpvpf.lambda-url.us-west-2.on.aws/
\ -H "Content-Type: application/json" \ -H "x-webhook-signature: abcdefg" \ -d '{"type": "payment.success", "orderId": "1234", "amount": "99.99"}'다음 결과가 표시됩니다.
{"error": "Invalid signature"}
리소스 정리
이 자습서 용도로 생성한 리소스를 보관하고 싶지 않다면 지금 삭제할 수 있습니다. 더 이상 사용하지 않는 AWS 리소스를 삭제하면 AWS 계정에 불필요한 요금이 발생하는 것을 방지할 수 있습니다.
Lambda 함수를 삭제하려면
-
Lambda 콘솔의 함수 페이지
를 엽니다. -
생성한 함수를 선택합니다.
-
작업, 삭제를 선택합니다.
-
텍스트 입력 필드에
confirm
를 입력하고 Delete(삭제)를 선택합니다.
콘솔에서 Lambda 함수를 생성하면 Lambda는 함수에 대한 실행 역할도 생성합니다.
집행 역할 삭제
-
IAM 콘솔에서 역할 페이지
를 엽니다. -
Lambda가 생성한 실행 역할을 선택합니다. 역할의 이름 형식은
myLambdaWebhook-role-<random string>
입니다. -
Delete(삭제)를 선택합니다.
-
텍스트 입력 필드에 역할의 이름을 입력하고 Delete(삭제)를 선택합니다.