Transparent proxy of SSL traffic using Pound to HAProxy backend patch and howto
by Malcolm Turnbull
OK so I’ve previously blogged about how to get TPROXY and HAProxy working nicely together. But what if you want to terminate SSL traffic on the load balancer in order to use HaProxy to insert cookies in the standard HTTP stream to the backend servers?
Many thanks to Krisztián Ivancsó for working on the TPROXY patch for Pound for us, we can finally do this!
First of all lets explain what we are trying to achieve. We have clients coming in from the external subnet 10.0.0.x with both HTTP and HTTPS requests to our virtual server (10.0.0.142), The HTTPS traffic is terminated by pound and sent to an HAProxy backend (10.0.0.142:81) which in turn inserts session cookies and passes the traffic to the backend servers (192.168.2.x).
The HTTP traffic hits a seperate HAProxy instance on (10.0.0.142:80) where cookies are inserted and traffic passed to the backend servers (192.168.2.x). Why a second instance? Unfortunately it is not currently possible to have TPROXY running for Pound and HAProxy using the same IP and port combination (which makes sense if you think about it).
Just a reminder - “why are we doing all of this?”, because we want to clients source IP address to be presented to the backend server even though the traffic is coming through a proxy!
So lets assume that you have already set up HAProxy in TPROXY mode for full transparency.
First of all we need to grab a recent copy of Pound and the TPROXY patch, configure, make & install etc.
wget http://www.loadbalancer.org/download/PoundSSL-Tproxy/Pound-2.4.5.tgz
tar -xvf Pound-2.4.5.tgz
cd Pound-2.4.5
wget http://www.loadbalancer.org/download/PoundSSL-Tproxy/poundtp-2.4.5.diff
patch -p1 < poundtp-2.4.5.diff
./configure
make TPROXY=1
make install
Make sure the firewall rules are set correctly for standard TPROXY (HAProxy binds to these automatically), as in the previous blog.
# Standard rules for TPROXY setup
#!/bin/bash
iptables -t mangle -N DIVERT
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 111
iptables -t mangle -A DIVERT -j ACCEPT
ip rule add fwmark 111 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
Add the rules to make sure that local Pound -> HAProxy traffic is transparent:
# Rules to match PoundSSL -> Haproxy backend
iptables -t mangle -A OUTPUT -s 10.0.0.142 -p tcp –sport 81 -j DIVERT
iptables -t mangle -A OUTPUT -d 10.0.0.142 -p tcp –dport 81 -j DIVERT
Then configure HAProxy making sure you have two instances with the same real servers, one for HTP traffic and one for the transparent terminated HTTPS traffic:
# HAProxy configuration file generated by load balancer appliance
global
#uid 99
#gid 99
daemon
stats socket /var/run/haproxy.stat mode 600
maxconn 40000
ulimit-n 81000
pidfile /var/run/haproxy.pid
defaults
mode http
contimeout 4000
clitimeout 42000
srvtimeout 43000
balance roundrobin
listen VIP_Name 10.0.0.142:80
mode http
option forwardfor
source 0.0.0.0 usesrc clientip
cookie SERVERID insert nocache indirect
server RIP_Name 192.168.2.98:80 weight 1 cookie RIP_Name check inter 2000 rise 2 fall 3
server backup 127.0.0.1:80 backup source 0.0.0.0
option redispatch
option abortonclose
maxconn 40000
listen SSL_Backend 10.0.0.142:81
mode http
option forwardfor
source 0.0.0.0 usesrc clientip
cookie SERVERID insert nocache indirect
server RIP_Name 192.168.2.98:80 weight 1 cookie RIP_Name check inter 2000 rise 2 fall 3
server backup 127.0.0.1:81 backup source 0.0.0.0
option redispatch
option abortonclose
maxconn 40000
Make sure that when you do the Pound configuration that Pound is running as root:
# Pound2 configuration file generated by load balancer appliance
#User "nobody"
#Group "nobody"
LogLevel 0
Client 30
TimeOut 60
ListenHTTPS
Address 10.0.0.142
Port 443
Cert "/usr/local/etc/server1.pem"
Service
BackEnd
Address 10.0.0.142
Port 81
TProxy 1
End
End
End
Obviously make sure that:
- The client is in the 10.0.0.x network.
- The load balancer has IPs in both networks.
- The backend server uses the load balancer as the default gateway.
- You have your fingers crossed :-).
I put this together fairly quickly, so please let me know if I have missed anything. With any luck it should make it into the v6.7 appliance fairly soon.. available as a manual update for now until v6.7 is ready.
Since writting this Ivan has added three new features (I’ve updated the dowload link to have this latest version).
Three new features:
- You can use patched Pound without root privileges
- It adds a new global TProxy option which disables/enables TProxy globally. (If this global option is set, then pound will preserve needed privileges to work as transparent proxy as a simple user. If it’s not set pound will work as unpatched version and will not preserve additional rights.)
- Let tproxy to set a random port for source IP when Pound connects to backend. It means original source port is not preserved in communication with backend.
Example config:
User "ivan"
Group "ivan"
LogFacility -
LogLevel 5
TProxy 1
ListenHTTP
Address 192.168.254.22
Port 81
End
Service
BackEnd
Address 192.168.254.22
Port 80
TProxy 1
End
End



