grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / security / dhparams.nix
blobc501ea70d05ce69eb15b82325e6d856b7b214150
1 { config, lib, options, pkgs, ... }:
3 let
4   inherit (lib) literalExpression mkOption types;
5   cfg = config.security.dhparams;
6   opt = options.security.dhparams;
8   bitType = types.addCheck types.int (b: b >= 16) // {
9     name = "bits";
10     description = "integer of at least 16 bits";
11   };
13   paramsSubmodule = { name, config, ... }: {
14     options.bits = mkOption {
15       type = bitType;
16       default = cfg.defaultBitSize;
17       defaultText = literalExpression "config.${opt.defaultBitSize}";
18       description = ''
19         The bit size for the prime that is used during a Diffie-Hellman
20         key exchange.
21       '';
22     };
24     options.path = mkOption {
25       type = types.path;
26       readOnly = true;
27       description = ''
28         The resulting path of the generated Diffie-Hellman parameters
29         file for other services to reference. This could be either a
30         store path or a file inside the directory specified by
31         {option}`security.dhparams.path`.
32       '';
33     };
35     config.path = let
36       generated = pkgs.runCommand "dhparams-${name}.pem" {
37         nativeBuildInputs = [ pkgs.openssl ];
38       } "openssl dhparam -out \"$out\" ${toString config.bits}";
39     in if cfg.stateful then "${cfg.path}/${name}.pem" else generated;
40   };
42 in {
43   options = {
44     security.dhparams = {
45       enable = mkOption {
46         type = types.bool;
47         default = false;
48         description = ''
49           Whether to generate new DH params and clean up old DH params.
50         '';
51       };
53       params = mkOption {
54         type = with types; let
55           coerce = bits: { inherit bits; };
56         in attrsOf (coercedTo int coerce (submodule paramsSubmodule));
57         default = {};
58         example = lib.literalExpression "{ nginx.bits = 3072; }";
59         description = ''
60           Diffie-Hellman parameters to generate.
62           The value is the size (in bits) of the DH params to generate. The
63           generated DH params path can be found in
64           `config.security.dhparams.params.«name».path`.
66           ::: {.note}
67           The name of the DH params is taken as being the name of
68           the service it serves and the params will be generated before the
69           said service is started.
70           :::
72           ::: {.warning}
73           If you are removing all dhparams from this list, you
74           have to leave {option}`security.dhparams.enable` for at
75           least one activation in order to have them be cleaned up. This also
76           means if you rollback to a version without any dhparams the
77           existing ones won't be cleaned up. Of course this only applies if
78           {option}`security.dhparams.stateful` is
79           `true`.
80           :::
82           ::: {.note}
83           **For module implementers:** It's recommended
84           to not set a specific bit size here, so that users can easily
85           override this by setting
86           {option}`security.dhparams.defaultBitSize`.
87           :::
88         '';
89       };
91       stateful = mkOption {
92         type = types.bool;
93         default = true;
94         description = ''
95           Whether generation of Diffie-Hellman parameters should be stateful or
96           not. If this is enabled, PEM-encoded files for Diffie-Hellman
97           parameters are placed in the directory specified by
98           {option}`security.dhparams.path`. Otherwise the files are
99           created within the Nix store.
101           ::: {.note}
102           If this is `false` the resulting store
103           path will be non-deterministic and will be rebuilt every time the
104           `openssl` package changes.
105           :::
106         '';
107       };
109       defaultBitSize = mkOption {
110         type = bitType;
111         default = 2048;
112         description = ''
113           This allows to override the default bit size for all of the
114           Diffie-Hellman parameters set in
115           {option}`security.dhparams.params`.
116         '';
117       };
119       path = mkOption {
120         type = types.str;
121         default = "/var/lib/dhparams";
122         description = ''
123           Path to the directory in which Diffie-Hellman parameters will be
124           stored. This only is relevant if
125           {option}`security.dhparams.stateful` is
126           `true`.
127         '';
128       };
129     };
130   };
132   config = lib.mkIf (cfg.enable && cfg.stateful) {
133     systemd.services = {
134       dhparams-init = {
135         description = "Clean Up Old Diffie-Hellman Parameters";
137         # Clean up even when no DH params is set
138         wantedBy = [ "multi-user.target" ];
140         serviceConfig.RemainAfterExit = true;
141         serviceConfig.Type = "oneshot";
143         script = ''
144           if [ ! -d ${cfg.path} ]; then
145             mkdir -p ${cfg.path}
146           fi
148           # Remove old dhparams
149           for file in ${cfg.path}/*; do
150             if [ ! -f "$file" ]; then
151               continue
152             fi
153             ${lib.concatStrings (lib.mapAttrsToList (name: { bits, path, ... }: ''
154               if [ "$file" = ${lib.escapeShellArg path} ] && \
155                  ${pkgs.openssl}/bin/openssl dhparam -in "$file" -text \
156                  | head -n 1 | grep "(${toString bits} bit)" > /dev/null; then
157                 continue
158               fi
159             '') cfg.params)}
160             rm "$file"
161           done
163           # TODO: Ideally this would be removing the *former* cfg.path, though
164           # this does not seem really important as changes to it are quite
165           # unlikely
166           rmdir --ignore-fail-on-non-empty ${cfg.path}
167         '';
168       };
169     } // lib.mapAttrs' (name: { bits, path, ... }: lib.nameValuePair "dhparams-gen-${name}" {
170       description = "Generate Diffie-Hellman Parameters for ${name}";
171       after = [ "dhparams-init.service" ];
172       before = [ "${name}.service" ];
173       wantedBy = [ "multi-user.target" ];
174       unitConfig.ConditionPathExists = "!${path}";
175       serviceConfig.Type = "oneshot";
176       script = ''
177         mkdir -p ${lib.escapeShellArg cfg.path}
178         ${pkgs.openssl}/bin/openssl dhparam -out ${lib.escapeShellArg path} \
179           ${toString bits}
180       '';
181     }) cfg.params;
182   };
184   meta.maintainers = with lib.maintainers; [ ekleog ];