-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from ngi-nix/algae-rosenpass
rosenpass: Add package, module and tests
- Loading branch information
Showing
17 changed files
with
19,558 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
{ | ||
config, | ||
lib, | ||
options, | ||
pkgs, | ||
... | ||
}: | ||
with builtins; | ||
with lib; let | ||
cfg = config.services.rosenpass; | ||
opt = options.services.rosenpass; | ||
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`."; | ||
}; | ||
|
||
defaultDevice = mkOption { | ||
type = nullOr str; | ||
description = "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."; | ||
}; | ||
|
||
peers = let | ||
peer = submodule { | ||
options = { | ||
publicKeyFile = mkOption { | ||
type = path; | ||
description = "Path to a file containing the public key of the remote Rosenpass peer."; | ||
}; | ||
|
||
endpoint = mkOption { | ||
type = nullOr str; | ||
default = null; | ||
description = "Endpoint of the remote Rosenpass peer."; | ||
}; | ||
|
||
device = mkOption { | ||
type = str; | ||
default = cfg.defaultDevice; | ||
defaultText = literalExpression "config.${opt.defaultDevice}"; | ||
description = "Name of the local WireGuard interface to use for this peer."; | ||
}; | ||
|
||
wireguard = mkOption { | ||
type = submodule { | ||
options = { | ||
publicKey = mkOption { | ||
type = str; | ||
description = "WireGuard public key corresponding to the remote Rosenpass peer."; | ||
}; | ||
}; | ||
}; | ||
description = "WireGuard configuration for this peer."; | ||
}; | ||
}; | ||
}; | ||
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 = {}; | ||
}; | ||
}; | ||
|
||
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."<name>".wireguardPeers.*.PublicKey | ||
# directly, but don't know how to traverse "<name>" 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}.\"<name>\".wireguardPeers.*.PublicKey`. While this may work as expected, such a scenario is unusual. Please double-check your configuration."; | ||
in | ||
concatMap (peer: optional (!publicKeyInNetdevs peer) (warningMsg peer)) cfg.peers; | ||
|
||
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. | ||
# <https://systemd.io/CREDENTIALS/> | ||
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 { | ||
wantedBy = ["multi-user.target"]; | ||
after = ["network-online.target"]; | ||
path = [pkgs.wireguard-tools]; | ||
|
||
script = "${cfg.package}/bin/rosenpass exchange-config ${configFile}"; | ||
|
||
serviceConfig = { | ||
User = cfg.user; | ||
Group = cfg.group; | ||
AmbientCapabilities = ["CAP_NET_ADMIN"]; | ||
}; | ||
}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
lib, | ||
makeWrapper, | ||
stdenv, | ||
coreutils, | ||
findutils, | ||
gawk, | ||
rosenpass, | ||
wireguard-tools, | ||
}: | ||
stdenv.mkDerivation { | ||
pname = "rosenpass-tools"; | ||
inherit (rosenpass) version src; | ||
|
||
nativeBuildInputs = [makeWrapper]; | ||
|
||
postInstall = let | ||
rpDependencies = [ | ||
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."; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
lib, | ||
fetchFromGitHub, | ||
nixosTests, | ||
rustPlatform, | ||
targetPlatform, | ||
cmake, | ||
libsodium, | ||
pkg-config, | ||
}: | ||
rustPlatform.buildRustPackage rec { | ||
pname = "rosenpass"; | ||
version = "0.2.0"; | ||
src = fetchFromGitHub { | ||
owner = pname; | ||
repo = pname; | ||
rev = "v${version}"; | ||
hash = "sha256-r7/3C5DzXP+9w4rp9XwbP+/NK1axIP6s3Iiio1xRMbk="; | ||
}; | ||
|
||
cargoHash = "sha256-g2w3lZXQ3Kg3ydKdFs8P2lOPfIkfTbAF0MhxsJoX/E4="; | ||
|
||
nativeBuildInputs = [ | ||
cmake # for oqs build in the oqs-sys crate | ||
pkg-config # let libsodium-sys-stable find libsodium | ||
rustPlatform.bindgenHook # for C-bindings in the crypto libs | ||
]; | ||
|
||
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"''; | ||
|
||
preInstall = "install -D doc/rosenpass.1 $out/share/man/man1/rosenpass.1"; | ||
|
||
meta = with lib; { | ||
description = "Build post-quantum-secure VPNs with WireGuard!"; | ||
homepage = "https://rosenpass.eu/"; | ||
license = with licenses; [ | ||
mit | ||
/* | ||
or | ||
*/ | ||
asl20 | ||
]; | ||
platforms = platforms.all; | ||
maintainers = with maintainers; | ||
[ | ||
andresnav | ||
imincik | ||
lorenzleutgeb | ||
] | ||
++ (with (import ../../maintainers/maintainers-list.nix); [augustebaum kubaneko]); | ||
}; | ||
|
||
passthru.tests = { | ||
inherit (nixosTests) rosenpass; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.