1 import ./make-test-python.nix ({ pkgs, ... }:
8 public = "mQufmDFeQQuU/fIaB2hHgluhjjm1ypK4hJr1cW3WqAw=";
9 secret = "4N5Y1dldqrpsbaEiY8O0XBUGUFf8vkvtBtm8AoOX7Eo=";
16 public = "Mb3GOlT7oS+F3JntVKiaD7SpHxLxNdtEmWz/9FMnRFU=";
17 secret = "uC5dfGMv7Oxf5UDfdPkj6rZiRZT2dRWp5x8IQxrNcUE=";
26 shared = peer: { config, modulesPath, ... }: {
27 imports = [ "${modulesPath}/services/networking/rosenpass.nix" ];
29 boot.kernelModules = [ "wireguard" ];
31 services.rosenpass = {
33 defaultDevice = deviceName;
35 verbosity = "Verbose";
36 public_key = "/etc/rosenpass/pqpk";
37 secret_key = "/etc/rosenpass/pqsk";
41 networking.firewall.allowedUDPPorts = [ 9999 ];
45 networks."rosenpass" = {
46 matchConfig.Name = deviceName;
47 networkConfig.IPv4Forwarding = true;
48 networkConfig.IPv6Forwarding = true;
49 address = [ "${peer.ip}/64" ];
57 wireguardConfig.PrivateKeyFile = "/etc/wireguard/wgsk";
61 environment.etc."wireguard/wgsk" = {
62 text = peer.wg.secret;
63 user = "systemd-network";
64 group = "systemd-network";
70 imports = [ (shared server) ];
72 networking.firewall.allowedUDPPorts = [ server.wg.listen ];
74 systemd.network.netdevs."10-${deviceName}" = {
75 wireguardConfig.ListenPort = server.wg.listen;
78 AllowedIPs = [ "::/0" ];
79 PublicKey = client.wg.public;
84 services.rosenpass.settings = {
85 listen = [ "0.0.0.0:9999" ];
88 public_key = "/etc/rosenpass/peers/client/pqpk";
89 peer = client.wg.public;
95 imports = [ (shared client) ];
97 systemd.network.netdevs."10-${deviceName}".wireguardPeers = [
99 AllowedIPs = [ "::/0" ];
100 PublicKey = server.wg.public;
101 Endpoint = "server:${builtins.toString server.wg.listen}";
105 services.rosenpass.settings.peers = [
107 public_key = "/etc/rosenpass/peers/server/pqpk";
108 endpoint = "server:9999";
109 peer = server.wg.public;
115 testScript = { ... }: ''
116 from os import system
118 # Full path to rosenpass in the store, to avoid fiddling with `$PATH`.
119 rosenpass = "${pkgs.rosenpass}/bin/rosenpass"
121 # Path in `/etc` where keys will be placed.
122 etc = "/etc/rosenpass"
126 for machine in [server, client]:
127 machine.wait_for_unit("multi-user.target")
129 # Gently stop Rosenpass to avoid crashes during key generation/distribution.
130 for machine in [server, client]:
131 machine.execute("systemctl stop rosenpass.service")
133 for (name, machine, remote) in [("server", server, client), ("client", client, server)]:
134 pk, sk = f"{name}.pqpk", f"{name}.pqsk"
135 system(f"{rosenpass} gen-keys --force --secret-key {sk} --public-key {pk}")
136 machine.copy_from_host(sk, f"{etc}/pqsk")
137 machine.copy_from_host(pk, f"{etc}/pqpk")
138 remote.copy_from_host(pk, f"{etc}/peers/{name}/pqpk")
140 for machine in [server, client]:
141 machine.execute("systemctl start rosenpass.service")
143 for machine in [server, client]:
144 machine.wait_for_unit("rosenpass.service")
146 with subtest("ping"):
147 client.succeed("ping -c 2 -i 0.5 ${server.ip}%${deviceName}")
149 with subtest("preshared-keys"):
150 # Rosenpass works by setting the WireGuard preshared key at regular intervals.
151 # Thus, if it is not active, then no key will be set, and the output of `wg show` will contain "none".
152 # Otherwise, if it is active, then the key will be set and "none" will not be found in the output of `wg show`.
153 for machine in [server, client]:
154 machine.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5)
157 # NOTE: Below configuration is for "interactive" (=developing/debugging) only.
160 inherit (import ./ssh-keys.nix pkgs) snakeOilPublicKey snakeOilPrivateKey;
162 sshAndKeyGeneration = {
163 services.openssh.enable = true;
164 users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
165 environment.systemPackages = [
166 (pkgs.writeShellApplication {
168 runtimeInputs = [ pkgs.rosenpass ];
171 if [ "$HOST" == "server" ]
179 mkdir -vp /etc/rosenpass/peers/$PEER
180 rosenpass gen-keys --force --secret-key /etc/rosenpass/pqsk --public-key /etc/rosenpass/pqpk
184 cp ${snakeOilPrivateKey} /root/.ssh/id_ecdsa
185 chmod 0400 /root/.ssh/id_ecdsa
187 # Copy public key to other peer.
188 # shellcheck disable=SC2029
189 ssh -o StrictHostKeyChecking=no $PEER "mkdir -pv /etc/rosenpass/peers/$HOST"
190 scp /etc/rosenpass/pqpk "$PEER:/etc/rosenpass/peers/$HOST/pqpk"
196 # Use kmscon <https://www.freedesktop.org/wiki/Software/kmscon/>
197 # to provide a slightly nicer console, and while we're at it,
198 # also use a nice font.
199 # With kmscon, we can for example zoom in/out using [Ctrl] + [+]
201 niceConsoleAndAutologin.services.kmscon = {
203 autologinUser = "root";
206 package = pkgs.fira-code;
211 server = sshAndKeyGeneration // niceConsoleAndAutologin;
212 client = sshAndKeyGeneration // niceConsoleAndAutologin;