October 2nd, 2009 at 4:56 pm
Hi Malcolm and a big thanks for this article.
I am going through it as of now as we now need to terminate SSL on the SLB.
I was just wondering if it could be possible for you guys to put the checksum of the files (pound and patch) available so we can make sure the data we are downloading is properly downloaded and not compromised in any way.
Thanks a lot in advance!
G.
October 2nd, 2009 at 5:26 pm
I have just downloaded the file: poundtp-2.4.5.tgz and it does not contain the poundtp-2.4.5.diff file.
I found it here: http://pound.percek.hu/poundtp-2.4.5.diff from this site: http://pound.percek.hu/
HTH
G.
October 2nd, 2009 at 5:36 pm
Me again but I do not understand the following:
cp ./poundtp-2.4.5.diff ../Pound-2.4.5
cd ../
cd ../Pound-2.4.5
patch -p1 < poundtp-2.4.5-rndport-cap.diff
You are copying poundtp-2.4.5.diff to Pound-2.4.5, then applying this patch: poundtp-2.4.5-rndport-cap.diff from Pound-2.4.5.
The only problem is that this patch does not exist in the Pound-2.4.5 folder…
Can you please shed some light?
TIA
G.
October 3rd, 2009 at 1:07 pm
Gael,
Sorry I had not updated the tar file with the latest diff package. I have now changed the blog and uploaded the current patch correctly. wget http://www.loadbalancer.org/download/PoundSSL-Tproxy/poundtp-2.4.5.diff
October 5th, 2009 at 2:11 pm
Hi Malcolm and thanks for your reply and update of your post, much appreciate!
The other thing, I would like to highlight is that I had problems with the logged IP on my httpd backend server. They were logging the SLB IP (even with mod_rpaf doing some cleaning of the X-Forwarded-For headers…).
So after some investigation, scratching my head and doing some diagrams of the network flow of my installation, it appears that the problem was in haproxy configuration.
In the post, you are using mode http, and that was causing the web server to log the wrong IP. Using mode tcp fixed the problem.
Which makes sense if you think about how TProxy is working with HAProxy, as, AFAIK , it is used on Layer 4 and not Layer 7…
Well anyway, here is my conf of haproxy (hugely inspired from yours obviously!):
listen SSL_Backend VIP_OF_SLB:81
mode tcp
balance roundrobin
option forwardfor
source 0.0.0.0 usesrc clientip
server gr-web04 RIP_OF_BACKEND_WEBSERVER port 80 weight 10 check
Now, the IP is correctly logged!
So now, having accomplished that, we are able to do the following:
SLB: with HAProxy + Pound for SSL termination that load balances: HTTP, HTTPS and FTP active / passive
And on the backend, we have Squid as reverse proxy then Apache and we are logging the originating client IP!
I hope this helps!
Gael
October 30th, 2009 at 5:22 pm
Hi Malcolm, thanks for your great article. We are running Haproxy with full transparent mode enabled, and we are using Pound to terminate SSL requests.
But, for multiple times that I’ve reread this article, I can’t see why do you need a separate instance (not as in process instance, but as “bind” instanace, I assume) for Pound-incoming traffic.
Couldn’t you just redirect traffic from Pound to the haproxy bound on port 80? Why another instance in port 81? As you say, its not possible to use the same IP:port combination in Pound and Haproxy, but Pound is binding to port 443 and Haproxy to port 80. I can’t see an IP:port collision.
Thanks and congratulations!!
Alberto Giménez
November 14th, 2009 at 3:48 am
Alberto,
Ooops forgot to actually reply to this, hence the delay. The port collision occurs on the TPROXIED return packets.. How does the subsystem know whether to send the replies to Pound or to HAProxy? I’m not totally sure on the specifics but I just know you can’t do it - at least not with the current code :-).