I want to set up sslh on port 443 to forward to https and openvpn which reside in two docker containers. Since I want to provide IP based ACLs on https in the long run, I want sslh to provide the true client IP to the webserver (aka sslh's "transparent" mode).
As I understand the documentation and this answer, sslh will fake outside requests on the internal network and needs to be fed back the servers answer to translate the port for communication with the client.
My problem is the iptables setup. There are two possibilities where to run sslh: on the host or in a container inside the docker network.
I managed to get the "default" setup as described in the documentation to work, i.e.: sslh on the host could transparently forward to a service on the host.
However, I cannot get transparent sslh either on the host or in a container to work with the containerized servers. More specifically, my iptables rules to mark the traffic that should be routed to sslh never match a packet.
E.g. for an https webserver I would:
iptables -t mangle -A OUTPUT -p tcp --sport 443 --source 172.25.0.2 --jump SSLH
Using this chart I tried to discern how the virtual ethernet devices of the container, the docker bridge, the docker NAT and iptables work together but I can't wrap my head around it.
To better discuss this let us assume the following:
- host (eth0): 220.127.116.11
- docker-bridge (br0): 172.25.0.0/16
- webserver (veth1): 172.25.0.2:443 (exposed on host as 8443 if necessary)
- openvpn (veth2): 172.25.0.3:1194 (forwarded to host if necessary)
- sslh in container (mutually exclusive with host sslh): 172.25.0.4:443 (forwarded to host)
- sslh on host (mutually exclusive with container sslh): port 443
- client: 18.104.22.168
Here is my failing model of should happen when a browser connects to host:443 and sslh is on the host in transparent mode
- sslh connects to 172.25.0.2:8443 posing as the original client 22.214.171.124
- the webserver answers for the TCP handshake to 126.96.36.199 via veth1
- the packet goes onto br0
- the routing decides to send it via ent0
- iptables' mangle output chain marks it as traffic for sslh (this is what does not work for me)
- the mark indicates to route the packet to the local lo device instead
- sslh picks it up, translates the port and sends it back to the client
My problem in the above list is, that I don't know the filter criteria for the webservers outbound traffic: Should I use the docker internal port 443 or the mapped port 8443? The docker IP 172.25.0.2 or another one? It boils down to: will by mangle output rule run before or after docker's NAT?
The I thought I could put sslh into the docker network to avoid thinking about the NAT but I still can't get the iptables rules to match.
I am at a loss how to proceed.