Networking – Allow Docker Container to Pass Through Strongswan on Host

dockernetworkingstrongswanUbuntu

This is my first time posting here, so i'll do my best to explain.

I installed an IPSec tunnel on my host (Ubuntu 22.04) using strongswan (bypass-lan plugin). The connection is up and stable, confirmed by ipsec statusall.

strongswan network

I declared a bridge network (app) in Docker with the exact subnet of strongswan leftsubnet (10.22.10.0/24).
I got no access to right side settings.
I got a docker-compose stack with containers using the app networks.
I added some settings to one of my container and a fixed IP for testing purpose:
compose info

THE PROBLEM:
I have absolutely no access to the TUNNEL inside the container…
but i have ping or access to internet inside container.

I tried to add an iptables rules found on other tech blog:

iptables -j SNAT -t nat -I POSTROUTING 1 -o ${OUT_INTERFACE} -d ${VPN_NETWORK} -s ${DOCKER_NETWORK} --to-source ${VPN_HOST_IP}

without any success but i'm not so aware on how iptables is working, here what I did:

${OUT_INTERFACE} = app-network-name (br-hash)
${VPN_NETWORK} = rightsubnet
${DOCKER_NETWORK} = leftsubnet
${VPN_HOST_IP} = left host public IP

I found those with the same problem but no response or not working:
here and here
I know that docker has some rules in isolation stage (1 and 2).
it's been nearly a week of unsuccessful tests, hope someone will be my savior
Thank you

EDIT

I tried this in another server with the same settings and it doesn't work, to add more details, here are the existing rules in iptables:
the network interface is br-7b5f3aa28bb9 with subnet 10.22.10.0/24

iptables -S
-A FORWARD -o br-7b5f3aa28bb9 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-7b5f3aa28bb9 -j DOCKER
-A FORWARD -i br-7b5f3aa28bb9 ! -o br-7b5f3aa28bb9 -j ACCEPT
-A FORWARD -i br-7b5f3aa28bb9 -o br-7b5f3aa28bb9 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-7b5f3aa28bb9 ! -o br-7b5f3aa28bb9 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o br-7b5f3aa28bb9 -j DROP
iptables -S -t nat
-A POSTROUTING -i br-7b5f3aa28bb9 -m policy --dir in --pol ipsec -j ACCEPT
-A POSTROUTING -s 10.22.10.0/24 ! -o br-7b5f3aa28bb9 -j MASQUERADE
-A DOCKER -i br-7b5f3aa28bb9 -j RETURN

there is nothing in mangle table.

If someone can see what is wrong here, because my POC server is off by now :/

Thank you

EDIT 2

I managed to make it work
the problem was: i used more than one network interface for the container and the destination was not directed through the good one, i added this:

iptables -t nat -I POSTROUTING -d 10.5.18.38 ! -s 10.22.10.0/24 -j SNAT --to-source 10.22.10.1

so that the traffic is nat to the good source once we asked for the IP tunneled by ipsec, so we need to add this 2 rules to makes everything works properly:

iptables -t nat -I POSTROUTING -s $DOCKER_NETWORK -d $REMOTE_NETWORK -m policy --dir out --pol ipsec -j ACCEPT
iptables -t nat -I POSTROUTING -d $REMOTE_NETWORK ! -s $DOCKER_NETWORK -j SNAT --to-source $DOCKER_NETWORK_GATEWAY

many thanks to @ecdsa for his iptables explanations

Best Answer

That NAT rule is incorrect as that is basically what Docker already does anyway (NAT private Docker networks to the IP of the host).

Since the local traffic selector (leftsubnet) for the VPN is the Docker network and not that IP, the traffic won't get tunneled.

You want to avoid any NAT from happening (including the one configured by Docker) for traffic that matches an IPsec policy. This can be achieved with a firewall rule like this:

iptables -t nat -I POSTROUTING -s ${DOCKER_NETWORK} -m policy --dir out --pol ipsec -j ACCEPT

This has to be the first rule in POSTROUTING (hence the -I). Optionally add -d ${VPN_NETWORK} to filter on the remote network(s), which can avoid an IPsec policy lookup for unrelated traffic out of the Docker network.

Related Topic