 c684398c6a
			
		
	
	
		c684398c6a
		
	
	
	
	
		
			
			nixos/tests/initrd-openvpn: Add test for openvpn in the initramfs
The module in this commit adds new options that allows the
integration of an OpenVPN client into the initrd.
This can be used e.g. to remotely unlock LUKS devices.
This commit also adds two tests for `boot.initrd.network.openvpn`.
The first one is a basic test to validate that a failing connection
does not prevent the machine from booting.
The second test validates that this module actually creates a valid
openvpn connection.
For this, it spawns three nodes:
  - The client that uses boot.initrd.network.openvpn
  - An OpenVPN server that acts as gateway and forwards a port
    to the client
  - A node that is external to the OpenVPN network
The client connects to the OpenVPN server and spawns a netcat instance
that echos a value to every client.
Afterwards, the external node checks if it receives this value over the
forwarded port on the OpenVPN gateway.
		
	
			
		
			
				
	
	
		
			146 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| import ../make-test-python.nix ({ lib, ...}:
 | |
| 
 | |
| {
 | |
|   name = "initrd-network-openvpn";
 | |
| 
 | |
|   nodes =
 | |
|     let
 | |
| 
 | |
|       # Inlining of the shared secret for the
 | |
|       # OpenVPN server and client
 | |
|       secretblock = ''
 | |
|         secret [inline]
 | |
|         <secret>
 | |
|         ${lib.readFile ./shared.key}
 | |
|         </secret>
 | |
|         '';
 | |
| 
 | |
|     in
 | |
|     {
 | |
| 
 | |
|       # Minimal test case to check a successful boot, even with invalid config
 | |
|       minimalboot =
 | |
|         { ... }:
 | |
|         {
 | |
|           boot.initrd.network = {
 | |
|             enable = true;
 | |
|             openvpn = {
 | |
|               enable = true;
 | |
|               configuration = "/dev/null";
 | |
|             };
 | |
|           };
 | |
|         };
 | |
| 
 | |
|       # initrd VPN client
 | |
|       ovpnclient =
 | |
|         { ... }:
 | |
|         {
 | |
|           virtualisation.useBootLoader = true;
 | |
|           virtualisation.vlans = [ 1 ];
 | |
| 
 | |
|           boot.initrd = {
 | |
|             # This command does not fork to keep the VM in the state where
 | |
|             # only the initramfs is loaded
 | |
|             preLVMCommands =
 | |
|             ''
 | |
|               /bin/nc -p 1234 -lke /bin/echo TESTVALUE
 | |
|             '';
 | |
| 
 | |
|             network = {
 | |
|               enable = true;
 | |
| 
 | |
|               # Work around udhcpc only getting a lease on eth0
 | |
|               postCommands = ''
 | |
|                 /bin/ip addr add 192.168.1.2/24 dev eth1
 | |
|               '';
 | |
| 
 | |
|               # Example configuration for OpenVPN
 | |
|               # This is the main reason for this test
 | |
|               openvpn = {
 | |
|                 enable = true;
 | |
|                 configuration = "${./initrd.ovpn}";
 | |
|               };
 | |
|             };
 | |
|           };
 | |
|         };
 | |
| 
 | |
|       # VPN server and gateway for ovpnclient between vlan 1 and 2
 | |
|       ovpnserver =
 | |
|         { ... }:
 | |
|         {
 | |
|           virtualisation.vlans = [ 1 2 ];
 | |
| 
 | |
|           # Enable NAT and forward port 12345 to port 1234
 | |
|           networking.nat = {
 | |
|             enable = true;
 | |
|             internalInterfaces = [ "tun0" ];
 | |
|             externalInterface = "eth2";
 | |
|             forwardPorts = [ { destination = "10.8.0.2:1234";
 | |
|                                sourcePort = 12345; } ];
 | |
|           };
 | |
| 
 | |
|           # Trust tun0 and allow the VPN Server to be reached
 | |
|           networking.firewall = {
 | |
|             trustedInterfaces = [ "tun0" ];
 | |
|             allowedUDPPorts = [ 1194 ];
 | |
|           };
 | |
| 
 | |
|           # Minimal OpenVPN server configuration
 | |
|           services.openvpn.servers.testserver =
 | |
|           {
 | |
|             config = ''
 | |
|               dev tun0
 | |
|               ifconfig 10.8.0.1 10.8.0.2
 | |
|               ${secretblock}
 | |
|             '';
 | |
|           };
 | |
|         };
 | |
| 
 | |
|       # Client that resides in the "external" VLAN
 | |
|       testclient =
 | |
|         { ... }:
 | |
|         {
 | |
|           virtualisation.vlans = [ 2 ];
 | |
|         };
 | |
|   };
 | |
| 
 | |
| 
 | |
|   testScript =
 | |
|     ''
 | |
|       # Minimal test case, checks whether enabling (with invalid config) harms
 | |
|       # the boot process
 | |
|       with subtest("Check for successful boot with broken openvpn config"):
 | |
|           minimalboot.start()
 | |
|           # If we get to multi-user.target, we booted successfully
 | |
|           minimalboot.wait_for_unit("multi-user.target")
 | |
|           minimalboot.shutdown()
 | |
| 
 | |
|       # Elaborated test case where the ovpnclient (where this module is used)
 | |
|       # can be reached by testclient only over ovpnserver.
 | |
|       # This is an indirect test for success.
 | |
|       with subtest("Check for connection from initrd VPN client, config as file"):
 | |
|           ovpnserver.start()
 | |
|           testclient.start()
 | |
|           ovpnclient.start()
 | |
| 
 | |
|           # Wait until the OpenVPN Server is available
 | |
|           ovpnserver.wait_for_unit("openvpn-testserver.service")
 | |
|           ovpnserver.succeed("ping -c 1 10.8.0.1")
 | |
| 
 | |
|           # Wait for the client to connect
 | |
|           ovpnserver.wait_until_succeeds("ping -c 1 10.8.0.2")
 | |
| 
 | |
|           # Wait until the testclient has network
 | |
|           testclient.wait_for_unit("network.target")
 | |
| 
 | |
|           # Check that ovpnclient is reachable over vlan 1
 | |
|           ovpnserver.succeed("nc -w 2 192.168.1.2 1234 | grep -q TESTVALUE")
 | |
| 
 | |
|           # Check that ovpnclient is reachable over tun0
 | |
|           ovpnserver.succeed("nc -w 2 10.8.0.2 1234 | grep -q TESTVALUE")
 | |
| 
 | |
|           # Check that ovpnclient is reachable from testclient over the gateway
 | |
|           testclient.succeed("nc -w 2 192.168.2.3 12345 | grep -q TESTVALUE")
 | |
|     '';
 | |
| })
 |