Firewall (iptables)#
A very simple static firewall based on iptables
is installed when running the
deploy scripts. It allows connections to the VPN, SSH, HTTP and HTTPS ports. In
addition it uses NAT for both IPv4 and IPv6 client traffic.
This document explains how to modify the firewall for common scenarios that
deviate from the default and on how to tailor the VPN configuration for your
particular set-up. Much more is possible with iptables
that is out
of scope of this document. We only collected some common situations below.
The annotated default firewall configuration files as installed on new deployments can be found here:
You can of course also use the firewall software of your choice, or fully disable the firewall! As our goal was to keep things as simple and easy as possible by default.
Fedora / EL#
You can find the firewall rules in /etc/sysconfig/iptables
(IPv4) and
/etc/sysconfig/ip6tables
(IPv6).
After making changes, you can restart the firewall using:
$ sudo systemctl restart iptables && sudo systemctl restart ip6tables
You can fully disable the firewall as well:
$ sudo systemctl disable --now iptables && sudo systemctl disable --now ip6tables
Debian#
You can find the firewall rules in /etc/iptables/rules.v4
(IPv4)
and /etc/iptables/rules.v6
(IPv6).
After making changes, you can restart the firewall using:
$ sudo systemctl restart netfilter-persistent
You can fully disable the firewall as well:
$ sudo systemctl disable --now netfilter-persistent
IPv4 vs IPv6#
The configuration of IPv4 and IPv6 firewalls is almost identical. When
modifying the configuration files you, obviously, have to use the IPv4 style
addresses in the IPv4 firewall, and the IPv6 style addresses in the IPv6
firewall. In addition, the ICMP type is different, i.e. icmp
for IPv4 and
ipv6-icmp
for IPv6, see the iptables
and ip6tables
for examples.
Improving the Defaults#
The default firewall works well, but can be improved upon by updating it to match your deployment.
Restricting SSH Access#
By default, SSH is allowed from everywhere, including the VPN clients. It makes sense to restrict this a set of hosts or a “bastion” host.
The default INPUT
rule for SSH is:
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
You can modify these rules like this:
-A INPUT -s 192.0.2.0/24 -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -s 198.51.100.0/24 -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
This allows only SSH connections coming from 192.0.2.0/24
and
198.51.100.0/24
. This will also prevent VPN clients from accessing the SSH
server.
Opening Additional VPN Ports#
By default, one port, both for TCP and UDP are open for OpenVPN connections:
-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 1194 -j ACCEPT
You can easily add more by using “ranges”, e.g.
-A INPUT -p udp -m state --state NEW -m udp --dport 1194:1197 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 1194:1197 -j ACCEPT
NAT to Multiple Public IP Addresses#
When using NAT with many clients, it makes sense to “share” the traffic over multiple public IP addresses.
The default POSTROUTING
rule in the “NAT” table is:
-A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE
-A POSTROUTING -s 172.16.0.0/12 -o eth0 -j MASQUERADE
-A POSTROUTING -s 192.168.0.0/16 -o eth0 -j MASQUERADE
Assuming all IP addresses assigned to VPN clients are in the 10.0.0.0/8
prefix, you can replace this by for example this line:
-A POSTROUTING -s 10.0.0.0/8 -j SNAT --to-source 192.0.2.1-192.0.2.8
Make sure you replace 10.0.0.0/8
with your VPN client IP range and
192.0.2.1-192.0.2.8
with your public IP addresses. All IP addresses in the
specified --to-source
range will be used, specified IPs included.
NOTE: for IPv6 the situation is similar, except you’d use the IPv6 range(s) and address(es).
NAT to Different Public IP Addresses per Profile#
When using Multiple Profiles, you may want to NAT to different public IP addresses. You could for example use:
-A POSTROUTING -s 10.0.1.0/24 -j SNAT --to-source 192.0.2.1
-A POSTROUTING -s 10.0.2.0/24 -j SNAT --to-source 192.0.2.2
-A POSTROUTING -s 10.0.3.0/24 -j SNAT --to-source 192.0.2.3
Make sure you replace the IP ranges specified in -s
with your VPN client IP
ranges assigned to the profiles, and the --to-source
address with your public
IP addresses.
NOTE: for IPv6 the situation is similar, except you’d use the IPv6 range(s) and address(es).
Allow Client to Client Traffic#
By default, client-to-client traffic is not allowed:
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT
You can either allow all forwarding, be specific with IP ranges
(using the -s
and -d
flags) or even interfaces.
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o wg0 -j ACCEPT
-A FORWARD -i wg0 -o tun+ -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i tun+ -o tun+ -j ACCEPT
-A FORWARD -i tun+ -o wg0 -j ACCEPT
As an example, you have two WireGuard-only profiles on your server with
10.0.0.0/24
and 10.100.100.0/24
prefixes where the first allows access to
the Internet, and the second only allows connectivity between the clients.
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wg0 -s 10.0.0.0/24 -o eth0 -j ACCEPT
-A FORWARD -i wg0 -s 10.100.100.0/24 -d 10.100.100.0/24 -i wg0 -o wg0 -j ACCEPT
Reject Forwarding Traffic#
Sometimes you want to prevent VPN clients from reaching certain network, or allow them to reach only certain networks. For example in the “split tunnel” scenario. By default, the firewall will allow all traffic and just route traffic as long as the routing for it is configured.
If you use split tunnel, it could make sense to only allow traffic for the ranges you also push to the client. As the client can always (manually) override the configuration and try to send all traffic over the VPN, this may need to be restricted.
If you want to only only traffic to 10.1.1.0/24
and 192.168.1.0/24
from
your VPN clients, you can use the following:
-A FORWARD -i tun+ -d 10.1.1.0/24 -j ACCEPT
-A FORWARD -i tun+ -d 192.168.1.0/24 -j ACCEPT
NOTE: for IPv6 the situation is similar.
Drop Certain VPN Client Traffic#
One might want to reject traffic to various ports on the Internet.
Traditionally the port to block would be tcp/25
to prevent spam, but these
days that seems unnecessary due to mitigations like SPF and DMARC/DKIM, but
for completeness sake, we’ll show how to do that here.
The first line is for the IPv4 firewall, the second for IPv6.
-A FORWARD -p tcp --dport 25 -j REJECT --reject-with icmp-admin-prohibited
-A FORWARD -p tcp --dport 25 -j REJECT --reject-with icmp6-adm-prohibited
Reject IPv6 Client Traffic#
As the VPN server is “dual stack” throughout, it is not possible to “disable”
IPv6. However, one can easily modify the firewall to prevent all IPv6 traffic
over the VPN to be rejected. By rejecting instead of dropping, clients will
quickly fall back to IPv4, there will not be any delays in establishing
connections. You can simply remove all FORWARD
rules and replace it with:
-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited
This will cause all IPv6 to be rejected. The VPN becomes thus effectively IPv4 only. You can of course also use it to reject IPv4 traffic to create an IPv6-only VPN.
Public IP Addresses for VPN Clients#
If you want to use Public Addresses for the VPN clients, this has some implications for the firewall:
- NAT needs to be disabled;
- Incoming traffic for VPN clients may need to be blocked.
NOTE: it is possible to use NAT for IPv4 and public IP addresses for IPv6, actually this is recommended over using IPv6 NAT!
Disabling NAT#
By removing all POSTROUTING
rules from the “NAT” table takes care of
disabling NAT.
Allowing Incoming Traffic#
The default FORWARD
rules used are:
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT
This restrict any traffic initiating on the outside reaching your VPN clients.
If you want to allow traffic from a designated host to the clients, e.g. for remote management, you can use the following:
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i wg0 -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o tun+ -s 192.168.11.22/32 -j ACCEPT
-A FORWARD -i eth0 -o wg0 -s 192.168.11.22/32 -j ACCEPT
NOTE: for IPv6 the situation is similar.