1import ../make-test-python.nix ({ lib, ...}: 2 3{ 4 name = "initrd-network-openvpn"; 5 6 nodes = 7 let 8 9 # Inlining of the shared secret for the 10 # OpenVPN server and client 11 secretblock = '' 12 secret [inline] 13 <secret> 14 ${lib.readFile ./shared.key} 15 </secret> 16 ''; 17 18 in 19 { 20 21 # Minimal test case to check a successful boot, even with invalid config 22 minimalboot = 23 { ... }: 24 { 25 boot.initrd.network = { 26 enable = true; 27 openvpn = { 28 enable = true; 29 configuration = "/dev/null"; 30 }; 31 }; 32 }; 33 34 # initrd VPN client 35 ovpnclient = 36 { ... }: 37 { 38 virtualisation.useBootLoader = true; 39 virtualisation.vlans = [ 1 ]; 40 41 boot.initrd = { 42 # This command does not fork to keep the VM in the state where 43 # only the initramfs is loaded 44 preLVMCommands = 45 '' 46 /bin/nc -p 1234 -lke /bin/echo TESTVALUE 47 ''; 48 49 network = { 50 enable = true; 51 52 # Work around udhcpc only getting a lease on eth0 53 postCommands = '' 54 /bin/ip addr add 192.168.1.2/24 dev eth1 55 ''; 56 57 # Example configuration for OpenVPN 58 # This is the main reason for this test 59 openvpn = { 60 enable = true; 61 configuration = "${./initrd.ovpn}"; 62 }; 63 }; 64 }; 65 }; 66 67 # VPN server and gateway for ovpnclient between vlan 1 and 2 68 ovpnserver = 69 { ... }: 70 { 71 virtualisation.vlans = [ 1 2 ]; 72 73 # Enable NAT and forward port 12345 to port 1234 74 networking.nat = { 75 enable = true; 76 internalInterfaces = [ "tun0" ]; 77 externalInterface = "eth2"; 78 forwardPorts = [ { destination = "10.8.0.2:1234"; 79 sourcePort = 12345; } ]; 80 }; 81 82 # Trust tun0 and allow the VPN Server to be reached 83 networking.firewall = { 84 trustedInterfaces = [ "tun0" ]; 85 allowedUDPPorts = [ 1194 ]; 86 }; 87 88 # Minimal OpenVPN server configuration 89 services.openvpn.servers.testserver = 90 { 91 config = '' 92 dev tun0 93 ifconfig 10.8.0.1 10.8.0.2 94 ${secretblock} 95 ''; 96 }; 97 }; 98 99 # Client that resides in the "external" VLAN 100 testclient = 101 { ... }: 102 { 103 virtualisation.vlans = [ 2 ]; 104 }; 105 }; 106 107 108 testScript = 109 '' 110 # Minimal test case, checks whether enabling (with invalid config) harms 111 # the boot process 112 with subtest("Check for successful boot with broken openvpn config"): 113 minimalboot.start() 114 # If we get to multi-user.target, we booted successfully 115 minimalboot.wait_for_unit("multi-user.target") 116 minimalboot.shutdown() 117 118 # Elaborated test case where the ovpnclient (where this module is used) 119 # can be reached by testclient only over ovpnserver. 120 # This is an indirect test for success. 121 with subtest("Check for connection from initrd VPN client, config as file"): 122 ovpnserver.start() 123 testclient.start() 124 ovpnclient.start() 125 126 # Wait until the OpenVPN Server is available 127 ovpnserver.wait_for_unit("openvpn-testserver.service") 128 ovpnserver.succeed("ping -c 1 10.8.0.1") 129 130 # Wait for the client to connect 131 ovpnserver.wait_until_succeeds("ping -c 1 10.8.0.2") 132 133 # Wait until the testclient has network 134 testclient.wait_for_unit("network.target") 135 136 # Check that ovpnclient is reachable over vlan 1 137 ovpnserver.succeed("nc -w 2 192.168.1.2 1234 | grep -q TESTVALUE") 138 139 # Check that ovpnclient is reachable over tun0 140 ovpnserver.succeed("nc -w 2 10.8.0.2 1234 | grep -q TESTVALUE") 141 142 # Check that ovpnclient is reachable from testclient over the gateway 143 testclient.succeed("nc -w 2 192.168.2.3 12345 | grep -q TESTVALUE") 144 ''; 145})