URI: 
       Title: WireGuard and Linux network namespaces
       Author: Solène
       Date: 02 July 2024
       Tags: security vpn network linux
       Description: In this article, you will learn how to establish a VPN in
       a dedicated network namespace on Linux
       
       # Introduction
       
       This guide explains how to setup a WireGuard tunnel on Linux using a
       dedicated network namespace so you can choose to run a program on the
       VPN or over clearnet.
       
       I have been able to figure the setup thanks to the following blog post,
       I enhanced it a bit using scripts and sudo rules.
       
  HTML Mo Ismailzai's blog: Creating WireGuard jails with Linux network namespaces
       
       # Explanations
       
       By default, if you connect WireGuard tunnel, its "allowedIps" field
       will be used as a route with a higher priority than your current
       default route.  It is not always ideal to have everything routed
       through a VPN, so you will create a dedicated network namespace that
       uses the VPN as a default route, without affecting all other software.
       
       Unfortunately, compared to OpenBSD rdomain (which provide the same
       features in this situation), network namespaces are much more
       complicated to deal with and requires root to run a program under a
       namespace.
       
       You will create a SAFE sudo rule to allow your user to run commands
       under the new namespace, making it more practical for daily use.
       
       # Setup
       
       ## VPN tunnel and namespace
       
       You need a wg-quick compatible WireGuard configuration file, but do not
       make it automatically used at boot.
       
       Create a script (for root use only) with the following content, then
       make it executable:
       
       ```shell
       #!/bin/sh
       
       # your VPN configuration file
       CONFIG=/etc/wireguard/my-vpn.conf
       
       # this directory is used to have a per netns resolver file
       mkdir -p /etc/netns/vpn/
       
       # cleanup any previous VPN in case you want to restart it
       ip netns exec vpn ip l del tun0
       ip netns del vpn
       
       # information to reuse later
       DNS=$(awk '/^DNS/ { print $3 }' $CONFIG)
       IP=$(awk '/^Address/ { print $3 }' $CONFIG)
       
       # the namespace will use the DNS defined in the VPN configuration file
       echo "nameserver $DNS" > /etc/netns/vpn/resolv.conf
       
       # now, it creates the namespace and configure it
       ip netns add vpn
       ip -n vpn link set lo up
       ip link add tun0 type wireguard
       ip link set tun0 netns vpn
       ip netns exec vpn wg setconf tun0 <(wg-quick strip "$CONFIG")
       ip -n vpn a add "$IP" dev tun0
       ip -n vpn link set tun0 up
       ip -n vpn route add default dev tun0
       ip -n vpn add
       
       # extra check if you want to verify the DNS used and the public IP assigned
       #ip netns exec vpn dig ifconfig.me
       #ip netns exec vpn curl https://ifconfig.me
       ```
       
       This script autoconfigure the network namespace and the VPN interface +
       the DNS server to use.  There are extra checks at the end of the script
       that you can uncomment if you want to take a look at the public IP and
       DNS resolver used just after connection.
       
       Running this script will make the netns "vpn" available for use.
       
       The command to run a program under the namespace is `ip netns exec vpn
       your command`, it can only be run as root.
       
       ## Sudo rule
       
       Now you need a specific rule so you can use sudo to run a command in
       vpn netns as your own user without having to log in as root.
       
       Add this to your sudo configuration file, in my example I allow the
       user `solene` to run commands as `solene` for the netns vpn:
       
       ```sudoers
       solene ALL=(root) NOPASSWD: /usr/sbin/ip netns exec vpn /usr/bin/sudo -u solene -- *
       ```
       
       When using this command line, you MUST use full paths exactly as in the
       sudo configuration file, this is important otherwise it would allow you
       to create a script called `ip` with whatever commands and run it as
       root, while `/usr/sbin/ip` can not be spoofed by a local script in
       $PATH.
       
       If I want a shell session with the VPN, I can run the following
       command:
       
       ```
       sudo /usr/sbin/ip netns exec vpn /usr/bin/sudo -u solene -- bash
       ```
       
       This runs bash under the netns vpn, so any command I'm running from it
       will be using the VPN.
       
       # Limitations
       
       It is not a real limitation, but you may be caught by it, if you make a
       program listening on localhost in the netns vpn, you can only connect
       to it from another program in the same namespace.  There are methods to
       connect two namespaces, but I do not plan to cover it, if you need to
       search about this setup, it can be done using socat (this is explained
       in the blog post linked earlier) or a local bridge interface.
       
       # Conclusion
       
       Network namespaces are a cool feature on Linux, but it is overly
       complicated in my opinion, unfortunately I have to deal with it, but at
       least it is working fine in practice.