Skip to content

Commit 1dd64f5

Browse files
committed
feat(modules): Add secrets as nixosModules
1 parent 6ff9a90 commit 1dd64f5

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

modules/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
./folder-size-metrics
77
./shard-split
88
./host-info.nix
9+
./secrets.nix
910
];
1011
}

modules/secrets.nix

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
{ withSystem, inputs, ... }:
2+
{
3+
flake.modules.nixos.mcl-secrets =
4+
{
5+
config,
6+
options,
7+
lib,
8+
dirs,
9+
...
10+
}:
11+
let
12+
eachServiceCfg = config.mcl.secrets.services;
13+
isDebugVM = config.mcl.host-info.isDebugVM;
14+
15+
sshKey =
16+
if isDebugVM then
17+
config.virtualisation.vmVariant.mcl.host-info.sshKey
18+
else
19+
config.mcl.host-info.sshKey;
20+
21+
ageSecretOpts = builtins.head (builtins.head options.age.secrets.type.nestedTypes.elemType.getSubModules)
22+
.imports;
23+
24+
secretDir =
25+
let
26+
machineConfigPath = config.mcl.host-info.configPath;
27+
machineSecretDir = machineConfigPath + "/secrets";
28+
vmConfig = dirs.modules + "/default-vm-config";
29+
vmSecretDir = vmConfig + "/secrets";
30+
in
31+
if isDebugVM then vmSecretDir else machineSecretDir;
32+
in
33+
{
34+
imports = [
35+
inputs.agenix.nixosModules.default
36+
];
37+
38+
options.mcl.secrets = with lib; {
39+
services = mkOption {
40+
type = types.attrsOf (
41+
types.submodule (
42+
{ config, ... }:
43+
let
44+
serviceName = config._module.args.name;
45+
in
46+
{
47+
options = {
48+
encryptedSecretDir = mkOption {
49+
type = types.path;
50+
default = secretDir;
51+
};
52+
secrets = mkOption {
53+
default = { };
54+
type = types.attrsOf (
55+
types.submoduleWith {
56+
modules = [
57+
ageSecretOpts
58+
(
59+
{ name, ... }:
60+
let
61+
secretName = name;
62+
in
63+
{
64+
config = {
65+
name = "${serviceName}/${secretName}";
66+
file = lib.mkDefault (config.encryptedSecretDir + "/${serviceName}/${secretName}.age");
67+
};
68+
}
69+
)
70+
];
71+
}
72+
);
73+
};
74+
extraKeys = mkOption {
75+
type = types.listOf types.str;
76+
default = [ ];
77+
example = [
78+
"ssh-ed25519 AAAAC3Nza"
79+
"ssh-ed25519 AAAACSNss"
80+
];
81+
description = "Extra keys which can decrypt the secrets.";
82+
};
83+
nix-file = mkOption {
84+
default =
85+
if (pathIsRegularFile (config.encryptedSecretDir + "/${serviceName}/secrets.nix")) then
86+
config.encryptedSecretDir + "/${serviceName}/secrets.nix"
87+
else
88+
builtins.toFile "${serviceName}-secrets.nix" ''
89+
let
90+
hostKey = ["${sshKey}"];
91+
extraKeys = ["${concatStringsSep "\"\"" config.extraKeys}"];
92+
in {
93+
${concatMapStringsSep "\n" (n: "\"${n}.age\".publicKeys = hostKey ++ extraKeys;") (
94+
builtins.attrNames config.secrets
95+
)}
96+
}
97+
'';
98+
type = types.path;
99+
};
100+
};
101+
}
102+
)
103+
);
104+
default = { };
105+
example = {
106+
service1.secrets.secretA = { };
107+
service1.secrets.secretB = { };
108+
service2.secrets.secretC = { };
109+
cachix-deploy.secrets.token = {
110+
path = "/etc/cachix-agent.token";
111+
};
112+
};
113+
description = mdDoc "Per-service attrset of encryptedSecretDir and secrets";
114+
};
115+
};
116+
117+
config = lib.mkIf (eachServiceCfg != { }) {
118+
age.secrets = lib.pipe eachServiceCfg [
119+
(lib.mapAttrsToList (
120+
serviceName: service:
121+
lib.mapAttrsToList (
122+
secretName: config: lib.nameValuePair "${serviceName}/${secretName}" config
123+
) service.secrets
124+
))
125+
lib.concatLists
126+
lib.listToAttrs
127+
];
128+
};
129+
};
130+
}

0 commit comments

Comments
 (0)