前言
在 API Gateway REST API 中我们可以配置 Resource policy 来实现对特定客户端 IP 地址的限制. 然而 HTTP API 并不提供这个功能, 不过我们可以用 Lambda 搓一个 Authorizer 实现等效的功能.
创建 Lambda authorizer
import json
import os
import ipaddress
def lambda_handler(event, context):
# Get the client's source IP address
# Make sure the HTTP is using version 2.0 payload format
client_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/24
allowed_cidr_str = os.environ.get('ALLOWED_CIDR')
allowed_cidr = [cidr.strip() for cidr in allowed_cidr_str.split(',')]
is_authorized = False
if 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 = True
print(f'{ip} in {cidr} is {is_authorized}')
break
else:
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.