HAProxy 作为 AWS API Gateway 的反向代理

HAProxy 作为 AWS API Gateway 的反向代理

正如标题所示,我有一个 AWS API 网关端点,我想将其放在 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

当我访问/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

答案1

如果您不使用 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)

你必须使用str()字符串样本获取这里,因为sni服务器关键字需要一个示例获取表达式(例如,对于您想要使用传入请求的 SNI 的情况)。

论坛上的问题实际上与 SNI 无关——配置的这一部分是正确的。问题在于他们未能执行您已经正确执行的操作——http-request set-header host ...以便 CloudFront 看到正确的Host:标头。


还要注意论坛上的建议,认为这是一个“非常糟糕的想法”,这似乎明显是错误的。


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

答案2

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)

对于未来的用户:您可能希望删除该:443,至少从 1.8 版本开始,ssl 是隐含的,如果您在定义该端口的情况下使用关键字 SSL 和/或 SNI,您将收到可能导致您重新编译的错误消息。

我有:

ssl 的未知关键字sni 也是一样,我直到重新阅读才明白为什么:https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.2接近一点了。

错误消息确实会让您相信 haproxy 未使用 SSL 支持进行编译,但如果是,haproxy -vv 会向您显示。

公平地说,如果您没有使用 USE_OPENSSL=1 进行编译或者有一个非标准发行版,请使用 SSL_INC=/usr/include/openssl/(替换路径)SSL_LIB=/usr/lib64/openssl(替换路径)

如果 haproxy -vv 显示未构建 ssl。

相关内容