Skip to content

Instantly share code, notes, and snippets.

@sorki
Created March 8, 2021 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sorki/d81e20fac599961b09dc74f52c46fb72 to your computer and use it in GitHub Desktop.
Save sorki/d81e20fac599961b09dc74f52c46fb72 to your computer and use it in GitHub Desktop.
wireguard, nats, containers
{ system ? builtins.currentSystem
, config ? {}
, pkgs ? import <nixpkgs> { inherit system config; }
, lib ? pkgs.lib
}:
let
inherit (import "${pkgs.path}/nixos/lib/testing-python.nix" { inherit system pkgs; }) makeTest;
peer = (import ./lib/make-peer.nix) { inherit lib; };
wg-snakeoil-keys = import ./lib/wg-snakeoil-keys.nix;
# XXX
unstable = import /home/srk/git/nixpkgs/new-tests {};
in
makeTest {
name = "wireguard-nat";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ sorki ];
};
nodes = {
# wireguard server / router
peer0 = peer {
ip4 = "192.168.0.1";
ip6 = "fd00::1";
extraConfig = {
networking.nat.enable = true;
networking.nat.externalInterface = "eth1";
networking.nat.internalInterfaces = [ "wg0" ];
networking.firewall.allowedUDPPorts = [ 23542 ];
networking.wireguard.interfaces.wg0 = {
ips = [ "10.23.42.1/32" "fc00::1/128" ];
listenPort = 23542;
inherit (wg-snakeoil-keys.peer0) privateKey;
/*
postSetup = ''
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.23.42.0/24 -j MASQUERADE
'';
postShutdown = ''
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.23.42.0/24 -j MASQUERADE
'';
*/
peers = [
{ allowedIPs = [ "10.23.42.2/32" "fc00::2/128" ];
inherit (wg-snakeoil-keys.peer1) publicKey;
}
{ allowedIPs = [ "10.23.42.3/32" "fc00::3/128" ];
inherit (wg-snakeoil-keys.peer2) publicKey;
}
{ allowedIPs = [ "10.23.42.4/32" "fc00::4/128" ];
inherit (wg-snakeoil-keys.peer3) publicKey;
}
{ allowedIPs = [ "10.23.42.5/32" "fc00::5/128" ];
inherit (wg-snakeoil-keys.peer4) publicKey;
}
{ allowedIPs = [ "10.23.42.6/32" "fc00::6/128" ];
inherit (wg-snakeoil-keys.peer5) publicKey;
}
];
};
};
};
# peer with nixos container
# and internal ipv6 access
peer1 = peer {
ip6 = "fd00::2";
extraConfig = {
networking.wireguard.interfaces.wg0 = {
ips = [ "10.23.42.2/32" "fc00::2/128" ];
allowedIPsAsRoutes = true;
inherit (wg-snakeoil-keys.peer1) privateKey;
peers = lib.singleton {
allowedIPs = [ "0.0.0.0/0" "::/0" ];
endpoint = "[fd00::1]:23542";
persistentKeepalive = 25;
inherit (wg-snakeoil-keys.peer0) publicKey;
};
};
# XXX
environment.systemPackages = [ unstable.cntr ];
networking.nat.enable = true;
networking.nat.enableIPv6 = true;
networking.nat.externalInterface = "wg0";
networking.nat.internalInterfaces = [ "ve-+" ];
containers.test = {
autoStart = true;
privateNetwork = true;
hostAddress = "172.16.0.1";
localAddress = "172.16.0.2";
hostAddress6 = "fa00::1";
localAddress6 = "fa00::2";
config = {};
};
};
};
# docker
peer2 = peer {
ip6 = "fd00::3";
extraConfig = {
networking.wireguard.interfaces.wg0 = {
ips = [ "10.23.42.3/32" "fc00::3/128" ];
allowedIPsAsRoutes = true;
inherit (wg-snakeoil-keys.peer2) privateKey;
peers = lib.singleton {
allowedIPs = [ "0.0.0.0/0" "::/0" ];
endpoint = "[fd00::1]:23542";
persistentKeepalive = 25;
inherit (wg-snakeoil-keys.peer0) publicKey;
};
};
# XXX
environment.systemPackages = [ unstable.cntr ];
networking.nat.enable = true;
networking.nat.enableIPv6 = true;
networking.nat.externalInterface = "wg0";
networking.nat.internalInterfaces = [ "docker+" ];
virtualisation.docker.extraOptions = "--ipv6 --fixed-cidr-v6=fa00:dac:1::/64 --iptables=false";
virtualisation.oci-containers = {
backend = "docker";
containers.nginx = {
image = "nginx-container";
imageFile = pkgs.dockerTools.examples.nginx;
ports = ["8181:80"];
};
};
};
};
# some service, only tunnel v4/24 in allowed IPs
peer3 = peer {
ip4 = "192.168.0.4";
ip6 = "fd00::4";
extraConfig = {
networking.wireguard.interfaces.wg0 = {
ips = [ "10.23.42.4/32" "fc00::4/128" ];
allowedIPsAsRoutes = true;
inherit (wg-snakeoil-keys.peer3) privateKey;
peers = lib.singleton {
allowedIPs = [ "10.23.42.0/24" ];
endpoint = "[fd00::1]:23542";
persistentKeepalive = 25;
inherit (wg-snakeoil-keys.peer0) publicKey;
};
};
};
};
# some service, everything thru tunnel
peer4 = peer {
ip4 = "192.168.0.5";
ip6 = "fd00::5";
extraConfig = {
networking.wireguard.interfaces.wg0 = {
ips = [ "10.23.42.5/32" "fc00::5/128" ];
allowedIPsAsRoutes = true;
inherit (wg-snakeoil-keys.peer4) privateKey;
peers = lib.singleton {
allowedIPs = [ "0.0.0.0/0" "::/0" ];
endpoint = "[fd00::1]:23542";
persistentKeepalive = 25;
inherit (wg-snakeoil-keys.peer0) publicKey;
};
};
};
};
# podman
# no wan v4, all v4 thru tunnel
# only lan v6 thru tunnel
peer5 = peer {
ip6 = "fd00::6";
extraConfig = {
networking.wireguard.interfaces.wg0 = {
ips = [ "10.23.42.6/32" "fc00::6/128" ];
allowedIPsAsRoutes = true;
inherit (wg-snakeoil-keys.peer5) privateKey;
peers = lib.singleton {
allowedIPs = [ "0.0.0.0/0" "fc00::/64" ];
endpoint = "[fd00::1]:23542";
persistentKeepalive = 25;
inherit (wg-snakeoil-keys.peer0) publicKey;
};
};
# XXX
environment.systemPackages = [ unstable.cntr ];
environment.etc."cni/net.d/10-podman-ipv6-bridge.conflist".text = builtins.readFile ./10-podman-ipv6-bridge.conflist;
virtualisation.oci-containers = {
backend = "podman";
containers.nginx = {
image = "nginx-container";
imageFile = pkgs.dockerTools.examples.nginx;
ports = ["8181:80"];
extraOptions = [ "--network=podman-ipv6" ];
};
};
};
};
# only part of hosts network, no wireguard peering
external = peer {
ip4 = "192.168.0.10";
ip6 = "fd00::10";
extraConfig = { };
};
};
testScript = ''
start_all()
peer0.wait_for_unit("wireguard-wg0.service")
peer1.wait_for_unit("wireguard-wg0.service")
peer2.wait_for_unit("wireguard-wg0.service")
peer3.wait_for_unit("wireguard-wg0.service")
peer4.wait_for_unit("wireguard-wg0.service")
peer5.wait_for_unit("wireguard-wg0.service")
def inspectPeer(num):
p = getattr(sys.modules[__name__], "peer{}".format(num))
print("Peer {}".format(num))
print(p.succeed("ip a"))
print(p.succeed("ip r"))
print(p.succeed("ip -6 a"))
print(p.succeed("ip -6 r"))
print(p.succeed("wg"))
inspectPeer(0)
peer1.succeed("ping -c1 fc00::2")
peer1.succeed("ping -c1 fc00::3")
peer1.fail("ping -c1 fc00::4")
peer1.succeed("ping -c1 fc00::5")
peer1.succeed("ping -c1 fc00::6")
inspectPeer(1)
# wg v6 allowed
peer1.succeed("ping -c1 fc00::1")
peer1.succeed("ping -c1 fd00::1")
peer1.succeed("ping -c1 10.23.42.1")
# we can reach external via wg
peer1.succeed("ping -c1 192.168.0.10")
print(peer1.succeed("ls -l $( which cntr )"))
peer1.wait_for_unit("container@test.service")
peer1.succeed("cntr attach test sh -- -c 'ping -c1 10.23.42.1'")
peer1.succeed("cntr attach test sh -- -c 'ping -c1 192.168.0.10'")
peer1.succeed("cntr attach test sh -- -c 'ping -c1 fc00::1'")
# our localhost
peer1.succeed("cntr attach test sh -- -c 'ping -c1 fd00::2'")
# cannot ping this one as there's a more specific route out of eth1
# but why it works from host?!
# proly because NAT has external wg and route points to eth1
peer1.fail("cntr attach test sh -- -c 'ping -c1 fd00::1'")
inspectPeer(2)
peer2.succeed("ping -c1 fc00::1")
peer2.succeed("ping -c1 fd00::1")
peer2.succeed("ping -c1 10.23.42.1")
peer2.succeed("ping -c1 fd00::2")
peer2.succeed("ping -c1 10.23.42.2")
peer2.wait_for_unit("docker-nginx.service")
peer2.sleep(1)
peer2.succeed("cntr attach -t docker nginx sh -- -c 'ping -c1 192.168.0.10'")
peer2.succeed("cntr attach -t docker nginx sh -- -c 'ping -c1 fc00::1'")
inspectPeer(3)
peer3.succeed("ping -c1 fd00::1")
peer3.succeed("ping -c1 10.23.42.1")
peer3.succeed("ping -c1 10.23.42.2")
peer3.succeed("ping -c1 10.23.42.3")
inspectPeer(4)
peer4.succeed("ping -c1 fc00::1")
peer4.succeed("ping -c1 fd00::1")
peer4.succeed("ping -c1 10.23.42.1")
peer4.succeed("ping -c1 10.23.42.2")
peer4.succeed("ping -c1 10.23.42.3")
inspectPeer(5)
peer5.succeed("ping -c1 fc00::1")
peer5.succeed("ping -c1 fc00::2")
peer5.succeed("ping -c1 fc00::3")
peer5.succeed("ping -c1 fd00::1")
peer5.succeed("ping -c1 10.23.42.1")
peer5.succeed("ping -c1 10.23.42.2")
peer5.succeed("ping -c1 10.23.42.3")
peer5.wait_for_unit("podman-nginx.service")
peer5.sleep(1)
peer5.succeed("cntr attach -t podman nginx sh -- -c 'ping -c1 192.168.0.10'")
peer5.succeed("cntr attach -t podman nginx sh -- -c 'ping -c1 fc00::1'")
peer5.succeed("cntr attach -t podman nginx sh -- -c 'ping -c1 fd00::1'")
peer5.succeed("cntr attach -t podman nginx sh -- -c 'ping -c1 fd00::10'")
'';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment