Created
August 10, 2021 13:29
-
-
Save c0deaddict/53aedbb69c8cbfebfec8f4428dc03102 to your computer and use it in GitHub Desktop.
NixOS container in Wireguard VPN network namespace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ lib, config, pkgs, ... }: | |
with lib; | |
let | |
veth = "veth-vpn"; | |
hostIp = "10.0.0.1/24"; | |
guestIp = "10.0.0.2/24"; | |
in | |
{ | |
sops.secrets = { | |
wireguard-vpn-private-key = { sopsFile = ./secrets.yaml; }; | |
}; | |
# https://mth.st/blog/nixos-wireguard-netns/ | |
systemd.services."netns@" = { | |
description = "%I network namespace"; | |
before = ["network.target"]; | |
serviceConfig = { | |
Type = "oneshot"; | |
RemainAfterExit = true; | |
PrivateNetwork = true; | |
ExecStart = "${pkgs.writers.writeDash "netns-up" '' | |
${pkgs.iproute}/bin/ip netns add $1 | |
${pkgs.utillinux}/bin/umount /var/run/netns/$1 | |
${pkgs.utillinux}/bin/mount --bind /proc/self/ns/net /var/run/netns/$1 | |
''} %I"; | |
ExecStop = "${pkgs.iproute}/bin/ip netns del %I"; | |
}; | |
}; | |
systemd.services."wireguard-wg0" = { | |
bindsTo = ["[email protected]"]; | |
after = ["[email protected]"]; | |
}; | |
networking.wireguard.interfaces = { | |
wg0 = { | |
ips = [ "10.0.0.2/32" ]; | |
privateKeyFile = config.sops.secrets.wireguard-vpn-private-key.path; | |
socketNamespace = "init"; | |
interfaceNamespace = "vpn"; | |
peers = [{ | |
publicKey = "<<wireguard pubkey>>" | |
# Forward all traffic via VPN. | |
allowedIPs = [ "0.0.0.0/0" "::/0" ]; | |
endpoint = "my.vpn-provider.com:51820"; | |
persistentKeepalive = 15; | |
}]; | |
}; | |
}; | |
# https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking#veth | |
systemd.services.${veth} = let | |
ns = "vpn"; | |
ipHost = "${pkgs.iproute}/bin/ip"; | |
ipGuest = "${ipHost} netns exec ${ns} ${pkgs.iproute}/bin/ip"; | |
in { | |
description = "Veth interface for download"; | |
bindsTo = [ "netns@${ns}.service" ]; | |
after = [ "netns@${ns}.service" ]; | |
wantedBy = [ "network.target" ]; | |
serviceConfig = { | |
Type = "oneshot"; | |
RemainAfterExit = true; | |
ExecStart = pkgs.writers.writeDash "veth-up" '' | |
${ipHost} link add ${veth} type veth peer name veth1 netns ${ns} | |
${ipHost} addr add ${hostIp} dev ${veth} | |
${ipHost} link set dev ${veth} up | |
${ipGuest} addr add ${guestIp} dev veth1 | |
${ipGuest} link set dev veth1 up | |
''; | |
ExecStop = pkgs.writers.writeDash "veth-down" '' | |
${ipHost} link del ${veth} | |
''; | |
}; | |
}; | |
systemd.services."container@download" = { | |
bindsTo = [ "${veth}.service" ]; | |
after = [ "${veth}.service" ]; | |
}; | |
containers.test = { | |
autoStart = true; | |
extraFlags = [ "--network-namespace-path=/run/netns/vpn" ]; | |
bindMounts = { | |
"/etc/resolv.conf" = { | |
hostPath = toString (pkgs.writeText "resolv.conf" '' | |
nameserver 9.9.9.9 | |
nameserver 1.1.1.1 | |
''); | |
isReadOnly = true; | |
}; | |
}; | |
config = { config, pkgs, ... }: { | |
environment.systemPackages = with pkgs; [ | |
wireguard | |
traceroute | |
ldns | |
]; | |
}; | |
}; | |
systemd.services."test" = { | |
description = "Test container in VPN namespace"; | |
bindsTo = [ "wireguard-wg0.service"]; | |
after = [ "wireguard-wg0.service" "[email protected]" "${veth}.service"]; | |
unitConfig.JoinsNamespaceOf = "[email protected]"; | |
serviceConfig = { | |
Type = "simple"; | |
ExecStart = pkgs.writers.writeDash "test" '' | |
cat /etc/resolv.conf | |
${pkgs.ldns}/bin/drill google.nl | |
${pkgs.traceroute}/bin/traceroute google.nl | |
tail -f /dev/null | |
''; | |
PrivateNetwork = true; | |
BindReadOnlyPaths = let | |
resolv = pkgs.writeText "resolv.conf" '' | |
nameserver 9.9.9.9 | |
nameserver 1.1.1.1 | |
''; | |
in [ "${resolv}:/etc/resolv.conf" ]; | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment