Skip to content

Commit 7da4d63

Browse files
committed
Update NixOS module for config changes
1 parent 62b6ef3 commit 7da4d63

File tree

3 files changed

+133
-4
lines changed

3 files changed

+133
-4
lines changed

nix/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ An example service configuration:
5656
providers.main = {
5757
issuer = "https://example.com";
5858
vhost.nginx = true;
59+
keys.main = {
60+
alg = "EdDSA";
61+
crv = "Ed25519";
62+
];
5963
tokens = [
6064
{
6165
path = "/run/diridp/my-application/token";

nix/nixosModule.nix

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,80 @@ let
125125
'';
126126
};
127127

128+
keys = mkOption {
129+
type = types.attrsOf (types.submodule {
130+
options = keyOptions;
131+
});
132+
default = { };
133+
description = ''
134+
One or more configurations for signing keys.
135+
'';
136+
};
137+
128138
tokens = mkOption {
129139
type = types.listOf (types.submodule {
130140
options = tokenOptions;
131141
});
142+
default = [ ];
132143
description = ''
133144
One or more tokens issued by this provider.
134145
'';
135146
};
136147

137148
};
138149

150+
keyOptions = {
151+
152+
alg = mkOption {
153+
type = types.str;
154+
description = ''
155+
Signing algorithm for this key.
156+
'';
157+
};
158+
159+
crv = mkOption {
160+
type = types.nullOr types.str;
161+
default = null;
162+
description = ''
163+
For EdDSA, the curve to use.
164+
'';
165+
};
166+
167+
keySize = mkOption {
168+
type = types.nullOr types.ints.positive;
169+
default = null;
170+
description = ''
171+
For RSA, the size of the generated keys.
172+
'';
173+
};
174+
175+
dir = mkOption {
176+
type = types.nullOr types.path;
177+
default = null;
178+
description = ''
179+
Optional custom path to store keys.
180+
'';
181+
};
182+
183+
lifespan = mkOption {
184+
type = types.nullOr types.ints.positive;
185+
default = null;
186+
description = ''
187+
Duration in seconds a key is used, before being rotated.
188+
'';
189+
};
190+
191+
publishMargin = mkOption {
192+
type = types.nullOr types.ints.positive;
193+
default = null;
194+
description = ''
195+
Duration in seconds before and after key lifespan during which the key
196+
is still announced.
197+
'';
198+
};
199+
200+
};
201+
139202
tokenOptions = {
140203

141204
path = mkOption {
@@ -154,6 +217,14 @@ let
154217
example = "/run/diridp/my-application/token";
155218
};
156219

220+
keyName = mkOption {
221+
type = types.nullOr types.str;
222+
default = null;
223+
description = ''
224+
If multiple keys are configured, which one to use for this token.
225+
'';
226+
};
227+
157228
claims = mkOption {
158229
type = types.attrs;
159230
default = { };
@@ -210,12 +281,56 @@ let
210281

211282
cfg = config.services.diridp;
212283

284+
supportedAlgorithms = [
285+
"EdDSA"
286+
"ES256" "ES384"
287+
"PS256" "PS384" "PS512"
288+
"RS256" "RS384" "RS512"
289+
];
290+
291+
# Convert a string to snake case.
292+
# This only covers some of the known inputs in this module.
293+
toSnakeCase = input: pipe input [
294+
(builtins.split "([[:upper:]]+)")
295+
(concatMapStrings (s: if isList s then "_${toLower (head s)}" else s))
296+
];
297+
298+
# Common transformations on an attribute set for our YAML config output.
299+
prepareConfigSection = attrs: pipe attrs [
300+
(filterAttrs (name: value: value != null))
301+
(mapAttrs' (name: nameValuePair (toSnakeCase name)))
302+
];
303+
304+
# Prepare the configuration file and perform checks.
213305
configFile = (pkgs.formats.yaml { }).generate "diridp.yaml" {
214-
providers = mapAttrs (name: provider: {
215-
inherit (provider) issuer claims tokens;
216-
}) cfg.providers;
306+
providers = mapAttrs (name: provider:
307+
let
308+
numKeys = length (attrNames provider.keys);
309+
in prepareConfigSection ({
310+
inherit (provider) issuer claims;
311+
keys = mapAttrs (name: key:
312+
# 'alg' must be one of the supported algorithms.
313+
assert elem key.alg supportedAlgorithms;
314+
# 'crv' is required for EdDSA.
315+
assert key.alg == "EdDSA" -> key.crv != null;
316+
# 'crv' can only be used with EdDSA.
317+
assert key.crv != null -> key.alg == "EdDSA";
318+
# 'keySize' can only be used with the RSA family.
319+
assert key.keySize != null -> (hasPrefix "RS" key.alg) || (hasPrefix "PS" key.alg);
320+
prepareConfigSection key
321+
) provider.keys;
322+
tokens = map (token:
323+
# 'keyName' is required if there are multiple keys.
324+
assert token.keyName == null -> numKeys == 1;
325+
# 'keyName' must match a configured key.
326+
assert token.keyName != null -> hasAttr token.keyName provider.keys;
327+
prepareConfigSection token
328+
) provider.tokens;
329+
})
330+
) cfg.providers;
217331
};
218332

333+
# Prepare the startup script that creates directories.
219334
preStartScript = pkgs.writeShellScript "diridp-dirs" (concatStringsSep "\n" (map (dir: ''
220335
install -d \
221336
-o ${escapeShellArg dir.owner} \

nix/package.nix

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@ rustPlatform.buildRustPackage {
44
name = "diridp";
55

66
src = ./..;
7-
cargoLock.lockFile = ./../Cargo.lock;
7+
cargoLock = {
8+
lockFile = ./../Cargo.lock;
9+
outputHashes = {
10+
"curve25519-dalek-4.0.0-pre.3" = "sha256-d+eETOnLv/n7B1vkarnWQdOUqY3mye1vdKykF9ZoQDc=";
11+
"ed25519-dalek-1.0.1" = "sha256-xiv7s32OOrExybJTW6Sp6qpzoSYdpn6D5QZIFfk5OIk=";
12+
};
13+
};
814

915
buildInputs = lib.optionals stdenv.isDarwin [ CoreServices ];
16+
17+
# Tests rely on Node.js and additional dependencies.
18+
# Skip for now an rely on our own CI.
19+
doCheck = false;
1020
}

0 commit comments

Comments
 (0)