vault-agent-secrets.nix 3.87 KB
Newer Older
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
# SPDX-FileCopyrightText: 2020 Luke Granger-Brown <depot@lukegb.com>
#
# SPDX-License-Identifier: Apache-2.0

{ pkgs, config, depot, lib, ... }:
let
  inherit (lib) mkOption types mkBefore optionalAttrs mkDefault mapAttrs;

  secrets = lib.mapAttrsToList (name: cOrig: cOrig // { inherit name; }) config.my.vault.secrets;

  secretsGroups = lib.unique (map (c: c.group) secrets);
  secretsRoot = "/var/lib/secrets";

  secretsTemplate = map (c: {
    contents = c.template;
    destination = c.path;
    perms = "0640";
    command = let
    in pkgs.writeShellScript "post-secret-${c.name}" ''
      chgrp "${c.group}" "${c.path}"
      ${lib.concatMapStringsSep "\n" (x: ''
        /run/current-system/sw/bin/systemctl reload-or-restart ${x}
      '') c.reloadOrRestartUnits}
      ${lib.concatMapStringsSep "\n" (x: ''
        /run/current-system/sw/bin/systemctl restart ${x}
      '') c.restartUnits}
      ${lib.optionalString (c.command != "") c.command}
    '';
  }) secrets;

  secretsTmpdirs = [
    "d ${secretsRoot} 0111 vault-agent vault-agent - -"
  ] ++ map (c: "d ${c.parentDir} 0750 vault-agent ${c.group} - -") secrets;

  allRestartableUnits = lib.unique (builtins.concatMap (c: c.reloadOrRestartUnits ++ c.restartUnits) secrets);
in
{
  imports = [
    ./vault-agent.nix
  ];

  options.my.vault.secrets = mkOption {
    type = with types; attrsOf (submodule ({ name, config, ...}: {
      options = {
        name = mkOption {
          type = str;
          default = name;
          readOnly = true;
        };
        parentDir = mkOption {
          type = path;
          default = "${secretsRoot}/${config.name}";
          readOnly = true;
        };
        path = mkOption {
          type = path;
          default = "${config.parentDir}/secret";
          readOnly = true;
        };

        template = mkOption {
          type = lines;
          description = "Template to use for generating secret output.";
        };

        command = mkOption {
          type = lines;
          default = "";
          description = "Command to run after writing the secrets file.";
        };
        reloadOrRestartUnits = mkOption {
          type = listOf str;
          default = [];
          description = "List of systemd units to reload/restart after writing the secrets file.";
        };
        restartUnits = mkOption {
          type = listOf str;
          default = [];
          description = "List of systemd units to restart after writing the secrets file.";
        };

        group = mkOption {
          type = str;
          description = "Owner group to set for the generated file.";
        };
      };
    }));
    default = {};
  };

  config = {
    my.vault.settings = {
      template = mkBefore secretsTemplate;
    };

    systemd = optionalAttrs config.my.vault.enable {
      services.vault-agent = {
        serviceConfig = {
          SupplementaryGroups = mkBefore secretsGroups;
100
101
        };
        unitConfig = {
102
103
          Before = mkBefore allRestartableUnits;
        };
104
        wantedBy = mkBefore allRestartableUnits;
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
      };

      tmpfiles.rules = secretsTmpdirs;
    };

    security.polkit.extraConfig = lib.mkAfter ''
      // NixOS module: depot/lib/vault-agent-secrets.nix
      polkit.addRule(function(action, subject) {
        if (action.id !== "org.freedesktop.systemd1.manage-units" ||
            subject.user !== "vault-agent") {
          return polkit.Result.NOT_HANDLED;
        }

        var verb = action.lookup("verb");
        if (verb !== "restart" && verb !== "reload-or-restart") {
          return polkit.Result.NOT_HANDLED;
        }

        var allowedUnits = ${builtins.toJSON allRestartableUnits};
        var unit = action.lookup("unit");
        for (var i = 0; i < allowedUnits.length; i++) {
          if (allowedUnits[i] === unit) {
            return polkit.Result.YES;
          }
        }
        return polkit.Result.NOT_HANDLED;
      });
    '';
  };
}