summary refs log tree commit diff
path: root/options.nix
blob: 8531404ab442f49684357cb6ac43b526f9e9ddfe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
{ config, pkgs, lib, ... }:

{
  options.secrets = {
    secrets = lib.mkOption {
      description = ''
        A set of secrets, each identified by a name (e.g. mattermost, gitlabce).
        Each secret has a filename and a script to generate it.
      '';
      default = { };
      type = lib.types.attrsOf (lib.types.submodule {
        options = {
          filename = lib.mkOption {
            type = lib.types.pathWith {
              absolute = false;
              inStore = false;
            };
            description = ''
              The filename this secret should have. This is a relative path,
              relative to the base of the secret store, which is normally
              `/etc/nixos/secrets`. It is fine for it to be a bare filename.
            '';
            example = "mysecret.key";
          };

          script = lib.mkOption {
            type = lib.types.lines;
            description = ''
              Shell command that generates the secret.
            '';
            example = "head -c 32 /dev/urandom | base32";
          };
        };
      });
    };

    # For modularity's sake, we export a cleanly-defined structure for the CLI
    # tool to wrap around. That way we avoid inadvertently relying on the
    # overall structure of the secrets options, and in particular we avoid
    # relying on implementation details that will change.
    export = lib.mkOption {
      description = ''
        An internal value used for the command-line secret-management tool to
        query an assembled NixOS configuration about what secrets it expects
        to exist, and their properties.
      '';
      example = {
        mattermost = {
          path = "/etc/nixos/secrets/mattermost.key";
          script = "touch /etc/nixos/secrets/mattermost.key";
        };

        neooffice = {
          path = "/etc/nixos/secrets/neooffice.key";
          script =
              "head -c 32 /dev/urandom > /etc/nixos/secrets/neooffice.key";
        };
      };

      type = lib.types.attrsOf (lib.types.submodule {
        options = {
          path = lib.mkOption {
            type = lib.types.pathWith {
              absolute = true;
              inStore = false;
            };
            description = ''
              An internal value which is part of `secrets.export`, used by
              the command-line secret-management tool. This is an absolute
              path to the file which, if the secret exists, should contain it.
              When the CLI tool is run, this directory is expected to exist;
              whether the file exists is the thing the CLI tool is responsible
              for managing.
            '';
            example = "/etc/nixos/secrets/neooffice.key";
          };

          script = lib.mkOption {
            type = lib.types.lines;
            description = ''
              An internal value which is part of `secrets.export`, used by
              the command-line secret-management tool. This is a shell script
              which will create the secret, destructively overwriting it if it
              already exists. It runs in an empty shell environment with no
              environment variables. It should start with an appropriate
              `#!` line pointing to the correct shell to run it under.
            '';
            example = ''
              #!/nix/store/s68ja06r60xbs51k8lrdciva4di46y61-bash-5.2/bin/bash
              head -c 32 /dev/urandom > /etc/nixos/secrets/neooffice.key
            '';
          };
        };
      });
    };
  };

  config.secrets.export =
      let exportSecret = name: secret: {
            path = "/etc/nixos/secrets/${secret.filename}";

            # In defiance of the usual code style, we leave off the trailing
            # newline here because that makes life easier when writing test
            # cases (see `checks.nix`), which would otherwise have to add an
            # extra one.
            script = ''
              #!${pkgs.bash}/bin/bash
              ${secret.script}'';
          };
      in builtins.mapAttrs exportSecret config.secrets.secrets;
}