mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-05 20:40:02 -08:00
rosenpass systemd unit file: introduce and test
This commit is contained in:
committed by
Paul Spooren
parent
d9f3c8fb96
commit
f9dce3fc9a
@@ -135,6 +135,8 @@
|
|||||||
|
|
||||||
|
|
||||||
checks = {
|
checks = {
|
||||||
|
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||||
|
|
||||||
cargo-fmt = pkgs.runCommand "check-cargo-fmt"
|
cargo-fmt = pkgs.runCommand "check-cargo-fmt"
|
||||||
{ inherit (self.devShells.${system}.default) nativeBuildInputs buildInputs; } ''
|
{ inherit (self.devShells.${system}.default) nativeBuildInputs buildInputs; } ''
|
||||||
cargo fmt --manifest-path=${./.}/Cargo.toml --check --all && touch $out
|
cargo fmt --manifest-path=${./.}/Cargo.toml --check --all && touch $out
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ in
|
|||||||
runCommandNoCC "lace-result" { } ''
|
runCommandNoCC "lace-result" { } ''
|
||||||
mkdir {bin,$out}
|
mkdir {bin,$out}
|
||||||
tar -cvf $out/rosenpass-${stdenvNoCC.hostPlatform.system}-${version}.tar \
|
tar -cvf $out/rosenpass-${stdenvNoCC.hostPlatform.system}-${version}.tar \
|
||||||
-C ${package} bin/rosenpass \
|
-C ${package} bin/rosenpass lib/systemd \
|
||||||
-C ${rp} bin/rp
|
-C ${rp} bin/rp
|
||||||
cp ${oci-image} \
|
cp ${oci-image} \
|
||||||
$out/rosenpass-oci-image-${stdenvNoCC.hostPlatform.system}-${version}.tar.gz
|
$out/rosenpass-oci-image-${stdenvNoCC.hostPlatform.system}-${version}.tar.gz
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ let
|
|||||||
extensions = [
|
extensions = [
|
||||||
"lock"
|
"lock"
|
||||||
"rs"
|
"rs"
|
||||||
|
"service"
|
||||||
|
"target"
|
||||||
"toml"
|
"toml"
|
||||||
];
|
];
|
||||||
# Files to explicitly include
|
# Files to explicitly include
|
||||||
@@ -69,6 +71,12 @@ rustPlatform.buildRustPackage {
|
|||||||
|
|
||||||
hardeningDisable = lib.optional isStatic "fortify";
|
hardeningDisable = lib.optional isStatic "fortify";
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/lib/systemd/system
|
||||||
|
install systemd/rosenpass@.service $out/lib/systemd/system
|
||||||
|
install systemd/rosenpass.target $out/lib/systemd/system
|
||||||
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
inherit (cargoToml.package) description homepage;
|
inherit (cargoToml.package) description homepage;
|
||||||
license = with lib.licenses; [ mit asl20 ];
|
license = with lib.licenses; [ mit asl20 ];
|
||||||
|
|||||||
2
systemd/rosenpass.target
Normal file
2
systemd/rosenpass.target
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Rosenpass target
|
||||||
47
systemd/rosenpass@.service
Normal file
47
systemd/rosenpass@.service
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Rosenpass key exchange for %I
|
||||||
|
Documentation=man:rosenpass(1)
|
||||||
|
Documentation=https://rosenpass.eu/docs
|
||||||
|
|
||||||
|
After=network-online.target nss-lookup.target sys-devices-virtual-net-%i.device
|
||||||
|
Wants=network-online.target nss-lookup.target
|
||||||
|
BindsTo=sys-devices-virtual-net-%i.device
|
||||||
|
PartOf=rosenpass.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=rosenpass exchange-config /etc/rosenpass/%i.toml
|
||||||
|
LoadCredential=pqsk:/etc/rosenpass/%i/pqsk
|
||||||
|
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN
|
||||||
|
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE CAP_BLOCK_SUSPEND CAP_BPF CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER CAP_IPC_LOCK CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_MKNOD CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_SYS_ADMIN CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYSLOG CAP_SYS_MODULE CAP_SYS_NICE CAP_SYS_RESOURCE CAP_SYS_PACCT CAP_SYS_PTRACE CAP_SYS_RAWIO CAP_SYS_TIME CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM
|
||||||
|
DynamicUser=true
|
||||||
|
LockPersonality=true
|
||||||
|
MemoryDenyWriteExecute=true
|
||||||
|
PrivateDevices=true
|
||||||
|
ProcSubset=pid
|
||||||
|
ProtectClock=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectHostname=true
|
||||||
|
ProtectKernelLogs=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectProc=noaccess
|
||||||
|
RestrictAddressFamilies=AF_NETLINK AF_INET AF_INET6
|
||||||
|
RestrictNamespaces=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
SystemCallFilter=~@clock
|
||||||
|
SystemCallFilter=~@cpu-emulation
|
||||||
|
SystemCallFilter=~@debug
|
||||||
|
SystemCallFilter=~@module
|
||||||
|
SystemCallFilter=~@mount
|
||||||
|
SystemCallFilter=~@obsolete
|
||||||
|
SystemCallFilter=~@privileged
|
||||||
|
SystemCallFilter=~@raw-io
|
||||||
|
SystemCallFilter=~@reboot
|
||||||
|
SystemCallFilter=~@swap
|
||||||
|
UMask=0077
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
183
tests/systemd/rosenpass.nix
Normal file
183
tests/systemd/rosenpass.nix
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# This test is largely inspired from:
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/rosenpass.nix
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/wireguard/basic.nix
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
server = {
|
||||||
|
ip4 = "192.168.0.1";
|
||||||
|
ip6 = "fd00::1";
|
||||||
|
wg = {
|
||||||
|
ip4 = "10.23.42.1";
|
||||||
|
ip6 = "fc00::1";
|
||||||
|
public = "mQufmDFeQQuU/fIaB2hHgluhjjm1ypK4hJr1cW3WqAw=";
|
||||||
|
secret = "4N5Y1dldqrpsbaEiY8O0XBUGUFf8vkvtBtm8AoOX7Eo=";
|
||||||
|
listen = 10000;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
client = {
|
||||||
|
ip4 = "192.168.0.2";
|
||||||
|
ip6 = "fd00::2";
|
||||||
|
wg = {
|
||||||
|
ip4 = "10.23.42.2";
|
||||||
|
ip6 = "fc00::2";
|
||||||
|
public = "Mb3GOlT7oS+F3JntVKiaD7SpHxLxNdtEmWz/9FMnRFU=";
|
||||||
|
secret = "uC5dfGMv7Oxf5UDfdPkj6rZiRZT2dRWp5x8IQxrNcUE=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
server_config = {
|
||||||
|
listen = [ "0.0.0.0:9999" ];
|
||||||
|
public_key = "/etc/rosenpass/rp0/pqpk";
|
||||||
|
secret_key = "/run/credentials/rosenpass@rp0.service/pqsk";
|
||||||
|
verbosity = "Verbose";
|
||||||
|
peers = [{
|
||||||
|
device = "rp0";
|
||||||
|
peer = client.wg.public;
|
||||||
|
public_key = "/etc/rosenpass/rp0/peers/client/pqpk";
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
client_config = {
|
||||||
|
listen = [ ];
|
||||||
|
public_key = "/etc/rosenpass/rp0/pqpk";
|
||||||
|
secret_key = "/run/credentials/rosenpass@rp0.service/pqsk";
|
||||||
|
verbosity = "Verbose";
|
||||||
|
peers = [{
|
||||||
|
device = "rp0";
|
||||||
|
peer = server.wg.public;
|
||||||
|
public_key = "/etc/rosenpass/rp0/peers/server/pqpk";
|
||||||
|
endpoint = "${server.ip4}:9999";
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
config = pkgs.runCommand "config" { } ''
|
||||||
|
mkdir -pv $out
|
||||||
|
cp -v ${(pkgs.formats.toml {}).generate "rp0.toml" server_config} $out/server
|
||||||
|
cp -v ${(pkgs.formats.toml {}).generate "rp0.toml" client_config} $out/client
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "rosenpass unit";
|
||||||
|
|
||||||
|
nodes =
|
||||||
|
let
|
||||||
|
shared = peer: { config, modulesPath, pkgs, ... }: {
|
||||||
|
# Need to work around a problem in recent systemd changes.
|
||||||
|
# It won't be necessary in other distros (for which the systemd file was designed), this is NixOS specific
|
||||||
|
# https://github.com/NixOS/nixpkgs/issues/258371#issuecomment-1925672767
|
||||||
|
# This can potentially be removed in future nixpkgs updates
|
||||||
|
systemd.packages = [
|
||||||
|
(pkgs.runCommand "rosenpass" { } ''
|
||||||
|
mkdir -p $out/lib/systemd/system
|
||||||
|
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass.target > $out/lib/systemd/system/rosenpass.target
|
||||||
|
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass@.service \
|
||||||
|
sed 's@^\(\[Service]\)$@\1\nEnvironment=PATH=${pkgs.wireguard-tools}/bin@' |
|
||||||
|
sed 's@^ExecStartPre=envsubst @ExecStartPre='"${pkgs.envsubst}"'/bin/envsubst @' |
|
||||||
|
sed 's@^ExecStart=rosenpass @ExecStart='"${pkgs.rosenpass}"'/bin/rosenpass @' > $out/lib/systemd/system/rosenpass@.service
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
networking.wireguard = {
|
||||||
|
enable = true;
|
||||||
|
interfaces.rp0 = {
|
||||||
|
ips = [ "${peer.wg.ip4}/32" "${peer.wg.ip6}/128" ];
|
||||||
|
privateKeyFile = "/etc/wireguard/wgsk";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
environment.etc."wireguard/wgsk".text = peer.wg.secret;
|
||||||
|
networking.interfaces.eth1 = {
|
||||||
|
ipv4.addresses = [{
|
||||||
|
address = peer.ip4;
|
||||||
|
prefixLength = 24;
|
||||||
|
}];
|
||||||
|
ipv6.addresses = [{
|
||||||
|
address = peer.ip6;
|
||||||
|
prefixLength = 64;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
server = {
|
||||||
|
imports = [ (shared server) ];
|
||||||
|
networking.firewall.allowedUDPPorts = [ 9999 server.wg.listen ];
|
||||||
|
networking.wireguard.interfaces.rp0 = {
|
||||||
|
listenPort = server.wg.listen;
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
allowedIPs = [ client.wg.ip4 client.wg.ip6 ];
|
||||||
|
publicKey = client.wg.public;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
client = {
|
||||||
|
imports = [ (shared client) ];
|
||||||
|
networking.wireguard.interfaces.rp0 = {
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
allowedIPs = [ "10.23.42.0/24" "fc00::/64" ];
|
||||||
|
publicKey = server.wg.public;
|
||||||
|
endpoint = "${server.ip4}:${toString server.wg.listen}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testScript = { ... }: ''
|
||||||
|
from os import system
|
||||||
|
rosenpass = "${pkgs.rosenpass}/bin/rosenpass"
|
||||||
|
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
for machine in [server, client]:
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
machine.wait_for_unit("network-online.target")
|
||||||
|
|
||||||
|
with subtest("Key, Config, and Service Setup"):
|
||||||
|
for name, machine, remote in [("server", server, client), ("client", client, server)]:
|
||||||
|
# generate all the keys
|
||||||
|
system(f"{rosenpass} gen-keys --public-key {name}-pqpk --secret-key {name}-pqsk")
|
||||||
|
|
||||||
|
# copy private keys to our side
|
||||||
|
machine.copy_from_host(f"{name}-pqsk", "/etc/rosenpass/rp0/pqsk")
|
||||||
|
machine.copy_from_host(f"{name}-pqpk", "/etc/rosenpass/rp0/pqpk")
|
||||||
|
|
||||||
|
# copy public keys to other side
|
||||||
|
remote.copy_from_host(f"{name}-pqpk", f"/etc/rosenpass/rp0/peers/{name}/pqpk")
|
||||||
|
|
||||||
|
machine.copy_from_host(f"${config}/{name}", "/etc/rosenpass/rp0.toml")
|
||||||
|
|
||||||
|
for machine in [server, client]:
|
||||||
|
machine.wait_for_unit("wireguard-rp0.service")
|
||||||
|
|
||||||
|
with subtest("wg network test"):
|
||||||
|
client.succeed("wg show all preshared-keys | grep none", timeout=5);
|
||||||
|
client.succeed("ping -c5 ${server.wg.ip4}")
|
||||||
|
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||||
|
|
||||||
|
with subtest("Set up rosenpass"):
|
||||||
|
for machine in [server, client]:
|
||||||
|
machine.succeed("systemctl start rosenpass@rp0.service")
|
||||||
|
|
||||||
|
for machine in [server, client]:
|
||||||
|
machine.wait_for_unit("rosenpass@rp0.service")
|
||||||
|
|
||||||
|
|
||||||
|
with subtest("compare preshared keys"):
|
||||||
|
client.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||||
|
server.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||||
|
|
||||||
|
def get_psk(m):
|
||||||
|
psk = m.succeed("wg show rp0 preshared-keys | awk '{print $2}'")
|
||||||
|
psk = psk.strip()
|
||||||
|
assert len(psk.split()) == 1, "Only one PSK"
|
||||||
|
return psk
|
||||||
|
|
||||||
|
assert get_psk(client) == get_psk(server), "preshared keys need to match"
|
||||||
|
|
||||||
|
with subtest("rosenpass network test"):
|
||||||
|
client.succeed("ping -c5 ${server.wg.ip4}")
|
||||||
|
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||||
|
'';
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user