1

I am very newbie to VPN so, be patient with me. Is it possible to get WireGuard work with config like that?: I need to create groups of pcs that can see only each other and with no access to the internet through VPN. They use their own gateway. For example:

  1. Group A has 10 endpoints
  2. Group B has 40 endpoints
  3. Group C has 6 endpoints, and so on - there can be up to 15 different groups with 6-40 endpoints
  4. every group has some SQL service, and every endpoint has VNC enables
  5. every endpoint can access the only endpoint from its group.
  6. endpoint uses its own gateway for the internet
  7. traffic between endoints is low (some sql queries every 60secs, and sometimes vnc connection for support)

Is it possible to do that with WireGuard? Is it the only config with WireGuard? Is iptables involved a lot? Can I ask for any guidelines?

thanks

gerpaick
  • 15
  • 8

1 Answers1

2

In order to isolate your groups, you need to configure multiple instance of wireguard with multiple routing tables.

First, create A and AAAA DNS entry for vpn.example.com resolving to your server public IPv4 and IPv6.

You can then install wireguard package. (eg. dnf install wireguard-tools), then generate the private and public key:

# Configure Wireguard folder
mkdir /etc/wireguard
cd /etc/wireguard
wg genkey | tee /etc/wireguard/privatekey | wg pubkey > /etc/wireguard/publickey
chmod 600 /etc/wireguard/*

Next, enable forwarding on your VPN server:

# Enable forwarding
echo "net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1" > /etc/sysctl.d/89-forward.conf
sysctl --system

You can now configure your group A. Most of the configuration is here, in the PostUp commands. We are refreshing nftables once the wg2 interface is created, then we are specifying that incoming traffic from wg2 ips goes to groupa routing table, and we are populating groupa routing table with only the groupa network (no default route, no groupb network), so groupa originated traffic can only access groupa machines.

PreDown deconfigure what PostUp did, all [Interface] section is the server configuration, the [Peer] ones are every single VPN client.

The Server private key is here, and the public on is in the client configuration file (later on). The client private key is in the client configuration file, and the public one is here.

# Configure groupA
echo "[Interface]
Address = 192.168.2.1/24, fd00:2::1/48
PrivateKey = [/etc/wireguard/privatekey value here]
PostUp=nft -f /etc/nftables.conf && ip rule add from 192.168.2.0/24 lookup groupa && ip -6 rule add from fd00:2::/48 lookup groupa && ip route add 192.168.2.0/24 dev wg2 proto kernel scope link src 192.168.2.1 table groupa && ip route add fd00:2::/48 dev wg2 proto kernel metric 256 pref medium table groupa
PreDown=nft -f /etc/nftables.conf && ip route del 192.168.2.0/24 dev wg2 proto kernel scope link src 192.168.2.1 table groupa && ip route del fd00:2::/48 dev wg2 proto kernel metric 256 pref medium table groupa
ListenPort = 51820
[Peer]
PublicKey = bbb
PresharedKey = ccc
AllowedIPs = 192.168.2.2/32, fd00:2::2/128
[Peer]
PublicKey = ddd
PresharedKey = eee
AllowedIPs = 192.168.2.3/32, fd00:2::3/128" > /etc/wireguard/wg2.conf

The group B, with a new routing table, a new wg3 interface, new listening port, and new networks:

# Configure groupB
echo "[Interface]
Address = 192.168.3.1/24, fd00:3::1/48
PrivateKey = [/etc/wireguard/privatekey value here]
PostUp=nft -f /etc/nftables.conf && ip rule add from 192.168.3.0/24 lookup groupb && ip -6 rule add from fd00:3::/48 lookup groupb && ip route add 192.168.3.0/24 dev wg3 proto kernel scope link src 192.168.3.1 table groupb && ip route add fd00:3::/48 dev wg3 proto kernel metric 256 pref medium table groupb
PreDown=nft -f /etc/nftables.conf && ip route del 192.168.3.0/24 dev wg3 proto kernel scope link src 192.168.2.1 table groupb && ip route del fd00:3::/48 dev wg3 proto kernel metric 256 pref medium table groupb
ListenPort = 51821
[Peer]
PublicKey = ggg
PresharedKey = hhh
AllowedIPs = 192.168.2.2/32, fd00:2::2/128
[Peer]
PublicKey = iii
PresharedKey = jjj
AllowedIPs = 192.168.2.3/32, fd00:2::3/128" > /etc/wireguard/wg3.conf

I'm not using iptables anymore, here is the nftables version so I don't do stupid mistakes. You can use it or convert it to iptables. It's a simple configuration : icmp, ssh, and wireguard accepted in input, any in output, and the forwarding section to allow wireguard clients to communicate. You can be more specific in your filtering if you want to allow only some ports.

# Configure nftables
echo 'flush ruleset
define wan = eth0
define groupa = wg2
define groupb = wg3
table inet x {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related counter packets 0 bytes 0 accept
iifname "lo" accept
icmp type echo-request accept
icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, echo-request } accept
tcp dport 22 ct state new,untracked accept
udp dport { 51820, 51821 } iif $wan ct state new,untracked accept
ip6 daddr fe80::/64 udp dport 546 ct state new,untracked accept
}
chain output {
type filter hook output priority filter; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state established,related counter packets 0 bytes 0 accept
ip protocol { icmp, tcp, udp } iif $groupa oif $groupa accept
ip6 nexthdr { icmpv6, tcp, udp } iif $groupa oif $groupa accept
ip protocol { icmp, tcp, udp } iif $groupb oif $groupb accept
ip6 nexthdr { icmpv6, tcp, udp } iif $groupb oif $groupb accept
}
}
' > /etc/nftables.conf

Here a script to create a new client in the group A. You have to change the FQDNSERVER value by the dns name you did set in the start, or set the server IP address instead.

You are the generating a private key for the client config file, and the associated public key for the server config file. The CLIENT variable just catch the last IP used, so if it is 192.168.2.10, the next client will use 192.168.2.11. Since we are using the previous IP to generate the next one, don't delete the examples address in the server config files.

In the [Peer] section, AllowedIPs is an ACL. Server side, we are only authorizing the client IP. Client side, we are authorizing the groupa network.

echo '#!/bin/bash
FQDNSERVER="vpn.example.com"
PRIVATE=`wg genkey`
PUBLIC=`echo ${PRIVATE} | wg pubkey`
PSK=`wg genpsk`
SRVPUBLICKEY=`cat /etc/wireguard/publickey` 
CLIENT="$((`cat wg2.conf | tail -n 1 | cut -d . -f 4 | cut -d / -f 1` + 1))"
echo "[Peer]
PublicKey = ${PUBLIC}
PresharedKey = ${PSK}
AllowedIPs = 192.168.2.${CLIENT}/32, fd00:2::${CLIENT}/128" >> wg2.conf
echo "[Interface]
Address = 192.168.2.${CLIENT}/32, fd00:2::${CLIENT}/48
PrivateKey = ${PRIVATE}' > /etc/wireguard/newgroupa.sh
echo "[Peer]
PublicKey = ${SRVPUBLICKEY}
PresharedKey = ${PSK}
AllowedIPs = 192.168.2.0/24, fd00:2::/48
Endpoint = ${FQDNSERVER}:51820" >> /etc/wireguard/newgroupa.sh
echo 'PersistentKeepalive = 30" > client${CLIENT}.conf
cat clienta${CLIENT}.conf
systemctl restart wg-quick@wg2.service' >> /etc/wireguard/newgroupa.sh 
chmod +x newgroupa.sh

The script for group B:

echo '#!/bin/bash
FQDNSERVER="vpn.example.com"
PRIVATE=`wg genkey`
PUBLIC=`echo ${PRIVATE} | wg pubkey`
PSK=`wg genpsk`
SRVPUBLICKEY=`cat /etc/wireguard/publickey` 
CLIENT="$((`cat wg3.conf | tail -n 1 | cut -d . -f 4 | cut -d / -f 1` + 1))"
echo "[Peer]
PublicKey = ${PUBLIC}
PresharedKey = ${PSK}
AllowedIPs = 192.168.3.${CLIENT}/32, fd00:3::${CLIENT}/128" >> wg3.conf
echo "[Interface]
Address = 192.168.3.${CLIENT}/32, fd00:3::${CLIENT}/48
PrivateKey = ${PRIVATE}' > /etc/wireguard/newgroupb.sh
echo "[Peer]
PublicKey = ${SRVPUBLICKEY}
PresharedKey = ${PSK}
AllowedIPs = 192.168.3.0/24, fd00:3::/48
Endpoint = ${FQDNSERVER}:51821" >> /etc/wireguard/newgroupb.sh
echo 'PersistentKeepalive = 30" > client${CLIENT}.conf
cat clientb${CLIENT}.conf
systemctl restart wg-quick@wg3.service' >> /etc/wireguard/newgroupb.sh 
chmod +x newgroupb.sh

Here, we add the new routing tables.

# Configure table
echo '2 groupa' >> /etc/iproute2/rt_tables 
echo '3 groupb' >> /etc/iproute2/rt_tables 

Since I'm using nftables here, I'm disabling any other firewall and be sure it is enabled. Also, we can enable the wireguard services.

# Disable firewalld (or ufw or else)
systemctl disable firewalld
systemctl stop firewalld

# Enable services on boot
systemctl enable nftables --now
systemctl enable wg-quick@wg2.service wg-quick@wg3.service --now

Now you can see your interfaces, addresses, routing tables, rules to direct to routing tables, and wireguard clients.

ip l
ip a 
ip r 
ip r show table groupa 
ip r show table groupb 
ip rule 
wg show

Configurations and scripts are based on Wireguard I'm using in production, although I did rewrite them for you without testing, so everything might not be working by just copy / pasting. It can be a good starting point though, and I'll answer your questions if you have some.

When you use newgroupa.sh or newgroupb.sh, a config file is generated. You can copy it to your client machine, and import it in the wireguard client.

If the client is Windows / MacOS / Android / iOS, you have a graphical interface to import it. If it's linux, you can install wireguard, copy the clientaxx.conf to /etc/wireguard, then systemctl enable wg-quick@clientaxx.service --now to enable and launch it.

setenforce 1
  • 928
  • 5
  • 7
  • thanks so much for the answer. I have a problem with nftables. in **/etc/nftables.conf** in `chain input` and `chain output` there is `type filter hook input priority filter;` and it gave me error, so I suppose it should be `type filter hook input priority 0;` is that right? another line with error i got is `icmp type echo-request accept` as it gives me error `Error: conflicting protocols specified: inet-service vs. icmp`. Any insight on that? It would be very helpful. – gerpaick Nov 09 '20 at 23:38
  • 1
    It looks like your nftables version (0.7.0 or older?) is older than mine (0.9.3). `filter` is an alias for `0` yes, and `icmp type echo-request accept` deals with both v4 and v6, but you can do `ip protocol icmp icmp type echo-request ct state new accept` and `ip6 nexthdr icmpv6 icmpv6 type echo-request ct state new accept` instead. – setenforce 1 Nov 10 '20 at 17:09
  • Thanks a lot! I upgraded to nftables 0.9 and it works. :) I think I have last question here (hopefully): I've connected two clients, and they both can ping servers IP, but cannot ping each other. What am I missing? I think there's something wrong with PostUp, but can't figure out what. Here is my [nftables](https://paste2.org/5dag6IzX) and [wg3.conf](https://paste2.org/XpJvwbvf). Can you please give a look and see what I am missing? – gerpaick Nov 11 '20 at 01:19
  • Have you the 192.168.3.0/24 route in `ip r show table groupb` ? – setenforce 1 Nov 11 '20 at 11:59
  • I have `192.168.0.0/24 dev wg3 proto kernel scope link src 192.168.173.1 `, so what I did wrong in PostUp and PreDown is I have `192.168.0.0/24` in **ip route add**, and **ip route del**, but it should be `192.168.173.0/24`, am I getting this right? – gerpaick Nov 11 '20 at 12:10
  • My bad, I failed at copy-pasting things, you can rewrite 192.168.0.0 by 192.168.2.0 or 192.168.3.0 depending on the interface. – setenforce 1 Nov 11 '20 at 12:43
  • 1
    works like a charm! Thank you so much for your guidance and help! – gerpaick Nov 11 '20 at 15:36