Skip to content

Commit d3965e8

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

File tree

2 files changed

+127
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)