前言
在 API Gateway REST API 中我們可以配置 Resource policy 來實現對特定客戶端 IP 地址的限制. 然而 HTTP API 并不提供這個功能, 不過我們可以用 Lambda 搓一個 Authorizer 實現等效的功能.
創建 Lambda authorizer
import json
import os
import ipaddressdef lambda_handler(event, context):# Get the client's source IP address# Make sure the HTTP is using version 2.0 payload formatclient_ip = event.get('requestContext', {}).get('http', {}).get('sourceIp')# Envinronment variable ALLOWED_CIDR seperate CIDRs by comma, example:# 1.1.1.0/24,1.1.2.0/24allowed_cidr_str = os.environ.get('ALLOWED_CIDR')allowed_cidr = [cidr.strip() for cidr in allowed_cidr_str.split(',')]is_authorized = Falseif client_ip:ip = ipaddress.ip_address(client_ip)for cidr_str in allowed_cidr:cidr = ipaddress.ip_network(cidr_str, strict=False)if ip in cidr:is_authorized = Trueprint(f'{ip} in {cidr} is {is_authorized}')breakelse:print(f'{ip} in {cidr} is {is_authorized}') return {"isAuthorized": is_authorized}
代碼很簡單, 不再贅述. 這里主要需要注意:
- HTTP API Authorizer Payload format version 需要指定為
2.0
, 否則獲取客戶端 IP 的路徑不一樣. - 保存代碼后需要額外創建一個環境變量
ALLOWED_CIDR
用來定義允許的客戶端 CIDR 格式地址, 多個中間用,
分隔.
配置 HTTP API
這里就用之前在文章 https://blog.csdn.net/lpwmm/article/details/149313858 中創建好的 HTTP API 作為例子.
- 創建 Authorizer
注意事項- Payload format version 選擇
2.0
- 刪除 Identity sources 因為之前創建的這個 HTTP API 是轉發請求給后面的 Flask Web 應用, 并不是單純的 API 調用, 所以客戶端會是瀏覽器匿名訪問, 請求的 Headers 中當然也不會包含 Authorization 這種信息. 如果不刪除的話 API Gateway 會直接拒絕請求, 后面的 Lambda authorizer 也不會被調用
- 也是因為沒有 Identity sources, 所以 Authorizer caching 不能開啟.
- Payload format version 選擇
- 將 Authorizer 附加到資源定義
注意, 不同的 Resource 需要分別附加 Authorizer
結尾
因為 HTTP API 配置了 Auto deploy, 因此上面的配置修改會立即生效, 不過也需要等個幾秒鐘的時間, 再使用瀏覽器訪問 HTTP API Stage URL 進行測試.
對于沒有在允許列表中的客戶端 IP 地址訪問時瀏覽器會返回:
{"message": "Forbidden"
}
后續只需要維護 Lambda 環境變量 ALLOWED_CIDR
內容就可以方便的管理允許訪問 HTTP API 的客戶端 IP.