采用 Lambda@Edge + DynamoDB 架构实现。
Lambda@Edge,每次访问都会调用Lambda函数,判断是否符合设定的规则,是则进行计数,否则阻断访问。
客户端可能会访问任意一个 CloudFront 的 POP 点,所以需要在多个物理位置维护一份访问数据并且保证同步。这里利用了Amazon DynamoDB 的全局表,可以在毫秒级实现全球数据同步,保证Lambda@Edge的数据全局一致。
DynamoDB维护两张全局表来作为数据存储,一张供 Lambda Edge 访问,存储必要的访问数据,一张存储被封禁的 IP 信息,更新WAF Rule 封禁违规IP。
git clone https://github.com/awslabs/aws-cloudfront-extensions.git
cd ./aws-cloudfront-extensions/function/js/limit-request-rate/cdk/
npm install
cdk bootstrap
# cdk deploy --parameters cfDistId=<cloudfront 分配ID,类似:EP1GUKEQP43MF> --parameters rateLimit=10 --parameters urlRateLimit=5 --parameters urlList='/login,/info' RateLimitCfStack
cdk deploy --parameters cfDistId=EU7NDIEB0KPVH --parameters rateLimit=10 --parameters urlRateLimit=5 --parameters urlList='/login,/info' RateLimitCfStack
注意,需要更换cfDistId为你创建的cloudfront 分配Id
参数说明:
- cfDistId: Cloudfront分配Id
- rateLimit: 全局每分钟限速次数
- urlList:需要单独设置限速规则的URL
- urlRateLimit:URL的每分钟限速次数
在cloudfront分配,打开行为标签,并编辑。 确认在最下方的function associate关联Lambda@Edge函数。
至此,配置完成。
export JUICESHOP_URL=<Your Juice Shop URL>
export JUICESHOP_URL=https://djbryp4jxosx1.cloudfront.net
for ((i=0; i<12; i++)); do echo $i; curl -I "${JUICESHOP_URL}";sleep 1;done
curl -I "${JUICESHOP_URL}"
请求结果
WSParticipantRole:~ $ curl -I "${JUICESHOP_URL}"
HTTP/1.1 403 Forbidden
Server: CloudFront
Date: Fri, 22 Dec 2023 06:09:11 GMT
Content-Type: text/html
Content-Length: 919
Connection: keep-alive
X-Cache: Error from cloudfront
Via: 1.1 6306947fb6ab60dc617ca2e025941652.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: IAD50-C2
X-Amz-Cf-Id: AJN-UrMIQ9_YYtKWnbeDmWPOakVyZKY9lWgon-MnVIYkWbqXQXMRLw==
状态码为403,请求是被WAF防火墙所屏蔽。status code为429时,是被Lambda@Edge所屏蔽,是即时的立即屏蔽。 后续经过waf ipset的更新周期,此IP会在waf的黑名单列表内保持4小时。
WSParticipantRole:~ $ curl ipinfo.io
{
"ip": "3.226.47.2",
"hostname": "ec2-3-226-47-2.compute-1.amazonaws.com",
"city": "Ashburn",
"region": "Virginia",
"country": "US",
"loc": "39.0437,-77.4875",
"org": "AS14618 Amazon.com, Inc.",
"postal": "20147",
"timezone": "America/New_York",
"readme": "https://ipinfo.io/missingauth"
}
WSParticipantRole:~ $
WAF内黑名单Ipset: BlockIPSET_0
请求命令:
export JUICESHOP_URL=<Your Juice Shop URL>
export JUICESHOP_URL=https://djbryp4jxosx1.cloudfront.net
for ((i=0; i<6; i++)); do echo $i; curl -I "${JUICESHOP_URL}/login";sleep 1;done
返回结果:
可以看出,对关键URL的rate限制每分钟5次,也已经生效。