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