WireGuard – Restrict access to specific IP addresses
To restrict client access to specific IP addresses, you can use the WG_POST_UP environment variable in the wg-easy Docker image to override the default iptable rules and define custom ones.
Prerequisite
This article describes the procedure for the wg-easy Docker container. It can also be adapted to any WireGuard setup.
The following example is made for a configuration with the default address 10.8.0.x (WG_DEFAULT_ADDRESS) and two clients with the IP addresses 10.8.0.2 and 10.8.0.3.
I want to achieve, that client1 (10.8.0.2) has no access restrictions and client2 (10.8.0.3) is only allowed to connect to a specific IP address (192.168.1.50).
Configuration
The default WG_POST_UP variable is:
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT;
If the WG_DEFAULT_ADDRESS is different than 10.8.0.x, you have to substitute “10.8.0.0/24” with your chosen address space.
The new WG_POST_UP variable is:
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT;
iptables -A FORWARD -i wg0 -s 10.8.0.2/32 -j ACCEPT;
iptables -A FORWARD -o wg0 -d 10.8.0.2/32 -j ACCEPT;
iptables -A FORWARD -i wg0 -s 10.8.0.3/32 -d 192.168.1.50/32 -j ACCEPT;
iptables -A FORWARD -o wg0 -s 192.168.1.50/32 -d 10.8.0.3/32 -j ACCEPT;
iptables -A FORWARD -i wg0 -j DROP;
iptables -A FORWARD -o wg0 -j DROP;
Explanation
To better understand the iptable rules in this context, it’s important to know that:
Inbound traffic means incoming traffic from a WireGuard client towards the local network based on the source address
Outbound traffic means outgoing traffic from the local network towards a WireGuard client based on the destination address
Explanation client1 (10.8.0.2):
This line targets incoming traffic on interface wg0 (-i) for the IP address 10.8.0.2 (-s) and accepts it:iptables -A FORWARD -i wg0 -s 10.8.0.2/32 -j ACCEPT;
This line targets outgoing traffic on interface wg0 (-o) for the IP address 10.8.0.2 (-d) and accepts it:
iptables -A FORWARD -o wg0 -d 10.8.0.2/32 -j ACCEPT;
Explanation client2 (10.8.0.3):
This line targets incoming traffic on interface wg0 (-i) for the IP address 10.8.0.3 (-s) from the IP address 192.168.1.50 (-d) and accepts it:iptables -A FORWARD -i wg0 -s 10.8.0.3/32 -d 192.168.1.50/32 -j ACCEPT;
This line targets outgoing traffic on interface wg0 (-o) for the IP address 192.168.1.50 (-s) from the IP address 10.8.0.3 (-d) and accepts it:
iptables -A FORWARD -o wg0 -s 192.168.1.50/32 -d 10.8.0.3/32 -j ACCEPT;
Explanation DROP part:
With the last two lines every other traffic which isn’t affected by an iptables rule will be dropped:
iptables -A FORWARD -i wg0 -j DROP;
iptables -A FORWARD -o wg0 -j DROP;
Docker Compose file
A Docker Compose file for wg-easy with the implemented config from above could look like this:
services:
wg-easy:
environment:
- WG_DEFAULT_ADDRESS=10.8.0.x
- WG_POST_UP=
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT;
iptables -A FORWARD -i wg0 -s 10.8.0.2/32 -j ACCEPT;
iptables -A FORWARD -o wg0 -d 10.8.0.2/32 -j ACCEPT;
iptables -A FORWARD -i wg0 -s 10.8.0.3/32 -d 192.168.1.50/32 -j ACCEPT;
iptables -A FORWARD -o wg0 -s 192.168.1.50/32 -d 10.8.0.3/32 -j ACCEPT;
iptables -A FORWARD -i wg0 -j DROP;
iptables -A FORWARD -o wg0 -j DROP;
...