Skip to content

Commit af44743

Browse files
authored
Add home manager support (#10)
* Add home-manager module * Update readme
1 parent 5ae1ba9 commit af44743

File tree

3 files changed

+151
-3
lines changed

3 files changed

+151
-3
lines changed

README.md

+25
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,31 @@ ssh.
259259
See [module](https://github.com/pinpox/lollypops/blob/main/module.nix) for a
260260
full list of options with defaults and example values.
261261

262+
#### Home-manager secrets
263+
264+
If you are using home-manager, you may want to use secrets in your home
265+
configuration as well. For this, lollypops provides a separate home-manager
266+
module that can be imported to enable support for user-specific secrets.
267+
268+
In your home-manager configuration import the `hmModule` provided by the flake:
269+
270+
```nix
271+
imports = [
272+
lollypops.hmModule
273+
];
274+
```
275+
276+
This allows specifying secrets in the same way as the system-wide secrets. For
277+
user-specific secrets lollypops defaults to `$HOME/lollypops-secrets` for it's
278+
location and sets the ownership to the user instead of root.
279+
280+
```
281+
lollypops.secrets = {
282+
cmd-name-prefix = "nixos-secrets/users/pinpox/";
283+
files."usertest" = { };
284+
};
285+
```
286+
262287
### Debugging
263288

264289
lollypops hides the executed commands in the default output. To enable full

flake.nix

+35-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
{
1212
nixosModules.lollypops = import ./module.nix;
1313
nixosModules.default = self.nixosModules.lollypops;
14+
15+
hmModule = import ./hm-module.nix;
16+
1417
} //
1518

1619
# TODO test/add other plattforms
@@ -20,10 +23,38 @@
2023
let
2124
pkgs = nixpkgs.legacyPackages.${system};
2225
in
23-
rec {
26+
{
2427
# Allow custom packages to be run using `nix run`
2528
apps =
2629
let
30+
31+
# Build steps for all secrets of all users
32+
mkSeclistUser = homeUsers: pkgs.lib.lists.flatten (builtins.attrValues (builtins.mapAttrs
33+
(user: userconfig: [
34+
# Deploy secrets for user 'user'
35+
(builtins.attrValues (builtins.mapAttrs
36+
(secretName: secretConfig: [
37+
# Deloy secret 'secretName' of user 'user'
38+
"echo 'Deploying ${secretName} (from user ${user}) to ${pkgs.lib.escapeShellArg secretConfig.path}'"
39+
40+
# Create parent directory if it does not exist
41+
''
42+
set -o pipefail -e; ssh {{.REMOTE_USER}}@{{.REMOTE_HOST}} 'umask 077; sudo -u ${user} mkdir -p "$(dirname ${pkgs.lib.escapeShellArg secretConfig.path})"'
43+
''
44+
# Copy file
45+
''
46+
set -o pipefail -e; ${secretConfig.cmd} | ssh {{.REMOTE_USER}}@{{.REMOTE_HOST}} "umask 077; cat > ${pkgs.lib.escapeShellArg secretConfig.path}"
47+
''
48+
# # Set group and owner
49+
''
50+
set -o pipefail -e; ssh {{.REMOTE_USER}}@{{.REMOTE_HOST}} "chown ${secretConfig.owner}:${secretConfig.group-name} ${pkgs.lib.escapeShellArg secretConfig.path}"
51+
''
52+
])
53+
userconfig.lollypops.secrets.files))
54+
55+
])
56+
homeUsers));
57+
2758
mkSeclist = config: pkgs.lib.lists.flatten (map
2859
(x: [
2960
"echo 'Deploying ${x.name} to ${pkgs.lib.escapeShellArg x.path}'"
@@ -76,8 +107,9 @@
76107

77108
cmds = [
78109
''echo "Deploying secrets to: {{.HOSTNAME}}"''
79-
] ++ mkSeclist hostConfig.config;
80-
110+
]
111+
++ mkSeclist hostConfig.config
112+
++ mkSeclistUser hostConfig.config.home-manager.users;
81113
};
82114

83115
rebuild = {

hm-module.nix

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{ config, pkgs, lib, ... }:
2+
with lib;
3+
let
4+
cfg = config.lollypops;
5+
6+
secret-file = types.submodule ({ config, ... }: {
7+
options = {
8+
9+
name = mkOption {
10+
type = types.str;
11+
default = config._module.args.name;
12+
description = "Name of the secret";
13+
defaultText = "<name>";
14+
};
15+
16+
cmd = mkOption {
17+
type = types.str;
18+
default = "${cfg.secrets.default-cmd} ${cfg.secrets.cmd-name-prefix}${config.name}";
19+
description = "Command to print the secret. E.g. `cat mysecretfile`";
20+
defaultText = "<default-cmd> <cmd-name-prefix><name>";
21+
};
22+
23+
path = mkOption {
24+
type = types.str;
25+
default = "${cfg.secrets.default-dir}/${config.name}";
26+
description = "Path to place the secret file";
27+
defaultText = "<default-dir>/<name>";
28+
};
29+
30+
mode = mkOption {
31+
type = types.str;
32+
default = "0400";
33+
description = "Unix permission";
34+
};
35+
36+
owner = mkOption {
37+
type = types.str;
38+
default = "${cfg.secrets.default-user}";
39+
description = "Owner of the secret file";
40+
};
41+
42+
group-name = mkOption {
43+
type = types.str;
44+
default = "users";
45+
description = "Group of the secret file";
46+
};
47+
};
48+
});
49+
in
50+
{
51+
52+
options.lollypops = {
53+
54+
secrets = {
55+
56+
default-cmd = mkOption {
57+
type = types.str;
58+
default = "${pkgs.pass}/bin/pass";
59+
description = "Default command to retrieve passwords. Will be passed the name as parameter";
60+
defaultText = "\${pkgs.pass}/bin/pass";
61+
};
62+
63+
cmd-name-prefix = mkOption {
64+
type = types.str;
65+
default = "";
66+
description = "Prefix to prepend to all name when passing to the cmd";
67+
};
68+
69+
default-dir = mkOption {
70+
type = types.str;
71+
default = "${config.home.homeDirectory}/lollypops-secrets";
72+
description = "Path to place the secrets on the remote host if no alternative is specified";
73+
};
74+
75+
default-user = mkOption {
76+
type = types.str;
77+
default = config.home.username;
78+
visible = false;
79+
readOnly = true;
80+
};
81+
82+
files = mkOption {
83+
type = with types; attrsOf secret-file;
84+
default = { };
85+
description = "Attribute set specifying secrets to be deployed";
86+
};
87+
};
88+
};
89+
90+
# config = { };
91+
}

0 commit comments

Comments
 (0)