Skip to content

Commit

Permalink
Update NixOS module for config changes
Browse files Browse the repository at this point in the history
  • Loading branch information
stephank committed Jun 29, 2022
1 parent 62b6ef3 commit 7da4d63
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 4 deletions.
4 changes: 4 additions & 0 deletions nix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ An example service configuration:
providers.main = {
issuer = "https://example.com";
vhost.nginx = true;
keys.main = {
alg = "EdDSA";
crv = "Ed25519";
];
tokens = [
{
path = "/run/diridp/my-application/token";
Expand Down
121 changes: 118 additions & 3 deletions nix/nixosModule.nix
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,80 @@ let
'';
};

keys = mkOption {
type = types.attrsOf (types.submodule {
options = keyOptions;
});
default = { };
description = ''
One or more configurations for signing keys.
'';
};

tokens = mkOption {
type = types.listOf (types.submodule {
options = tokenOptions;
});
default = [ ];
description = ''
One or more tokens issued by this provider.
'';
};

};

keyOptions = {

alg = mkOption {
type = types.str;
description = ''
Signing algorithm for this key.
'';
};

crv = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
For EdDSA, the curve to use.
'';
};

keySize = mkOption {
type = types.nullOr types.ints.positive;
default = null;
description = ''
For RSA, the size of the generated keys.
'';
};

dir = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Optional custom path to store keys.
'';
};

lifespan = mkOption {
type = types.nullOr types.ints.positive;
default = null;
description = ''
Duration in seconds a key is used, before being rotated.
'';
};

publishMargin = mkOption {
type = types.nullOr types.ints.positive;
default = null;
description = ''
Duration in seconds before and after key lifespan during which the key
is still announced.
'';
};

};

tokenOptions = {

path = mkOption {
Expand All @@ -154,6 +217,14 @@ let
example = "/run/diridp/my-application/token";
};

keyName = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
If multiple keys are configured, which one to use for this token.
'';
};

claims = mkOption {
type = types.attrs;
default = { };
Expand Down Expand Up @@ -210,12 +281,56 @@ let

cfg = config.services.diridp;

supportedAlgorithms = [
"EdDSA"
"ES256" "ES384"
"PS256" "PS384" "PS512"
"RS256" "RS384" "RS512"
];

# Convert a string to snake case.
# This only covers some of the known inputs in this module.
toSnakeCase = input: pipe input [
(builtins.split "([[:upper:]]+)")
(concatMapStrings (s: if isList s then "_${toLower (head s)}" else s))
];

# Common transformations on an attribute set for our YAML config output.
prepareConfigSection = attrs: pipe attrs [
(filterAttrs (name: value: value != null))
(mapAttrs' (name: nameValuePair (toSnakeCase name)))
];

# Prepare the configuration file and perform checks.
configFile = (pkgs.formats.yaml { }).generate "diridp.yaml" {
providers = mapAttrs (name: provider: {
inherit (provider) issuer claims tokens;
}) cfg.providers;
providers = mapAttrs (name: provider:
let
numKeys = length (attrNames provider.keys);
in prepareConfigSection ({
inherit (provider) issuer claims;
keys = mapAttrs (name: key:
# 'alg' must be one of the supported algorithms.
assert elem key.alg supportedAlgorithms;
# 'crv' is required for EdDSA.
assert key.alg == "EdDSA" -> key.crv != null;
# 'crv' can only be used with EdDSA.
assert key.crv != null -> key.alg == "EdDSA";
# 'keySize' can only be used with the RSA family.
assert key.keySize != null -> (hasPrefix "RS" key.alg) || (hasPrefix "PS" key.alg);
prepareConfigSection key
) provider.keys;
tokens = map (token:
# 'keyName' is required if there are multiple keys.
assert token.keyName == null -> numKeys == 1;
# 'keyName' must match a configured key.
assert token.keyName != null -> hasAttr token.keyName provider.keys;
prepareConfigSection token
) provider.tokens;
})
) cfg.providers;
};

# Prepare the startup script that creates directories.
preStartScript = pkgs.writeShellScript "diridp-dirs" (concatStringsSep "\n" (map (dir: ''
install -d \
-o ${escapeShellArg dir.owner} \
Expand Down
12 changes: 11 additions & 1 deletion nix/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ rustPlatform.buildRustPackage {
name = "diridp";

src = ./..;
cargoLock.lockFile = ./../Cargo.lock;
cargoLock = {
lockFile = ./../Cargo.lock;
outputHashes = {
"curve25519-dalek-4.0.0-pre.3" = "sha256-d+eETOnLv/n7B1vkarnWQdOUqY3mye1vdKykF9ZoQDc=";
"ed25519-dalek-1.0.1" = "sha256-xiv7s32OOrExybJTW6Sp6qpzoSYdpn6D5QZIFfk5OIk=";
};
};

buildInputs = lib.optionals stdenv.isDarwin [ CoreServices ];

# Tests rely on Node.js and additional dependencies.
# Skip for now an rely on our own CI.
doCheck = false;
}

0 comments on commit 7da4d63

Please sign in to comment.