如何在 TCP 模式下使用 haproxy 传递自定义 SNI
How to pass the custom SNI with haproxy in TCP mode
我有一个 public ssl 端点 something.example.com,它需要使用 SNI 扩展。不能直接访问,所以想通过haproxy(设置在可以上网的服务器)
这不起作用:
openssl s_client -connect something.example.com:443
这工作正常:
openssl s_client -connect something.example.com:443 -servername something.example.com
我的 haproxy 配置(版本 1.8.24):
frontend my_frontend
bind *:443
mode tcp
log global
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend my_backend
backend my_backend
mode tcp
server my-server something.example.com:443 sni str(something.example.com)
登录haproxy服务器后,我可以做:
curl -v https://something.example.com/
可以看到SSL连接已经建立
但是在做 curl -v https://127.0.0.1/
时我面对:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL 连接到 127.0.0.1:443
怎么了?我已经尝试终止 ssl,替换主机 header 但没有成功。我的理解是 SNI 本身与加密请求是分开的,并且通过上述配置我应该能够连接到后端。
PS。后台服务器不是我管理的。
编辑:如评论中所述,不可能在 TCP 模式配置中传递自定义 SNI。可以为 http 模式完成以下操作,使用 TLS 终止,以下工作正常:
frontend log_frontend
bind *:443 ssl crt /etc/pki/tls/private/mycert.pem
mode http
log global
option httplog
option forwardfor
use_backend log_backend
backend log_backend
mode http
server my-server something.example.com:443 ssl verify none sni str(something.example.com)
My understanding is that SNI itself is separated from ciphered request ...
SNI 是 SSL/TLS 握手的一部分,特别是客户端在握手开始时发送的 ClientHello。 不可能替换TLS握手的任何部分,包括SNI。相反,需要终止 TLS(这意味着需要适当的证书等),然后必须使用预期的 SNI 集创建新的 TLS 会话。
好吧,我假设您在调用 curl -v https://127.0.0.1/
.
中也会收到类似“证书与主机名不匹配”的信息
我强烈建议告诉 curl 如何解决 something.example.com
curl -v --resolve something.example.com:443:127.0.0.1 https://something.example.com/
这篇博客有更详细的解释post
https://daniel.haxx.se/blog/2018/04/05/curl-another-host/
顺便说一句:我强烈建议更新到最新的 haproxy 2.4 LTS 版本
我有一个 public ssl 端点 something.example.com,它需要使用 SNI 扩展。不能直接访问,所以想通过haproxy(设置在可以上网的服务器)
这不起作用:
openssl s_client -connect something.example.com:443
这工作正常:
openssl s_client -connect something.example.com:443 -servername something.example.com
我的 haproxy 配置(版本 1.8.24):
frontend my_frontend
bind *:443
mode tcp
log global
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend my_backend
backend my_backend
mode tcp
server my-server something.example.com:443 sni str(something.example.com)
登录haproxy服务器后,我可以做:
curl -v https://something.example.com/
可以看到SSL连接已经建立
但是在做 curl -v https://127.0.0.1/
时我面对:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL 连接到 127.0.0.1:443
怎么了?我已经尝试终止 ssl,替换主机 header 但没有成功。我的理解是 SNI 本身与加密请求是分开的,并且通过上述配置我应该能够连接到后端。
PS。后台服务器不是我管理的。
编辑:如评论中所述,不可能在 TCP 模式配置中传递自定义 SNI。可以为 http 模式完成以下操作,使用 TLS 终止,以下工作正常:
frontend log_frontend
bind *:443 ssl crt /etc/pki/tls/private/mycert.pem
mode http
log global
option httplog
option forwardfor
use_backend log_backend
backend log_backend
mode http
server my-server something.example.com:443 ssl verify none sni str(something.example.com)
My understanding is that SNI itself is separated from ciphered request ...
SNI 是 SSL/TLS 握手的一部分,特别是客户端在握手开始时发送的 ClientHello。 不可能替换TLS握手的任何部分,包括SNI。相反,需要终止 TLS(这意味着需要适当的证书等),然后必须使用预期的 SNI 集创建新的 TLS 会话。
好吧,我假设您在调用 curl -v https://127.0.0.1/
.
我强烈建议告诉 curl 如何解决 something.example.com
curl -v --resolve something.example.com:443:127.0.0.1 https://something.example.com/
这篇博客有更详细的解释post https://daniel.haxx.se/blog/2018/04/05/curl-another-host/
顺便说一句:我强烈建议更新到最新的 haproxy 2.4 LTS 版本