Skip to content

Commit 8aa9e69

Browse files
committed
modules: add secrets/age.nix
1 parent d538ea3 commit 8aa9e69

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

modules/secrets/age.nix

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
{ config, pkgs, lib, ... }:
2+
3+
with lib;
4+
let
5+
options.nix-bitcoin.age = {
6+
enable = mkOption {
7+
type = types.bool;
8+
default = false;
9+
description = mdDoc ''
10+
Enable age-encrypted secrets.
11+
12+
This requires that the [agenix](https://github.com/ryantm/agenix)
13+
module is included in your config.
14+
'';
15+
};
16+
17+
secretsSourceDir = mkOption {
18+
type = types.path;
19+
example = literalExpression "./secrets";
20+
description = mdDoc ''
21+
The directory where age-encrypted secrets are stored.
22+
'';
23+
};
24+
25+
publicKeys = mkOption {
26+
type = with types; listOf str;
27+
example = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH" ];
28+
description = mdDoc ''
29+
Public keys for encrypting the secrets.
30+
31+
A sensible default is to set this to the ed25519 public SSH host key of your node.
32+
You can query host keys with command {command}`ssh-keyscan <node address>`.
33+
34+
When not using a SSH host key, make sure to set the corresponding agenix
35+
option {option}`age.identityPaths`.
36+
'';
37+
};
38+
39+
generateSecretsScript = mkOption {
40+
readOnly = true;
41+
42+
description = mdDoc secretsScriptLib.scriptHelp;
43+
44+
default = pkgs.writers.writeBashBin "generate-secrets" ''
45+
${secretsScriptLib.gotoDestDir}
46+
47+
tmpSecretsDir=$(mktemp -d)
48+
trap 'rm -rf $tmpSecretsDir' EXIT
49+
50+
# 1. Generate secrets to a tmp dir
51+
pushd "$tmpSecretsDir" >/dev/null
52+
${config.nix-bitcoin.generateSecretsScriptImpl}
53+
popd >/dev/null
54+
55+
# 2. Age-encrypt each secret to $PWD/$name.age
56+
encrypt() {
57+
${getExe pkgs.rage} "$tmpSecretsDir/$1" -o "$1.age" ${
58+
concatMapStringsSep " " (pubkey:
59+
"--recipient ${escapeShellArg pubkey}"
60+
) cfg.publicKeys
61+
}
62+
}
63+
${
64+
concatMapStrings (name: ''
65+
encrypt "${name}"
66+
'') (builtins.attrNames config.nix-bitcoin.secrets)
67+
}
68+
'';
69+
};
70+
};
71+
72+
cfg = config.nix-bitcoin.age;
73+
inherit (config.nix-bitcoin) secretsScriptLib;
74+
in {
75+
inherit options;
76+
77+
config = {
78+
nix-bitcoin.secretsSetupMethod = "age";
79+
80+
nix-bitcoin.secretsDir = config.age.secretsDir;
81+
82+
# The `nix-bitcoin-secrets` target has no dependencies,
83+
# because agenix runs via the activation script, before systemd.
84+
systemd.targets.nix-bitcoin-secrets = {};
85+
86+
age.secrets = mapAttrs (name: value: {
87+
owner = value.user;
88+
group = value.group;
89+
mode = value.permissions;
90+
file = (cfg.secretsSourceDir + "/${name}.age");
91+
}) config.nix-bitcoin.secrets;
92+
};
93+
}

0 commit comments

Comments
 (0)