正如标题所示,我有一个 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-gateway
HAProxy 上的端点时,我得到了400 Bad Request
。如下所示:
我尝试改变后端来使用这个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。