From 887d3c8a343dda90c9e654521678a50f0f7d42a6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 4 Nov 2023 00:29:56 +0000 Subject: [PATCH 1/4] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/44881e03af1c730cbb1d72a4d41274a2c957813a' (2023-10-21) → 'github:NixOS/nixpkgs/27ead4fec31f241baed776d046b1dcac431a5919' (2023-11-03) • Updated input 'sops-nix': 'github:Mic92/sops-nix/51186b8012068c417dac7c31fb12861726577898' (2023-10-15) → 'github:Mic92/sops-nix/275b28593ef3a1b9d05b6eeda3ddce2f45f5c06f' (2023-11-03) • Updated input 'sops-nix/nixpkgs-stable': 'github:NixOS/nixpkgs/0e1cff585c1a85aeab059d3109f66134a8f76935' (2023-10-15) → 'github:NixOS/nixpkgs/d87c5d8c41c9b3b39592563242f3a448b5cc4bc9' (2023-10-29) • Updated input 'treefmt-nix': 'github:numtide/treefmt-nix/aae39f64f5ecbe89792d05eacea5cb241891292a' (2023-10-15) → 'github:numtide/treefmt-nix/5deb8dc125a9f83b65ca86cf0c8167c46593e0b1' (2023-10-27) --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index c5556b2a..68d6c7de 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1697886341, - "narHash": "sha256-AdE67xPty9M9wn36nPVp6aDntIdigrs7UbyaGv1VAaM=", + "lastModified": 1699034771, + "narHash": "sha256-S0iAvl1oETS6cVFP7aVNodY9eMnbaTtuypi0XiGXiLg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "44881e03af1c730cbb1d72a4d41274a2c957813a", + "rev": "27ead4fec31f241baed776d046b1dcac431a5919", "type": "github" }, "original": { @@ -38,11 +38,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1697332183, - "narHash": "sha256-ACYvYsgLETfEI2xM1jjp8ZLVNGGC0onoCGe+69VJGGE=", + "lastModified": 1698544399, + "narHash": "sha256-vhRmPyEyoPkrXF2iykBsWHA05MIaOSmMRLMF7Hul6+s=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0e1cff585c1a85aeab059d3109f66134a8f76935", + "rev": "d87c5d8c41c9b3b39592563242f3a448b5cc4bc9", "type": "github" }, "original": { @@ -69,11 +69,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1697339241, - "narHash": "sha256-ITsFtEtRbCBeEH9XrES1dxZBkE1fyNNUfIyQjQ2AYQs=", + "lastModified": 1699021419, + "narHash": "sha256-oy2j2OHXYcckifASMeZzpmbDLSvobMGt0V/RvoDotF4=", "owner": "Mic92", "repo": "sops-nix", - "rev": "51186b8012068c417dac7c31fb12861726577898", + "rev": "275b28593ef3a1b9d05b6eeda3ddce2f45f5c06f", "type": "github" }, "original": { @@ -104,11 +104,11 @@ ] }, "locked": { - "lastModified": 1697388351, - "narHash": "sha256-63N2eBpKaziIy4R44vjpUu8Nz5fCJY7okKrkixvDQmY=", + "lastModified": 1698438538, + "narHash": "sha256-AWxaKTDL3MtxaVTVU5lYBvSnlspOS0Fjt8GxBgnU0Do=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "aae39f64f5ecbe89792d05eacea5cb241891292a", + "rev": "5deb8dc125a9f83b65ca86cf0c8167c46593e0b1", "type": "github" }, "original": { From 4077c2c6f8a766579976f1240b7c255e66a02e14 Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Mon, 23 Oct 2023 16:00:32 +0200 Subject: [PATCH 2/4] rosenpass: Update with comments from Nixpkgs PR See https://github.com/NixOS/nixpkgs/pull/254813 --- flake.nix | 2 + modules/rosenpass.nix | 309 ++++++++++++++--------- pkgs/by-name/rosenpass-tools/package.nix | 30 ++- pkgs/by-name/rosenpass/package.nix | 45 ++-- tests/pretalx/default.nix | 1 + tests/rosenpass/default.nix | 89 ++++--- 6 files changed, 271 insertions(+), 205 deletions(-) diff --git a/flake.nix b/flake.nix index 8ad928c2..31d98cf4 100644 --- a/flake.nix +++ b/flake.nix @@ -39,6 +39,8 @@ in mapAttrs (name: _: pkgs.nixosTest (import (dir + "/${name}") { + inherit pkgs; + inherit (pkgs) lib; modules = extendedModules; configurations = importNixosConfigurations; })) (readDir dir) diff --git a/modules/rosenpass.nix b/modules/rosenpass.nix index 711c6e50..257c1d4d 100644 --- a/modules/rosenpass.nix +++ b/modules/rosenpass.nix @@ -4,175 +4,232 @@ options, pkgs, ... -}: -with builtins; -with lib; let +}: let + inherit + (lib) + attrValues + concatLines + concatMap + filter + filterAttrsRecursive + flatten + getExe + mdDoc + mkIf + optional + ; + cfg = config.services.rosenpass; opt = options.services.rosenpass; + settingsFormat = pkgs.formats.toml {}; in { - options.services.rosenpass = with types; { - enable = mkEnableOption "Whether to enable the Rosenpass service to provide post-quantum secure key exchange for WireGuard."; - - package = mkPackageOption pkgs "rosenpass" {}; - - user = mkOption { - type = str; - default = "rosenpass"; - description = "User to run Rosenpass as."; - }; - - group = mkOption { - type = str; - default = "rosenpass"; - description = "Primary group of the user running Rosenpass."; - }; - - publicKeyFile = mkOption { - type = path; - description = "Path to a file containing the public key of the local Rosenpass peer. Generate this by running `rosenpass gen-keys`."; - }; - - secretKeyFile = mkOption { - type = path; - description = "Path to a file containing the secret key of the local Rosenpass peer. Generate this by running `rosenpass gen-keys`."; - }; + options.services.rosenpass = let + inherit + (lib) + literalExpression + mdDoc + mkOption + ; + inherit + (lib.types) + enum + listOf + nullOr + path + str + submodule + ; + in { + enable = lib.mkEnableOption (mdDoc "Rosenpass"); + + package = lib.mkPackageOption pkgs "rosenpass" {}; defaultDevice = mkOption { type = nullOr str; - description = "Name of the network interface to use for all peers by default."; + description = mdDoc "Name of the network interface to use for all peers by default."; example = "wg0"; }; - listen = mkOption { - type = listOf str; - description = "List of local endpoints to listen for connections."; - default = []; - example = literalExpression "[ \"0.0.0.0:10000\" ]"; - }; - - verbosity = mkOption { - type = enum ["Verbose" "Quiet"]; - default = "Quiet"; - description = "Verbosity of output produced by the service."; - }; + settings = mkOption { + type = submodule { + freeformType = settingsFormat.type; - peers = let - peer = submodule { options = { - publicKeyFile = mkOption { + public_key = mkOption { type = path; - description = "Path to a file containing the public key of the remote Rosenpass peer."; + description = mdDoc "Path to a file containing the public key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`."; }; - endpoint = mkOption { - type = nullOr str; - default = null; - description = "Endpoint of the remote Rosenpass peer."; + secret_key = mkOption { + type = path; + description = mdDoc "Path to a file containing the secret key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`."; + }; + + listen = mkOption { + type = listOf str; + description = mdDoc "List of local endpoints to listen for connections."; + default = []; + example = literalExpression "[ \"0.0.0.0:10000\" ]"; }; - device = mkOption { - type = str; - default = cfg.defaultDevice; - defaultText = literalExpression "config.${opt.defaultDevice}"; - description = "Name of the local WireGuard interface to use for this peer."; + verbosity = mkOption { + type = enum ["Verbose" "Quiet"]; + default = "Quiet"; + description = mdDoc "Verbosity of output produced by the service."; }; - wireguard = mkOption { - type = submodule { + peers = let + peer = submodule { + freeformType = settingsFormat.type; + options = { - publicKey = mkOption { + public_key = mkOption { + type = path; + description = mdDoc "Path to a file containing the public key of the remote Rosenpass peer."; + }; + + endpoint = mkOption { + type = nullOr str; + default = null; + description = mdDoc "Endpoint of the remote Rosenpass peer."; + }; + + device = mkOption { + type = str; + default = cfg.defaultDevice; + defaultText = literalExpression "config.${opt.defaultDevice}"; + description = mdDoc "Name of the local WireGuard interface to use for this peer."; + }; + + peer = mkOption { type = str; - description = "WireGuard public key corresponding to the remote Rosenpass peer."; + description = mdDoc "WireGuard public key corresponding to the remote Rosenpass peer."; }; }; }; - description = "WireGuard configuration for this peer."; - }; + in + mkOption { + type = listOf peer; + description = mdDoc "List of peers to exchange keys with."; + default = []; + }; }; }; - in - mkOption { - type = listOf peer; - description = "List of peers to exchange keys with."; - default = []; - }; - - extraConfig = mkOption { - type = attrs; - description = '' - Extra configuration to be merged with the generated Rosenpass configuration file. - ''; default = {}; + description = mdDoc "Configuration for Rosenpass, see for further information."; }; }; config = mkIf cfg.enable { warnings = let - netdevsList = attrValues config.systemd.network.netdevs; - publicKeyInNetdevs = peer: any (netdev: any (publicKeyInWireguardPeers peer) netdev.wireguardPeers) netdevsList; - publicKeyInWireguardPeers = peer: x: x.wireguardPeerConfig ? PublicKey && x.wireguardPeerConfig.PublicKey == peer.wireguard.publicKey; - - # NOTE: In the message below, we tried to refer to - # options.systemd.network.netdevs."".wireguardPeers.*.PublicKey + # NOTE: In the descriptions below, we tried to refer to e.g. + # options.systemd.network.netdevs."".wireguardPeers.*.PublicKey # directly, but don't know how to traverse "" and * in this path. - warningMsg = peer: "It appears that you have configured a Rosenpass peer with the Wireguard public key '${peer.wireguard.publicKey}' but there is no corresponding Wireguard peer configuration in any of `${options.systemd.network.netdevs}.\"\".wireguardPeers.*.PublicKey`. While this may work as expected, such a scenario is unusual. Please double-check your configuration."; + extractions = [ + { + relevant = config.systemd.network.enable; + root = config.systemd.network.netdevs; + peer = x: x.wireguardPeers; + key = x: + if x.wireguardPeerConfig ? PublicKey + then x.wireguardPeerConfig.PublicKey + else null; + description = mdDoc "${options.systemd.network.netdevs}.\"\".wireguardPeers.*.wireguardPeerConfig.PublicKey"; + } + { + relevant = config.networking.wireguard.enable; + root = config.networking.wireguard.interfaces; + peer = x: x.peers; + key = x: x.publicKey; + description = mdDoc "${options.networking.wireguard.interfaces}.\"\".peers.*.publicKey"; + } + rec { + relevant = root != {}; + root = config.networking.wg-quick.interfaces; + peer = x: x.peers; + key = x: x.publicKey; + description = mdDoc "${options.networking.wg-quick.interfaces}.\"\".peers.*.publicKey"; + } + ]; + relevantExtractions = filter (x: x.relevant) extractions; + extract = { + root, + peer, + key, + ... + }: + filter (x: x != null) (flatten (concatMap (x: (map key (peer x))) (attrValues root))); + configuredKeys = flatten (map extract relevantExtractions); + itemize = xs: concatLines (map (x: " - ${x}") xs); + descriptions = map (x: "`${x.description}`"); + missingKeys = filter (key: !builtins.elem key configuredKeys) (map (x: x.peer) cfg.settings.peers); + unusual = '' + While this may work as expected, e.g. you want to manually configure WireGuard, + such a scenario is unusual. Please double-check your configuration. + ''; in - concatMap (peer: optional (!publicKeyInNetdevs peer) (warningMsg peer)) cfg.peers; + (optional (relevantExtractions != [] && missingKeys != []) '' + You have configured Rosenpass peers with the WireGuard public keys: + ${itemize missingKeys} + But there is no corresponding active Wireguard peer configuration in any of: + ${itemize (descriptions relevantExtractions)} + ${unusual} + '') + ++ optional (relevantExtractions == []) '' + You have configured Rosenpass, but you have not configured Wireguard via any of: + ${itemize (descriptions extractions)} + ${unusual} + ''; environment.systemPackages = [cfg.package pkgs.wireguard-tools]; - users.users."${cfg.user}" = { - isSystemUser = true; - createHome = false; - group = cfg.group; - }; - - users.groups."${cfg.group}" = {}; - - # NOTE: It would be possible to use systemd credentials for pqsk. - # systemd.services.rosenpass = let - generatePeerConfig = { - publicKeyFile, - endpoint, - device, - wireguard, - }: - { - inherit device; - public_key = publicKeyFile; - peer = wireguard.publicKey; - extra_params = []; - } - // (optionalAttrs (endpoint != null) {inherit endpoint;}); - - generateConfig = { - publicKeyFile, - secretKeyFile, - listen, - verbosity, - peers, - ... - }: { - inherit listen verbosity; - public_key = publicKeyFile; - secret_key = secretKeyFile; - peers = map generatePeerConfig peers; - }; - toml = pkgs.formats.toml {}; - configFile = toml.generate "config.toml" (recursiveUpdate (generateConfig cfg) cfg.extraConfig); - in { + filterNonNull = filterAttrsRecursive (_: v: v != null); + config = settingsFormat.generate "config.toml" ( + filterNonNull ( + cfg.settings + // ( + let + credentialPath = id: "$CREDENTIALS_DIRECTORY/${id}"; + # NOTE: We would like to remove all `null` values inside `cfg.settings` + # recursively, since `settingsFormat.generate` cannot handle `null`. + # This would require to traverse both attribute sets and lists recursively. + # `filterAttrsRecursive` only recurses into attribute sets, but not + # into values that might contain other attribute sets (such as lists, + # e.g. `cfg.settings.peers`). Here, we just specialize on `cfg.settings.peers`, + # and this may break unexpectedly whenever a `null` value is contained + # in a list in `cfg.settings`, other than `cfg.settings.peers`. + peersWithoutNulls = map filterNonNull cfg.settings.peers; + in { + secret_key = credentialPath "pqsk"; + public_key = credentialPath "pqpk"; + peers = peersWithoutNulls; + } + ) + ) + ); + in rec { wantedBy = ["multi-user.target"]; after = ["network-online.target"]; - path = [pkgs.wireguard-tools]; - - script = "${cfg.package}/bin/rosenpass exchange-config ${configFile}"; + path = [cfg.package pkgs.wireguard-tools]; serviceConfig = { - User = cfg.user; - Group = cfg.group; + User = "rosenpass"; + Group = "rosenpass"; + RuntimeDirectory = "rosenpass"; + DynamicUser = true; AmbientCapabilities = ["CAP_NET_ADMIN"]; + LoadCredential = [ + "pqsk:${cfg.settings.secret_key}" + "pqpk:${cfg.settings.public_key}" + ]; }; + + # See + environment.CONFIG = "%t/${serviceConfig.RuntimeDirectory}/config.toml"; + + preStart = "${getExe pkgs.envsubst} -i ${config} -o \"$CONFIG\""; + script = "rosenpass exchange-config \"$CONFIG\""; }; }; } diff --git a/pkgs/by-name/rosenpass-tools/package.nix b/pkgs/by-name/rosenpass-tools/package.nix index 2ecc50ff..35a7fe6c 100644 --- a/pkgs/by-name/rosenpass-tools/package.nix +++ b/pkgs/by-name/rosenpass-tools/package.nix @@ -1,7 +1,8 @@ { lib, - makeWrapper, stdenv, + makeWrapper, + installShellFiles, coreutils, findutils, gawk, @@ -9,27 +10,28 @@ wireguard-tools, }: stdenv.mkDerivation { - pname = "rosenpass-tools"; inherit (rosenpass) version src; + pname = "rosenpass-tools"; - nativeBuildInputs = [makeWrapper]; + nativeBuildInputs = [makeWrapper installShellFiles]; - postInstall = let - rpDependencies = [ + postInstall = '' + install -D $src/rp $out/bin/rp + installManPage $src/doc/rp.1 + wrapProgram $out/bin/rp \ + --prefix PATH : ${lib.makeBinPath [ coreutils findutils gawk rosenpass wireguard-tools - ]; - in '' - install -D $src/rp $out/bin/rp - install -D $src/doc/rp.1 $out/share/man/man1/rp.1 - wrapProgram $out/bin/rp --prefix PATH : ${lib.makeBinPath rpDependencies} + ]} ''; - meta = { - inherit (rosenpass.meta) homepage license maintainers; - description = rosenpass.meta.description + " This package contains `rp`, which is a script that wraps the `rosenpass` binary."; - }; + meta = + rosenpass.meta + // { + description = "This package contains the Rosenpass tool `rp`, which is a script that wraps the `rosenpass` binary."; + mainProgram = "rp"; + }; } diff --git a/pkgs/by-name/rosenpass/package.nix b/pkgs/by-name/rosenpass/package.nix index 1eda2c1e..e4baa777 100644 --- a/pkgs/by-name/rosenpass/package.nix +++ b/pkgs/by-name/rosenpass/package.nix @@ -4,44 +4,44 @@ nixosTests, rustPlatform, targetPlatform, + installShellFiles, cmake, libsodium, pkg-config, }: rustPlatform.buildRustPackage rec { pname = "rosenpass"; - version = "0.2.0"; + version = "unstable-2023-09-28"; + src = fetchFromGitHub { owner = pname; repo = pname; - rev = "v${version}"; - hash = "sha256-r7/3C5DzXP+9w4rp9XwbP+/NK1axIP6s3Iiio1xRMbk="; + rev = "b15f17133f8b5c3c5175b4cfd4fc10039a4e203f"; + hash = "sha256-UXAkmt4VY0irLK2k4t6SW+SEodFE3CbX5cFbsPG0ZCo="; }; - cargoHash = "sha256-g2w3lZXQ3Kg3ydKdFs8P2lOPfIkfTbAF0MhxsJoX/E4="; + cargoHash = "sha256-N1DQHkgKgkDQ6DbgQJlpZkZ7AMTqX3P8R/cWr14jK2I="; nativeBuildInputs = [ cmake # for oqs build in the oqs-sys crate - pkg-config # let libsodium-sys-stable find libsodium + pkg-config rustPlatform.bindgenHook # for C-bindings in the crypto libs + installShellFiles ]; buildInputs = [libsodium]; - # liboqs requires quite a lot of stack memory, thus we adjust - # Increase the default stack size picked for new threads (which is used - # by `cargo test`) to be _big enough_. - # Only set this value for the check phase (not as an environment variable for the derivation), - # because it is only required in this phase. - preCheck = "export RUST_MIN_STACK=${builtins.toString (8 * 1024 * 1024)}"; # 8 MiB - # nix defaults to building for aarch64 _without_ the armv8-a # crypto extensions, but liboqs depends on these - preBuild = - lib.optionalString targetPlatform.isAarch - ''NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -march=armv8-a+crypto"''; + preBuild = lib.optionalString targetPlatform.isAarch64 '' + NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -march=armv8-a+crypto" + ''; + + postInstall = '' + installManPage doc/rosenpass.1 + ''; - preInstall = "install -D doc/rosenpass.1 $out/share/man/man1/rosenpass.1"; + passthru.tests.rosenpass = nixosTests.rosenpass; meta = with lib; { description = "Build post-quantum-secure VPNs with WireGuard!"; @@ -53,15 +53,8 @@ rustPlatform.buildRustPackage rec { */ asl20 ]; - platforms = platforms.all; - maintainers = with maintainers; - [ - andresnav - imincik - lorenzleutgeb - ] - ++ (with (import ../../maintainers/maintainers-list.nix); [augustebaum kubaneko]); + maintainers = with maintainers; [wucke13]; + platforms = ["aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux"]; + mainProgram = "rosenpass"; }; - - passthru.tests.rosenpass = nixosTests.rosenpass; } diff --git a/tests/pretalx/default.nix b/tests/pretalx/default.nix index 9243ae54..6ee6cf62 100644 --- a/tests/pretalx/default.nix +++ b/tests/pretalx/default.nix @@ -1,6 +1,7 @@ { configurations, modules, + ... }: { name = "pretalx tests"; diff --git a/tests/rosenpass/default.nix b/tests/rosenpass/default.nix index 092650bb..df082a51 100644 --- a/tests/rosenpass/default.nix +++ b/tests/rosenpass/default.nix @@ -1,9 +1,11 @@ { configurations, modules, + pkgs, + lib, + ... }: let deviceName = "rp0"; - server = { ip = "fe80::1"; wg = { @@ -57,13 +59,14 @@ in { modules.rosenpass ]; - boot.kernelModules = ["wireguard"]; - services.rosenpass = { enable = true; - publicKeyFile = etcPath config "rosenpass/pqpk"; - secretKeyFile = sopsPath config "rosenpass/pqsk"; defaultDevice = deviceName; + settings = { + verbosity = "Verbose"; + public_key = etcPath config "rosenpass/pqpk"; + secret_key = sopsPath config "rosenpass/pqsk"; + }; }; networking.firewall.allowedUDPPorts = [9999]; @@ -87,10 +90,7 @@ in { }; }; - environment.etc."rosenpass/pqpk" = { - inherit (config.services.rosenpass) user group; - source = peer.rp.public; - }; + environment.etc."rosenpass/pqpk".source = peer.rp.public; sops = { age.keyFile = ./keys.txt; @@ -101,12 +101,7 @@ in { owner = "systemd-network"; group = "systemd-network"; }; - "rosenpass/pqsk" = - peer.rp.secret - // { - inherit (config.services.rosenpass) group; - owner = config.services.rosenpass.user; - }; + "rosenpass/pqsk" = peer.rp.secret; }; }; }; @@ -128,20 +123,17 @@ in { ]; }; - services.rosenpass = { + services.rosenpass.settings = { listen = ["0.0.0.0:9999"]; peers = [ { - publicKeyFile = etcPath config "rosenpass/peers/client/pqpk"; - wireguard.publicKey = client.wg.public; + public_key = "/etc/rosenpass/peers/client/pqpk"; + peer = client.wg.public; } ]; }; - environment.etc."rosenpass/peers/client/pqpk" = { - inherit (config.services.rosenpass) user group; - source = ./client/pqpk.bin; - }; + environment.etc."rosenpass/peers/client/pqpk".source = ./client/pqpk.bin; }; client = {config, ...}: { imports = [(shared client)]; @@ -156,35 +148,54 @@ in { } ]; - services.rosenpass = { - peers = [ - { - publicKeyFile = etcPath config "rosenpass/peers/server/pqpk"; - endpoint = "server:9999"; - wireguard.publicKey = server.wg.public; - } - ]; - }; + services.rosenpass.settings.peers = [ + { + public_key = "/etc/rosenpass/peers/server/pqpk"; + endpoint = "server:9999"; + peer = server.wg.public; + } + ]; - environment.etc."rosenpass/peers/server/pqpk" = { - inherit (config.services.rosenpass) user group; - source = ./server/pqpk.bin; - }; + environment.etc."rosenpass/peers/server/pqpk".source = ./server/pqpk.bin; }; }; testScript = {nodes, ...}: '' start_all() - with subtest("rosenpass"): - server.wait_for_unit("rosenpass.service") - client.wait_for_unit("rosenpass.service") + for machine in [server, client]: + machine.wait_for_unit("rosenpass.service") + with subtest("ping"): client.succeed("ping -c 2 -i 0.5 ${server.ip}%${deviceName}") + with subtest("preshared-keys"): # Rosenpass works by setting the WireGuard preshared key at regular intervals. # Thus, if it is not active, then no key will be set, and the output of `wg show` will contain "none". # Otherwise, if it is active, then the key will be set and "none" will not be found in the output of `wg show`. - server.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5) + for machine in [server, client]: + machine.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5) ''; + + # NOTE: Below configuration is for "interactive" (=developing/debugging) only. + interactive.nodes = let + # Use kmscon + # to provide a slightly nicer console, and while we're at it, + # also use a nice font. + # With kmscon, we can for example zoom in/out using [Ctrl] + [+] + # and [Ctrl] + [-] + niceConsoleAndAutologin.services.kmscon = { + enable = true; + autologinUser = "root"; + fonts = [ + { + name = "Fira Code"; + package = pkgs.fira-code; + } + ]; + }; + in { + server = niceConsoleAndAutologin; + client = niceConsoleAndAutologin; + }; } From 3f7bb28655d308af8a88c558643e0badc2a07923 Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Sat, 4 Nov 2023 17:02:10 +0100 Subject: [PATCH 3/4] rosenpass: Remove module --- modules/all-modules.nix | 1 - modules/rosenpass.nix | 235 ------------------------------------ tests/rosenpass/default.nix | 1 - 3 files changed, 237 deletions(-) delete mode 100644 modules/rosenpass.nix diff --git a/modules/all-modules.nix b/modules/all-modules.nix index c97954e9..77e319aa 100644 --- a/modules/all-modules.nix +++ b/modules/all-modules.nix @@ -4,6 +4,5 @@ #liberaforms = import ./liberaforms.nix; flarum = import ./flarum.nix; pretalx = import ./pretalx.nix; - rosenpass = import ./rosenpass.nix; unbootable = import ./unbootable.nix; } diff --git a/modules/rosenpass.nix b/modules/rosenpass.nix deleted file mode 100644 index 257c1d4d..00000000 --- a/modules/rosenpass.nix +++ /dev/null @@ -1,235 +0,0 @@ -{ - config, - lib, - options, - pkgs, - ... -}: let - inherit - (lib) - attrValues - concatLines - concatMap - filter - filterAttrsRecursive - flatten - getExe - mdDoc - mkIf - optional - ; - - cfg = config.services.rosenpass; - opt = options.services.rosenpass; - settingsFormat = pkgs.formats.toml {}; -in { - options.services.rosenpass = let - inherit - (lib) - literalExpression - mdDoc - mkOption - ; - inherit - (lib.types) - enum - listOf - nullOr - path - str - submodule - ; - in { - enable = lib.mkEnableOption (mdDoc "Rosenpass"); - - package = lib.mkPackageOption pkgs "rosenpass" {}; - - defaultDevice = mkOption { - type = nullOr str; - description = mdDoc "Name of the network interface to use for all peers by default."; - example = "wg0"; - }; - - settings = mkOption { - type = submodule { - freeformType = settingsFormat.type; - - options = { - public_key = mkOption { - type = path; - description = mdDoc "Path to a file containing the public key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`."; - }; - - secret_key = mkOption { - type = path; - description = mdDoc "Path to a file containing the secret key of the local Rosenpass peer. Generate this by running {command}`rosenpass gen-keys`."; - }; - - listen = mkOption { - type = listOf str; - description = mdDoc "List of local endpoints to listen for connections."; - default = []; - example = literalExpression "[ \"0.0.0.0:10000\" ]"; - }; - - verbosity = mkOption { - type = enum ["Verbose" "Quiet"]; - default = "Quiet"; - description = mdDoc "Verbosity of output produced by the service."; - }; - - peers = let - peer = submodule { - freeformType = settingsFormat.type; - - options = { - public_key = mkOption { - type = path; - description = mdDoc "Path to a file containing the public key of the remote Rosenpass peer."; - }; - - endpoint = mkOption { - type = nullOr str; - default = null; - description = mdDoc "Endpoint of the remote Rosenpass peer."; - }; - - device = mkOption { - type = str; - default = cfg.defaultDevice; - defaultText = literalExpression "config.${opt.defaultDevice}"; - description = mdDoc "Name of the local WireGuard interface to use for this peer."; - }; - - peer = mkOption { - type = str; - description = mdDoc "WireGuard public key corresponding to the remote Rosenpass peer."; - }; - }; - }; - in - mkOption { - type = listOf peer; - description = mdDoc "List of peers to exchange keys with."; - default = []; - }; - }; - }; - default = {}; - description = mdDoc "Configuration for Rosenpass, see for further information."; - }; - }; - - config = mkIf cfg.enable { - warnings = let - # NOTE: In the descriptions below, we tried to refer to e.g. - # options.systemd.network.netdevs."".wireguardPeers.*.PublicKey - # directly, but don't know how to traverse "" and * in this path. - extractions = [ - { - relevant = config.systemd.network.enable; - root = config.systemd.network.netdevs; - peer = x: x.wireguardPeers; - key = x: - if x.wireguardPeerConfig ? PublicKey - then x.wireguardPeerConfig.PublicKey - else null; - description = mdDoc "${options.systemd.network.netdevs}.\"\".wireguardPeers.*.wireguardPeerConfig.PublicKey"; - } - { - relevant = config.networking.wireguard.enable; - root = config.networking.wireguard.interfaces; - peer = x: x.peers; - key = x: x.publicKey; - description = mdDoc "${options.networking.wireguard.interfaces}.\"\".peers.*.publicKey"; - } - rec { - relevant = root != {}; - root = config.networking.wg-quick.interfaces; - peer = x: x.peers; - key = x: x.publicKey; - description = mdDoc "${options.networking.wg-quick.interfaces}.\"\".peers.*.publicKey"; - } - ]; - relevantExtractions = filter (x: x.relevant) extractions; - extract = { - root, - peer, - key, - ... - }: - filter (x: x != null) (flatten (concatMap (x: (map key (peer x))) (attrValues root))); - configuredKeys = flatten (map extract relevantExtractions); - itemize = xs: concatLines (map (x: " - ${x}") xs); - descriptions = map (x: "`${x.description}`"); - missingKeys = filter (key: !builtins.elem key configuredKeys) (map (x: x.peer) cfg.settings.peers); - unusual = '' - While this may work as expected, e.g. you want to manually configure WireGuard, - such a scenario is unusual. Please double-check your configuration. - ''; - in - (optional (relevantExtractions != [] && missingKeys != []) '' - You have configured Rosenpass peers with the WireGuard public keys: - ${itemize missingKeys} - But there is no corresponding active Wireguard peer configuration in any of: - ${itemize (descriptions relevantExtractions)} - ${unusual} - '') - ++ optional (relevantExtractions == []) '' - You have configured Rosenpass, but you have not configured Wireguard via any of: - ${itemize (descriptions extractions)} - ${unusual} - ''; - - environment.systemPackages = [cfg.package pkgs.wireguard-tools]; - - systemd.services.rosenpass = let - filterNonNull = filterAttrsRecursive (_: v: v != null); - config = settingsFormat.generate "config.toml" ( - filterNonNull ( - cfg.settings - // ( - let - credentialPath = id: "$CREDENTIALS_DIRECTORY/${id}"; - # NOTE: We would like to remove all `null` values inside `cfg.settings` - # recursively, since `settingsFormat.generate` cannot handle `null`. - # This would require to traverse both attribute sets and lists recursively. - # `filterAttrsRecursive` only recurses into attribute sets, but not - # into values that might contain other attribute sets (such as lists, - # e.g. `cfg.settings.peers`). Here, we just specialize on `cfg.settings.peers`, - # and this may break unexpectedly whenever a `null` value is contained - # in a list in `cfg.settings`, other than `cfg.settings.peers`. - peersWithoutNulls = map filterNonNull cfg.settings.peers; - in { - secret_key = credentialPath "pqsk"; - public_key = credentialPath "pqpk"; - peers = peersWithoutNulls; - } - ) - ) - ); - in rec { - wantedBy = ["multi-user.target"]; - after = ["network-online.target"]; - path = [cfg.package pkgs.wireguard-tools]; - - serviceConfig = { - User = "rosenpass"; - Group = "rosenpass"; - RuntimeDirectory = "rosenpass"; - DynamicUser = true; - AmbientCapabilities = ["CAP_NET_ADMIN"]; - LoadCredential = [ - "pqsk:${cfg.settings.secret_key}" - "pqpk:${cfg.settings.public_key}" - ]; - }; - - # See - environment.CONFIG = "%t/${serviceConfig.RuntimeDirectory}/config.toml"; - - preStart = "${getExe pkgs.envsubst} -i ${config} -o \"$CONFIG\""; - script = "rosenpass exchange-config \"$CONFIG\""; - }; - }; -} diff --git a/tests/rosenpass/default.nix b/tests/rosenpass/default.nix index df082a51..1446903e 100644 --- a/tests/rosenpass/default.nix +++ b/tests/rosenpass/default.nix @@ -56,7 +56,6 @@ in { imports = [ modules.default modules.sops-nix - modules.rosenpass ]; services.rosenpass = { From 64392069961af7804afcf411fb7de284a0716cba Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Sat, 4 Nov 2023 17:26:47 +0100 Subject: [PATCH 4/4] flarum: Disable strict composer validation --- pkgs/by-name/flarum/package.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/by-name/flarum/package.nix b/pkgs/by-name/flarum/package.nix index ad2201fc..4880f87d 100644 --- a/pkgs/by-name/flarum/package.nix +++ b/pkgs/by-name/flarum/package.nix @@ -16,6 +16,7 @@ php.buildComposerProject (finalAttrs: { }; composerLock = ./composer.lock; + composerStrictValidation = false; vendorHash = "sha256-G/EPHcvcppuyAC0MAzE11ZjlOSTlphQrHnO3yS4+j5g="; meta = {