HAProxy 作为 AWS API Gateway 的反向代理

Rud*_*Lee 2 haproxy amazon-web-services amazon-api-gateway

正如标题所暗示的,我有一个 AWS API Gateway 端点,我想将它放在 HAProxy 后面。

这是我当前的 HAProxy 配置

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

listen  http
        bind 127.0.0.1:8080
        maxconn     18000

        acl api_gateway path_beg /api-gateway
        use_backend api-gateway-backend if api-gateway

backend api-gateway-backend
        http-request set-header Host xxxxx.execute-api.ap-southeast-2.amazonaws.com
        server api-gateway xxxxx.execute-api.ap-southeast-2.amazonaws.com:443
Run Code Online (Sandbox Code Playgroud)

当我点击/api-gatewayHAProxy 上的端点时,我得到400 Bad Request. 见下文:

api网关400

我试图更改后端以使用它,server api-gateway xxxxx.execute-api.ap-southeast-2.amazonaws.com:443 ssl verify none但我得到了503 Service Unavailable

我认为这可能与我需要在 HAProxy 上启用的 SSL SNI 配置有关,请参阅此论坛帖子https://forums.aws.amazon.com/thread.jspa?threadID=240197

Mic*_*bot 8

如果您不使用 HTTPS,则 CloudFront 将返回400 Bad Request¹ 错误,因为 API Gateway 不支持 HTTP。

添加ssl verify none到后端启用HTTPS,CloudFront只是关闭连接,导致HAProxy将断开连接时会话状态记录为SC--并返回本地503 Service Unavailable错误。

解决方案确实是发送服务器名称标识 (SNI)。否则,CloudFront 的前端不知道为您提供哪个 SSL 证书——通用*.cloudfront.net通配符证书,或者*.execute-api.ap-southeast-2.amazonaws.com可能是数十万种其他可能性中的一种。这就是 SNI 在这种情况下所做的——它告诉服务器您要连接的名称。

解决方案——这是一行,为清楚起见显示为多行:

server api-gateway 
       xxxxx.execute-api.ap-southeast-2.amazonaws.com:443
       ssl
       verify none
       sni str(xxxxx.execute-api.ap-southeast-2.amazonaws.com)
Run Code Online (Sandbox Code Playgroud)

您必须在此处使用str()字符串 sample fetch,因为sniserver 关键字需要一个 sample fetch 表达式(例如,对于您想要使用传入请求的 SNI 的情况)。

论坛上问题中的问题实际上与 SNI 无关——那部分配置是正确的。问题是他们没有做你已经正确做的事情——http-request set-header host ...所以 CloudFront 看到了正确的Host:标头。


另请注意论坛上的建议,即这是一个“非常糟糕的主意”,这似乎显然是错误的。


¹ 400 CloudFront - 在某些情况下 - 在正文中返回“错误请求”,但实际的 HTTP 状态代码403对应于Forbidden.