python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / security / vault.nix
blob7b9e31a8d990ffbcba0245fb1d5fd576ef902370
1 { config, lib, options, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.vault;
7   opt = options.services.vault;
9   configFile = pkgs.writeText "vault.hcl" ''
10     # vault in dev mode will refuse to start if its configuration sets listener
11     ${lib.optionalString (!cfg.dev) ''
12     listener "tcp" {
13       address = "${cfg.address}"
14       ${if (cfg.tlsCertFile == null || cfg.tlsKeyFile == null) then ''
15           tls_disable = "true"
16         '' else ''
17           tls_cert_file = "${cfg.tlsCertFile}"
18           tls_key_file = "${cfg.tlsKeyFile}"
19         ''}
20       ${cfg.listenerExtraConfig}
21     }
22     ''}
23     storage "${cfg.storageBackend}" {
24       ${optionalString (cfg.storagePath   != null) ''path = "${cfg.storagePath}"''}
25       ${optionalString (cfg.storageConfig != null) cfg.storageConfig}
26     }
27     ${optionalString (cfg.telemetryConfig != "") ''
28         telemetry {
29           ${cfg.telemetryConfig}
30         }
31       ''}
32     ${cfg.extraConfig}
33   '';
35   allConfigPaths = [configFile] ++ cfg.extraSettingsPaths;
36   configOptions = escapeShellArgs
37     (lib.optional cfg.dev "-dev" ++
38      lib.optional (cfg.dev && cfg.devRootTokenID != null) "-dev-root-token-id=${cfg.devRootTokenID}"
39       ++ (concatMap (p: ["-config" p]) allConfigPaths));
44   options = {
45     services.vault = {
46       enable = mkEnableOption (lib.mdDoc "Vault daemon");
48       package = mkOption {
49         type = types.package;
50         default = pkgs.vault;
51         defaultText = literalExpression "pkgs.vault";
52         description = lib.mdDoc "This option specifies the vault package to use.";
53       };
55       dev = mkOption {
56         type = types.bool;
57         default = false;
58         description = lib.mdDoc ''
59           In this mode, Vault runs in-memory and starts unsealed. This option is not meant production but for development and testing i.e. for nixos tests.
60         '';
61       };
63       devRootTokenID = mkOption {
64         type = types.str;
65         default = false;
66         description = lib.mdDoc ''
67           Initial root token. This only applies when {option}`services.vault.dev` is true
68         '';
69       };
71       address = mkOption {
72         type = types.str;
73         default = "127.0.0.1:8200";
74         description = lib.mdDoc "The name of the ip interface to listen to";
75       };
77       tlsCertFile = mkOption {
78         type = types.nullOr types.str;
79         default = null;
80         example = "/path/to/your/cert.pem";
81         description = lib.mdDoc "TLS certificate file. TLS will be disabled unless this option is set";
82       };
84       tlsKeyFile = mkOption {
85         type = types.nullOr types.str;
86         default = null;
87         example = "/path/to/your/key.pem";
88         description = lib.mdDoc "TLS private key file. TLS will be disabled unless this option is set";
89       };
91       listenerExtraConfig = mkOption {
92         type = types.lines;
93         default = ''
94           tls_min_version = "tls12"
95         '';
96         description = lib.mdDoc "Extra text appended to the listener section.";
97       };
99       storageBackend = mkOption {
100         type = types.enum [ "inmem" "file" "consul" "zookeeper" "s3" "azure" "dynamodb" "etcd" "mssql" "mysql" "postgresql" "swift" "gcs" "raft" ];
101         default = "inmem";
102         description = lib.mdDoc "The name of the type of storage backend";
103       };
105       storagePath = mkOption {
106         type = types.nullOr types.path;
107         default = if cfg.storageBackend == "file" || cfg.storageBackend == "raft" then "/var/lib/vault" else null;
108         defaultText = literalExpression ''
109           if config.${opt.storageBackend} == "file" || cfg.storageBackend == "raft"
110           then "/var/lib/vault"
111           else null
112         '';
113         description = lib.mdDoc "Data directory for file backend";
114       };
116       storageConfig = mkOption {
117         type = types.nullOr types.lines;
118         default = null;
119         description = lib.mdDoc ''
120           HCL configuration to insert in the storageBackend section.
122           Confidential values should not be specified here because this option's
123           value is written to the Nix store, which is publicly readable.
124           Provide credentials and such in a separate file using
125           [](#opt-services.vault.extraSettingsPaths).
126         '';
127       };
129       telemetryConfig = mkOption {
130         type = types.lines;
131         default = "";
132         description = lib.mdDoc "Telemetry configuration";
133       };
135       extraConfig = mkOption {
136         type = types.lines;
137         default = "";
138         description = lib.mdDoc "Extra text appended to {file}`vault.hcl`.";
139       };
141       extraSettingsPaths = mkOption {
142         type = types.listOf types.path;
143         default = [];
144         description = lib.mdDoc ''
145           Configuration files to load besides the immutable one defined by the NixOS module.
146           This can be used to avoid putting credentials in the Nix store, which can be read by any user.
148           Each path can point to a JSON- or HCL-formatted file, or a directory
149           to be scanned for files with `.hcl` or
150           `.json` extensions.
152           To upload the confidential file with NixOps, use for example:
154           ```
155           # https://releases.nixos.org/nixops/latest/manual/manual.html#opt-deployment.keys
156           deployment.keys."vault.hcl" = let db = import ./db-credentials.nix; in {
157             text = ${"''"}
158               storage "postgresql" {
159                 connection_url = "postgres://''${db.username}:''${db.password}@host.example.com/exampledb?sslmode=verify-ca"
160               }
161             ${"''"};
162             user = "vault";
163           };
164           services.vault.extraSettingsPaths = ["/run/keys/vault.hcl"];
165           services.vault.storageBackend = "postgresql";
166           users.users.vault.extraGroups = ["keys"];
167           ```
168         '';
169       };
170     };
171   };
173   config = mkIf cfg.enable {
174     assertions = [
175       {
176         assertion = cfg.storageBackend == "inmem" -> (cfg.storagePath == null && cfg.storageConfig == null);
177         message = ''The "inmem" storage expects no services.vault.storagePath nor services.vault.storageConfig'';
178       }
179       {
180         assertion = (
181           (cfg.storageBackend == "file" -> (cfg.storagePath != null && cfg.storageConfig == null)) &&
182           (cfg.storagePath != null -> (cfg.storageBackend == "file" || cfg.storageBackend == "raft"))
183         );
184         message = ''You must set services.vault.storagePath only when using the "file" or "raft" backend'';
185       }
186     ];
188     users.users.vault = {
189       name = "vault";
190       group = "vault";
191       uid = config.ids.uids.vault;
192       description = "Vault daemon user";
193     };
194     users.groups.vault.gid = config.ids.gids.vault;
196     systemd.tmpfiles.rules = optional (cfg.storagePath != null)
197       "d '${cfg.storagePath}' 0700 vault vault - -";
199     systemd.services.vault = {
200       description = "Vault server daemon";
202       wantedBy = ["multi-user.target"];
203       after = [ "network.target" ]
204            ++ optional (config.services.consul.enable && cfg.storageBackend == "consul") "consul.service";
206       restartIfChanged = false; # do not restart on "nixos-rebuild switch". It would seal the storage and disrupt the clients.
208       startLimitIntervalSec = 60;
209       startLimitBurst = 3;
210       serviceConfig = {
211         User = "vault";
212         Group = "vault";
213         ExecStart = "${cfg.package}/bin/vault server ${configOptions}";
214         ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
215         StateDirectory = "vault";
216         # In `dev` mode vault will put its token here
217         Environment = lib.optional (cfg.dev) "HOME=/var/lib/vault";
218         PrivateDevices = true;
219         PrivateTmp = true;
220         ProtectSystem = "full";
221         ProtectHome = "read-only";
222         AmbientCapabilities = "cap_ipc_lock";
223         NoNewPrivileges = true;
224         KillSignal = "SIGINT";
225         TimeoutStopSec = "30s";
226         Restart = "on-failure";
227       };
229       unitConfig.RequiresMountsFor = optional (cfg.storagePath != null) cfg.storagePath;
230     };
231   };