I am running HAProxy in TCP mode with TLS (client certificate based authentication). My configuration is pasted below. My goal is to redirect the SSH connection to correct server based on Client certificate that is being presented. This example talks about SSH but in the future I have various services that I may have to securely expose in this manner. Any help is appreciated.
Note that in HTTPS mode you can extract the client CN using something like and use the variable in header against an ACL. However, as I am in TCP mode, I am unsure how to do something similar.
http-request set-header X-SSL-Client-CN %{+Q}[ssl_c_s_dn(cn)]
However, I am not sure how to do something similar when running in TCP mode.
frontend Frontend_server
mode tcp
option tcplog
log global
bind X.X.X.X:8000 ssl crt /etc/certs/server.pem ca-file /etc/certs/ca.crt verify required
acl ACL_SRV1 ??????? -m str -f /etc/SRV1/cn.list
acl ACL_SRV2 ??????? -m str -f /etc/SRV2/cn.list
acl ACL_SRV3 ??????? -m str -f /etc/SRV3/cn.list
log-format %ci:%cp\ [%t]\ %ft\ %b/%s\ %ST\ %B\ %tsc\ %ac/%fc/%bc/%sc\ %sq/%bq\ {%[ssl_c_verify],%{+Q}[ssl_c_s_dn],%{+Q}[ssl_c_i_dn]
use_backend SRV1 if ACL_SRV1
use_backend SRV2 if ACL_SRV2
use_backend SRV3 if ACL_SRV3
backend SRV1
mode tcp
option tcplog
option tcp-check
server MY_SRV1 X.X.X.X:22 check inter 1000 port 22 maxconn 1000
backend SRV2
mode tcp
option tcplog
option tcp-check
server MY_SRV2 X.X.X.X:22 check inter 1000 port 22 maxconn 1000
backend SRV3
mode tcp
option tcplog
option tcp-check
server MY_SRV3 X.X.X.X:22 check inter 1000 port 22 maxconn 1000
With tcp mode the TLS is not terminating at HAProxy but the TLS termination is done on the server behind haproxy. This server has of course to be known before any data can be send or forwarded to the server. This means a decision which server to choose can only be done on the first data from the client in the TLS handshake (ClientHello) but not on later data which require a reply from the server already.
But, client certificates are only send by the client if the server explicitly requests these. This means, in order to get a client certificate from the client the server needs to communicate with the client which means that the connection to the server has to be established already. This of course means that the decision which server to use cannot be done based on the client certificate since the client certificate is known too late in the TLS handshake.
The only way to make such a decision based on the client certificate would be to terminate TLS at the load balancer already.
Related
I just set up HAProxy on a server by itself to act as a reverse proxy. This will send the traffic to a main server that's running Nginx.
I got it almost working, aside from being able to pass the original IP through from the proxy server to the web server.
I'm using mode tcp in haproxy since a lot of the traffic coming in will already be on port 443 using SSL. I read that I can't use the option forwardfor in tcp mode, and I can't send SSL traffic using mode http. So I added send-proxy to the server lines, and then tried to enable the proxy protocol on Nginx.
That actually worked for the domain I'm running, but we have about 10 other virtualhost domains being hosted on that same machine, and as soon as I enabled proxy protocol on one vhost separately, it broke ALL of our other domains pointing to that server, as they all started timing out.
Is there a way around this? Can I enable proxy protocol for just one virtualhost on Nginx without breaking the rest of them? Or is there a way to just use http mode with the forwardfor option, even if it's sending SSL traffic?
Below is my haproxy config, with the IPs redacted:
global
maxconn 10000
user haproxy
group haproxy
defaults
retries 3
timeout client 30s
timeout server 30s
timeout connect 30s
mode tcp
frontend incoming
bind *:80
bind *:443
option tcplog
default_backend client_proxy
backend client_proxy
use-server ps_proxy_http if { dst_port 80 }
use-server ps_proxy_https if { dst_port 443 }
server ps_proxy_http XXX.XXX.XXX.XXX:80 send-proxy
server ps_proxy_https XXX.XXX.XXX.XXX:443 send-proxy
This is my first time using HAProxy as a reverse proxy, so any insight would be much appreciated.
I have Direct Connect over a fast pipe to an AWS VPC and I'd like to use a cluster of HAProxy instances in my VPC to reverse-proxy one or more S3 buckets. This is so my users on premises can enjoy the increased bandwidth.
I guess the main question is whether this is doable, with the follow-on, "Is there a better solution for this than HAProxy?" I don't want to use an explicit proxy like squid because my only use-case for this is S3.
Assuming HAProxy is fine, I did a quick dummy setup for one bucket as a POC. When I connect directly to the bucket without credentials (simply to test connectivity), I see the "Access Denied" XML response I expect. But when I connect to the reverse-proxy, it seems to redirect me to https://aws.amazon.com/s3/. How am I screwing this up?
Here's my config (replace MY_BUCKET with any bucket name):
global
daemon
maxconn 256
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:80
default_backend servers
backend servers
server server1 MY_BUCKET.s3.amazonaws.com:80 maxconn 100
UPDATE:
Per Pedro's request, here is the configuration I found that makes this work. As you can see, it's extremely bare bones. (I'm using an EC2 instance with two CPUs.)
global
daemon
nbproc 2
nbthread 1
defaults
mode tcp
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:80
default_backend S3
backend S3
server server1 s3.amazonaws.com:80
Proxying from HAProxy to Amazon S3 is definitely possible! Below is a copy of our production config file. We are using HAProxy 2.2 but this should be backward compatible to older versions as well.
resolvers dns
parse-resolv-conf
hold valid 10s
frontend wwoof
mode http
bind *:80
default_backend s3
backend s3
mode http
http-request set-header Host your-bucket.s3-website.eu-west-3.amazonaws.com
http-request del-header Authorization
http-response del-header x-amz-id-2
http-response del-header x-amz-request-id
server s3 your-bucket.s3-website.eu-west-3.amazonaws.com:80 resolvers dns check inter 5000
I'm creating an application, where frontend is Haproxy and nginx.
Do you know a way to get client IP address if navigates behind anonymous proxy with HAproxy ?
My actual configuration for haproxy use "option forwardfor", but I get anonymous proxy IP instead real client IP in nginx logs (using $http_x_forwarded_for var)
frontend general_frontend
bind 111.111.111.111:80
default_backend nginx_farm_backend
backend nginx_farm_backend
balance roundrobin
option abortonclose
option forwardfor
http-check disable-on-404
http-check expect string nginx
option httpchk GET /index.html HTTP/1.0
# - Nodes
server nginx-server-1 222.222.222.222:8080 check on-error mark-down observe layer7 error-limit 1
server nginx-server-1 333.333.333.333:8080 check on-error mark-down observe layer7 error-limit 1
Thank you
Do you Using $remote_addr var for nginx log format?
I am running HAProxy on a machine with multiple interfaces and I want the connection to the backend to be made from the source IP of the interface on which the client request came in. Using the source directive from the documentation in the listen blocks didn't seem to do it as all connections seem to come from the first interface. My configuration is as follows:
listen f_192.168.1.10_http
bind 192.168.1.10:80
source 192.168.1.10
mode http
option httplog
capture request header Host len 30
use_backend b_domain1_http if { hdr(host) -i domain1.com }
listen f_192.168.1.20_http
bind 192.168.1.20:80
source 192.168.1.20
mode http
option httplog
capture request header Host len 30
use_backend b_domain1_http if { hdr(host) -i domain1.com }
backend b_domain1_http
mode http
option httplog
server srv1 domain1.com:80 check inter 30s
Ie. I am struggling to get connections coming in on interface 192.168.1.10 to have their source IP be 192.168.1.10 when connecting to the backend. Right now, regardless of if the connection comes in on 192.168.1.10 or 192.168.1.20, the outgoing connection to the backend is initiated from 192.168.1.10. I thought that using source in the listen would accomplish this but when I look at the output of netstat -at, all originating connections to the backend come from 1 interface.
Does anyone have any idea on how I can ensure the source ip of the connection to the backend is the same as the interface of the original client request?
I believe you can use source as a parameter for a server.
backend be1
...
server srv1 domain1.com:80 source ${frontend_ip} check inter 30s
I believe it is possible to substitute %fi for ${frontend_ip}, and you may also use %fp or ${frontend_port} to specifiy the port. This way you can remove the source statements in the frontends.
I have set up rotating proxies with HAProxy successfully.
Following is part of haproxy.cfg;
frontend RotatingProxies1000
bind 0.0.0.0:1000
default_backend Proxies1000
option http_proxy
option httpclose
option http-use-proxy-header
backend Proxies1000
server fp0 1.1.1.1:8800
server fp1 2.2.2.2:8800
server fp2 3.3.3.3:8800
server fp3 4.4.4.4:8800
...
balance roundrobin
But i notice the rotation speed is very slow.
I made test in the Firefox, I looked up the client ip address on http://whatismyipaddress.com/.
First it's 1.1.1.1. I refreshed the page, still 1.1.1.1, refreshed again, still 1.1.1.1.
One minute later i refreshed again it became 2.2.2.2.
How to make HAProxy rotate more faster?
According to Baptiste and Willy's suggestions. I tried to add "mode http" and remove "option http_proxy".
The current config, but it's still slow to rotate IPs:
global
log 127.0.0.1 local0 notice
maxconn 4096
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
retries 3
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
frontend RotatingProxies1000
bind 0.0.0.0:1000
default_backend Proxies1000
#option http_proxy
mode http
option httpclose
option http-use-proxy-header
backend Proxies1000
server fp0 1.1.1.1:8800
server fp1 2.2.2.2:8800
server fp2 3.3.3.3:8800
server fp3 4.4.4.4:8800
...
balance roundrobin
Your configuration misses timeouts and http mode.
My assumption is that your browser does not close the connection with HAProxy because of you configuration, so HAProxy can't balance you to an other server until a new connexion is established.