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})