FirewallD VPN Network Lock

Configuring a VPN network lock on Fedora with FirewallD for boht host and podman traffic.

Remote Penetration Tests are typically performed over a VPN, to ensure no traffic is acidentally sent from a home or non VPN IP in case of VPN drop out or issue it is important to use a lock on the network which only allows traffic to leave the host via the VPN interface and or to the VPN endpoint. Previously when running Ubuntu I achieved this using UFW (which can be seen here (https://github.com/shaunography/docker-openvpn-network-lock/blob/main/ufw_on.sh)) but migrating to Fedora Silverblue I spent some time learning FirewallD and figured out how to implement the same functionality on Fedora.

I soon realised that firewallD is more powerfull than UFW and its use of zones is much more felxible. Aditionally the integration with Podman means the hosts instance of FirewallD can be used to control traffic emanating from containers as well, obviating the need to configure a firewall within the container itself.

Below I show how it is possible to lock down all traffic coming from the host as well a traffic comming from containers in a podman network. This is also achieved using zones and policies and not any "direct" rules which manipulate IP tables directly.

Host Level

create a new VPN zone

sudo firewall-cmd --permanent --new-zone airvpn

create a new policy which will control traffic from the HOST to the VPN.

sudo firewall-cmd --permanent --new-policy HOSTToairvpn
sudo firewall-cmd --permanent --policy HOSTToairvpn --set-target DROP
sudo firewall-cmd --permanent --policy HOSTToairvpn --add-ingress-zone HOST
sudo firewall-cmd --permanent --policy HOSTToairvpn --add-egress-zone airvpn

As the policy is default DROP we need to create a rule allowing ipv4 traffic to the VPN entrypoint on port 443 (OpenVPN). if your provider uses a different port this will need to be updated accordingly. Also if multiple entrypoint servers are in use, add a new rule for each IP address of each server.

sudo firewall-cmd --permanent --policy HOSTToairvpn --add-rich-rule="rule family="ipv4" destination address="$ip" port port=443 protocol="udp" accept"

If you need to communicate with hosts on the LAN then add an accept for that as well. Beware, if your DNS is provided by a DNS server on your LAN you are also allowing non VPN DNS requests to reach the internet.

sudo firewall-cmd --permanent --policy HOSTToairvpn --add-rich-rule="rule family="ipv4" destination address="$ip" accept"

Reload the firewall for the configuration to be applied.

sudo firewall-cmd --reload

now you just need to enable the policy by assigning your ethernet or wireless interface to the VPN zone, in the case of this example "airvpn".

sudo sudo firewall-cmd --zone airvpn --change-interface enp0s13f0u1u4c2

Container Level

Controlling traffic at the container level is much the same.

Create a new podman network, all containers to which the lock down policy will apply will need to be in this network. To ensure greater control over DNS we will disable DNS in this network and pass the DNS servers IPs into the containers at run time.

sudo podman network create \
--subnet=172.30.30.0/24 \
--disable-dns \
-o com.docker.network.bridge.name="airvpnBridge" \
airvpn \

Create a new zone in which we will put the podman network.

sudo firewall-cmd --permanent --new-zone airvpnNetwork

Create a new policy controlling traffic from the VPN network to ANY, with a default drop policy.

sudo firewall-cmd --permanent --new-policy airvpnNetToWorld
sudo firewall-cmd --permanent --policy airvpnNetToWorld --set-target DROP
sudo firewall-cmd --permanent --policy airvpnNetToWorld --add-ingress-zone airvpnNetwork
sudo firewall-cmd --permanent --policy airvpnNetToWorld --add-egress-zone ANY
sudo firewall-cmd --permanent --policy airvpnNetToWorld --add-masquerade

Once again allow outbound traffic to the VPN entrypoint servers on port 443 (OpenVPN), if you have multiple entry IPs and different port numbers create a rule for each and update accordingly.

sudo firewall-cmd --permanent --policy airvpnNetToWorld --add-rich-rule="rule family="ipv4" destination address="$ip" port port=443 protocol="udp" accept"

Reload the firewall for the configuration to be applied.

sudo firewall-cmd --reload

Enable the policy by adding the source IP ranges for the newly created podman network to the VPN network zone.

sudo firewall-cmd --zone airvpnNetwork --change-source 172.30.30.0/24

In this setup you will need a container in the podman network to connect to the VPN and act as the gateway for any other containers in the network. Examples of which can be found here (https://github.com/shaunography/docker-openvpn-network-lock/blob/main/dockerfile) and here (https://gitlab.com/shaunwebber/field-kit/-/blob/main/airvpn/Containerfile) but any container with the OpenVPN client intalled will be fine.

once you have a running container in the network with an active VPN connection, additional containers can use the network and therefore VPN as follows.

sudo podman run -ti --rm --name kali --network host:host_connected_to_vpn docker.io/kalilinux/kali-rolling

Resources