请注意,这也已发布在http://thread.gmane.org/gmane.comp.web.haproxy/27737
我们正在尝试配置这种架构:
- ELB 终止 SSL,使用预配置的证书。(这是必需的,因为只有受限制的人才能访问最终用户证书)
- ELB 使用 SSL 连接到 HAproxy 后端(也是要求)
ELB 发送代理标头,具体说明如下http://amzn.to/1YajEG3
HAproxy 在 443 中监听 SSL
- HAProxy 用于进行一些 HTTP 转换(修改标头等)。
一旦 ELB 配置为 SSL + Proxy 协议,我们就尝试通过在 HTTPS 前端的绑定中添加 accept-proxy 来配置 HAProxy:
frontend https-in
mode http
# Note, I truncated this line because the maillist 80 chars limitations
bind :443 accept-proxy ssl crt \
/var/vcap/jobs/haproxy/config/cert.pem \
no-sslv3 ciphers ...
...
但它失败了:Received something which does not look like a PROXY protocol header
。
故障排除我发现 ELB 在 SSL 流内部发送 PROXY 标头。例如,我运行 openssl 作为服务器:
$ openssl s_server -accept 443 -cert cert.pem
...
ACCEPT
bad gethostbyaddr
-----BEGIN SSL SESSION PARAMETERS-----
MFUCAQECAgMDBAIAnwQABDBsAWD78V/tz9KhYw4R/kpL5YPBxfF1qcmzxlclNDuz
0KWw9aGojVogjtBkH/zZOLWhBgIEVyoquqIEAgIBLKQGBAQBAAAA
-----END SSL SESSION PARAMETERS-----
Shared
ciphers:...
CIPHER is DHE-RSA-AES256-GCM-SHA384
Secure Renegotiation IS supported
PROXY TCP4 80.194.77.90 192.168.6.14 39220 443
GET / HTTP/1.1
User-Agent: curl/7.35.0
Host: something.com
Accept: */*
因此我在 haproxy 中做了一个“链式”配置,一个使用纯 TCP 进行 SSL 终止,另一个“提取”代理协议并进行 HTTP 转换:
listen https-in
mode tcp
bind :443 ssl crt /var/vcap/jobs/haproxy/config/cert.pem no-sslv3
ciphers ...
server http 127.0.0.1:8081
frontend http-in-from-ssl
mode http
bind :8081 accept-proxy
option httplog
option forwardfor
reqadd X-Forwarded-Proto:\ https
default_backend http-routers
并且有效!
我的问题是:
- 这是正常且预料之中的吗?我找不到任何相关信息。
- 是否可以更改 ELB 行为以将代理协议标头放在 SSL 流之外?我没有找到有关此内容的任何信息。
- 如果没有的话,是否可以更改 HAProxy 的行为以使用一个前端,但从 SSL 流内部读取代理协议标头?
- 如果没有的话,有没有更好的方法来“链接”配置,就像我上面做的那样。
谢谢你!
答案1
这是针对您的问题 1 的信息,请查看下面的 URL。
桌子最后一排的战利品TCP/SSL 负载均衡器(第二张表)。这只是你的情况。它明确地说
不支持代理协议标头。
因此对于你的问题2,答案是否定的。
并且很抱歉我无法为您的问题3和4提供更多帮助。(实际上,根据我的经验,对于问题4,我认为您的方法已经足够好了。也许我的经验还不够;P)
答案2
我也遇到了这个问题。但是,我在内部负载均衡器上使用 nginx 而不是 HA-proxy。
解决方案类似,但我认为值得发布:
#nginx.conf
user nginx;
worker_processes 1;
error_log /dev/stderr debug;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
stream {
upstream stream_backend {
server 127.0.0.1:500;
}
server{
listen 443 ssl;
proxy_pass stream_backend;
ssl_certificate /certs/local/public.crt;
ssl_certificate_key /certs/local/private.key;
ssl_protocols TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
}
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '[$host] $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /dev/stdout main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 60;
#gzip on;
server {
listen 8000;
location /elb-status {
keepalive_timeout 0; # Disable HTTP keepalive
access_log off;
return 200;
}
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80 proxy_protocol;
server_name test-nginx.corp.com;
location / {
keepalive_timeout 0; # Disable HTTP keepalive
return 301 https://$host$request_uri;
}
}
upstream nginx-test-stack {
server 10.42.111.6:80;
}
server {
listen 127.0.0.1:500 proxy_protocol;
server_name test-nginx.corp.com;
real_ip_header proxy_protocol;
location / {
proxy_pass http://nginx-test-stack;
}
}
}
这样我就可以为任何 TCP 连接启用 E2E 加密。如果需要,我可以代理 websockets 或 https,或者直接使用 TCP