I use libpam-net to segregate a dedicated system user into a network namespace which can only talk to the outside world through a wireguard interface.
mullvad-wg-netns.sh
implements the provisioning of the
wireguard configs (generating privkey, uploading pubkey to mullvad API etc.). It
also supports bringing up the wireguard interface at boot since wg-quick
does
not support netns or operating on a pre-existing wg interface.
First we set up dependencies and libpam-net:
$ apt-get install dateutils curl jq wireguard-tools libpam-net
$ pam-auth-update --enable libpam-net-usernet
$ addgroup --system usernet
$ adduser <myuser> usernet
Note we need at least libpam-net 0.3, which is part of Debian bullseye now. Yey!
Now whenever <myuser>
logs in, or a service is started as them, it will
be placed in a netns (cf. ip-netns(8)) corresponding to their
username. This netns is created if it doesn't already exist, but the
intention is that you arrange for it to be setup during boot.
Next we provision the wireguard configs:
$ path/to/mullvad-wg-net.sh provision
This will ask you for your mullvad account number, so keep that ready. What this does is associate your mullvad account with the wg private key it generates.
Note: The account number is not stored on the system after provisioning.
We're almost done, now we setup resolv.conf
to prevent DNS leaks in the
netns:
$ mkdir -p /etc/netns/<myuser>
$ printf '%s\n' '# Mullvad DNS' 'nameserver 10.64.0.1' > /etc/netns/<myuser>/resolv.conf
$ chattr +i /etc/netns/<myuser>/resolv.conf
I do chattr +i
to prevent resolvconf from meddling with this config. I suppose
it would be possible just to change the resolvconf configuration to get it
seperated from the main system, but without changes it will just use the DNS of
the rest of the system.
Finally to start the mullvad wireguard interface you should use the following command:
$ path/to/mullvad-wg-net.sh init <myuser> mullvad-<regioncode>.conf
Replace <regioncode>
by whatever mullvad region you want to use, for example
mullvad-at1.conf
, you can find the full list in /etc/wireguard/
after
provisioning.
To make this permanent you can simply put it in /etc/rc.local
or create a
systemd unit or something if you insist.
In order to make sure this whole setup works and to prevent leaks if something fails I like to check if connectivity is going through mullvad on login. The mullvad guys provide a convinient service for this: https://am.i.mullvad.net and I wrote a convinient shell wrapper for it: am-i-mullvad.sh.
To use it put it in your .bash_profile
or simmilar shell startup script:
$ cat >> .bash_profile << EOF
sh path/to/am-i-mullvad.sh || exit 1
EOF
If we're not connected through mullvad it will print an error message and kill the shell after a short timeout so you can still get access by Ctrl-C'ing the script if needed.