Merge pull request #63165 from CRTified/module/initrd-ovpn
nixos/system/boot/initrd-openvpn: New openvpn options for initrd
This commit is contained in:
commit
e0f07f9b8d
@ -938,6 +938,7 @@
|
|||||||
./system/boot/grow-partition.nix
|
./system/boot/grow-partition.nix
|
||||||
./system/boot/initrd-network.nix
|
./system/boot/initrd-network.nix
|
||||||
./system/boot/initrd-ssh.nix
|
./system/boot/initrd-ssh.nix
|
||||||
|
./system/boot/initrd-openvpn.nix
|
||||||
./system/boot/kernel.nix
|
./system/boot/kernel.nix
|
||||||
./system/boot/kexec.nix
|
./system/boot/kexec.nix
|
||||||
./system/boot/loader/efi.nix
|
./system/boot/loader/efi.nix
|
||||||
|
81
nixos/modules/system/boot/initrd-openvpn.nix
Normal file
81
nixos/modules/system/boot/initrd-openvpn.nix
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
cfg = config.boot.initrd.network.openvpn;
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options = {
|
||||||
|
|
||||||
|
boot.initrd.network.openvpn.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Starts an OpenVPN client during initrd boot. It can be used to e.g.
|
||||||
|
remotely accessing the SSH service controlled by
|
||||||
|
<option>boot.initrd.network.ssh</option> or other network services
|
||||||
|
included. Service is killed when stage-1 boot is finished.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.network.openvpn.configuration = mkOption {
|
||||||
|
type = types.path; # Same type as boot.initrd.secrets
|
||||||
|
description = ''
|
||||||
|
The configuration file for OpenVPN.
|
||||||
|
|
||||||
|
<warning>
|
||||||
|
<para>
|
||||||
|
Unless your bootloader supports initrd secrets, this configuration
|
||||||
|
is stored insecurely in the global Nix store.
|
||||||
|
</para>
|
||||||
|
</warning>
|
||||||
|
'';
|
||||||
|
example = "./configuration.ovpn";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (config.boot.initrd.network.enable && cfg.enable) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.configuration != null;
|
||||||
|
message = "You should specify a configuration for initrd OpenVPN";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Add kernel modules needed for OpenVPN
|
||||||
|
boot.initrd.kernelModules = [ "tun" "tap" ];
|
||||||
|
|
||||||
|
# Add openvpn and ip binaries to the initrd
|
||||||
|
# The shared libraries are required for DNS resolution
|
||||||
|
boot.initrd.extraUtilsCommands = ''
|
||||||
|
copy_bin_and_libs ${pkgs.openvpn}/bin/openvpn
|
||||||
|
copy_bin_and_libs ${pkgs.iproute}/bin/ip
|
||||||
|
|
||||||
|
cp -pv ${pkgs.glibc}/lib/libresolv.so.2 $out/lib
|
||||||
|
cp -pv ${pkgs.glibc}/lib/libnss_dns.so.2 $out/lib
|
||||||
|
'';
|
||||||
|
|
||||||
|
boot.initrd.secrets = {
|
||||||
|
"/etc/initrd.ovpn" = cfg.configuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
# openvpn --version would exit with 1 instead of 0
|
||||||
|
boot.initrd.extraUtilsCommandsTest = ''
|
||||||
|
$out/bin/openvpn --show-gateway
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Add `iproute /bin/ip` to the config, to ensure that openvpn
|
||||||
|
# is able to set the routes
|
||||||
|
boot.initrd.network.postCommands = ''
|
||||||
|
(cat /etc/initrd.ovpn; echo -e '\niproute /bin/ip') | \
|
||||||
|
openvpn /dev/stdin &
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -151,6 +151,7 @@ in
|
|||||||
incron = handleTest ./incron.nix {};
|
incron = handleTest ./incron.nix {};
|
||||||
influxdb = handleTest ./influxdb.nix {};
|
influxdb = handleTest ./influxdb.nix {};
|
||||||
initrd-network-ssh = handleTest ./initrd-network-ssh {};
|
initrd-network-ssh = handleTest ./initrd-network-ssh {};
|
||||||
|
initrd-network-openvpn = handleTest ./initrd-network-openvpn {};
|
||||||
initrdNetwork = handleTest ./initrd-network.nix {};
|
initrdNetwork = handleTest ./initrd-network.nix {};
|
||||||
installer = handleTest ./installer.nix {};
|
installer = handleTest ./installer.nix {};
|
||||||
iodine = handleTest ./iodine.nix {};
|
iodine = handleTest ./iodine.nix {};
|
||||||
|
145
nixos/tests/initrd-network-openvpn/default.nix
Normal file
145
nixos/tests/initrd-network-openvpn/default.nix
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
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")
|
||||||
|
'';
|
||||||
|
})
|
29
nixos/tests/initrd-network-openvpn/initrd.ovpn
Normal file
29
nixos/tests/initrd-network-openvpn/initrd.ovpn
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
remote 192.168.1.3
|
||||||
|
dev tun
|
||||||
|
ifconfig 10.8.0.2 10.8.0.1
|
||||||
|
# Only force VLAN 2 through the VPN
|
||||||
|
route 192.168.2.0 255.255.255.0 10.8.0.1
|
||||||
|
secret [inline]
|
||||||
|
<secret>
|
||||||
|
#
|
||||||
|
# 2048 bit OpenVPN static key
|
||||||
|
#
|
||||||
|
-----BEGIN OpenVPN Static key V1-----
|
||||||
|
553aabe853acdfe51cd6fcfea93dcbb0
|
||||||
|
c8797deadd1187606b1ea8f2315eb5e6
|
||||||
|
67c0d7e830f50df45686063b189d6c6b
|
||||||
|
aab8bb3430cc78f7bb1f78628d5c3742
|
||||||
|
0cef4f53a5acab2894905f4499f95d8e
|
||||||
|
e69b7b6748b17016f89e19e91481a9fd
|
||||||
|
bf8c10651f41a1d4fdf5f438925a6733
|
||||||
|
13cec8f04701eb47b8f7ffc48bc3d7af
|
||||||
|
65f07bce766015b87c3db4d668c655ff
|
||||||
|
be5a69522a8e60ccb217f8521681b45d
|
||||||
|
27c0b70bdfbfbb426c7646d80adf7482
|
||||||
|
3ddac58b25cb1c1bb100de974478b4c6
|
||||||
|
8b45a94261a2405e99810cb2b3abd49f
|
||||||
|
21b3198ada87ff3c4e656a008e540a8d
|
||||||
|
e7811584363597599cce2040a68ac00e
|
||||||
|
f2125540e0f7f4adc37cb3f0d922eeb7
|
||||||
|
-----END OpenVPN Static key V1-----
|
||||||
|
</secret>
|
21
nixos/tests/initrd-network-openvpn/shared.key
Normal file
21
nixos/tests/initrd-network-openvpn/shared.key
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#
|
||||||
|
# 2048 bit OpenVPN static key
|
||||||
|
#
|
||||||
|
-----BEGIN OpenVPN Static key V1-----
|
||||||
|
553aabe853acdfe51cd6fcfea93dcbb0
|
||||||
|
c8797deadd1187606b1ea8f2315eb5e6
|
||||||
|
67c0d7e830f50df45686063b189d6c6b
|
||||||
|
aab8bb3430cc78f7bb1f78628d5c3742
|
||||||
|
0cef4f53a5acab2894905f4499f95d8e
|
||||||
|
e69b7b6748b17016f89e19e91481a9fd
|
||||||
|
bf8c10651f41a1d4fdf5f438925a6733
|
||||||
|
13cec8f04701eb47b8f7ffc48bc3d7af
|
||||||
|
65f07bce766015b87c3db4d668c655ff
|
||||||
|
be5a69522a8e60ccb217f8521681b45d
|
||||||
|
27c0b70bdfbfbb426c7646d80adf7482
|
||||||
|
3ddac58b25cb1c1bb100de974478b4c6
|
||||||
|
8b45a94261a2405e99810cb2b3abd49f
|
||||||
|
21b3198ada87ff3c4e656a008e540a8d
|
||||||
|
e7811584363597599cce2040a68ac00e
|
||||||
|
f2125540e0f7f4adc37cb3f0d922eeb7
|
||||||
|
-----END OpenVPN Static key V1-----
|
Loading…
x
Reference in New Issue
Block a user