
First of all let's start with a clean up the multiline string
indentation for descriptions, because having two indentation levels
after description is a waste of screen estate.
A quick survey in the form of the following also reveals that the
majority of multiline strings in nixpkgs is starting the two beginning
quotes in the same line:
$ find -name '*.nix' -exec sed -n -e '/=$/ { n; /'\'\''/p }' {} + | wc -l
817
$ find -name '*.nix' -exec grep "= *'' *\$" {} + | wc -l
14818
The next point is to get the type, default and example attributes on top
of the description because that's the way it's rendered in the manual.
Most services have their enable option close to the beginning of the
file, so let's move it to the top.
Also, I found the script attribute for dhparams-init.service a bit hard
to read as it was using string concatenation to split a "for" loop.
Now for the more substantial clean ups rather than just code style:
* Remove the "with lib;" at the beginning of the module, because it
makes it easier to do a quick check with "nix-instantiate --parse".
* Use ConditionPathExists instead of test -e for checking whether we
need to generate the dhparams file. This avoids spawning a shell if
the file exists already and it's probably more common that it will
exist, except for the initial creation of course.
* When cleaning up old dhparams file, use RemainAfterExit so that the
unit won't be triggered again whenever we stop and start a service
depending on it.
* Capitalize systemd unit descriptions to be more in par with most
other unit descriptions (also see 0c5e837b66
).
* Use "=" instead of "==" for conditionals using []. It's just a very
small nitpick though and it will only fail for POSIX shells. Bash on
the other side accepts it anyway.
Signed-off-by: aszlig <aszlig@nix.build>
Cc: @Ekleog
157 lines
5.4 KiB
Nix
157 lines
5.4 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
inherit (lib) mkOption types;
|
|
cfg = config.security.dhparams;
|
|
|
|
paramsSubmodule = { name, config, ... }: {
|
|
options.bits = mkOption {
|
|
type = types.addCheck types.int (b: b >= 16) // {
|
|
name = "bits";
|
|
description = "integer of at least 16 bits";
|
|
};
|
|
default = 4096;
|
|
description = ''
|
|
The bit size for the prime that is used during a Diffie-Hellman
|
|
key exchange.
|
|
'';
|
|
};
|
|
|
|
options.path = mkOption {
|
|
type = types.path;
|
|
readOnly = true;
|
|
description = ''
|
|
The resulting path of the generated Diffie-Hellman parameters
|
|
file for other services to reference. This could be either a
|
|
store path or a file inside the directory specified by
|
|
<option>security.dhparams.path</option>.
|
|
'';
|
|
};
|
|
|
|
config.path = let
|
|
generated = pkgs.runCommand "dhparams-${name}.pem" {
|
|
nativeBuildInputs = [ pkgs.openssl ];
|
|
} "openssl dhparam -out \"$out\" ${toString config.bits}";
|
|
in if cfg.stateful then "${cfg.path}/${name}.pem" else generated;
|
|
};
|
|
|
|
in {
|
|
options = {
|
|
security.dhparams = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = ''
|
|
Whether to generate new DH params and clean up old DH params.
|
|
'';
|
|
};
|
|
|
|
params = mkOption {
|
|
type = with types; let
|
|
coerce = bits: { inherit bits; };
|
|
in attrsOf (coercedTo int coerce (submodule paramsSubmodule));
|
|
default = {};
|
|
example = lib.literalExample "{ nginx.bits = 3072; }";
|
|
description = ''
|
|
Diffie-Hellman parameters to generate.
|
|
|
|
The value is the size (in bits) of the DH params to generate. The
|
|
generated DH params path can be found in
|
|
<literal>config.security.dhparams.params.<replaceable>name</replaceable>.path</literal>.
|
|
|
|
<note><para>The name of the DH params is taken as being the name of
|
|
the service it serves and the params will be generated before the
|
|
said service is started.</para></note>
|
|
|
|
<warning><para>If you are removing all dhparams from this list, you
|
|
have to leave <option>security.dhparams.enable</option> for at
|
|
least one activation in order to have them be cleaned up. This also
|
|
means if you rollback to a version without any dhparams the
|
|
existing ones won't be cleaned up. Of course this only applies if
|
|
<option>security.dhparams.stateful</option> is
|
|
<literal>true</literal>.</para></warning>
|
|
'';
|
|
};
|
|
|
|
stateful = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = ''
|
|
Whether generation of Diffie-Hellman parameters should be stateful or
|
|
not. If this is enabled, PEM-encoded files for Diffie-Hellman
|
|
parameters are placed in the directory specified by
|
|
<option>security.dhparams.path</option>. Otherwise the files are
|
|
created within the Nix store.
|
|
|
|
<note><para>If this is <literal>false</literal> the resulting store
|
|
path will be non-deterministic and will be rebuilt every time the
|
|
<package>openssl</package> package changes.</para></note>
|
|
'';
|
|
};
|
|
|
|
path = mkOption {
|
|
type = types.str;
|
|
default = "/var/lib/dhparams";
|
|
description = ''
|
|
Path to the directory in which Diffie-Hellman parameters will be
|
|
stored. This only is relevant if
|
|
<option>security.dhparams.stateful</option> is
|
|
<literal>true</literal>.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf (cfg.enable && cfg.stateful) {
|
|
systemd.services = {
|
|
dhparams-init = {
|
|
description = "Clean Up Old Diffie-Hellman Parameters";
|
|
|
|
# Clean up even when no DH params is set
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
serviceConfig.RemainAfterExit = true;
|
|
serviceConfig.Type = "oneshot";
|
|
|
|
script = ''
|
|
if [ ! -d ${cfg.path} ]; then
|
|
mkdir -p ${cfg.path}
|
|
fi
|
|
|
|
# Remove old dhparams
|
|
for file in ${cfg.path}/*; do
|
|
if [ ! -f "$file" ]; then
|
|
continue
|
|
fi
|
|
${lib.concatStrings (lib.mapAttrsToList (name: { bits, path, ... }: ''
|
|
if [ "$file" = ${lib.escapeShellArg path} ] && \
|
|
${pkgs.openssl}/bin/openssl dhparam -in "$file" -text \
|
|
| head -n 1 | grep "(${toString bits} bit)" > /dev/null; then
|
|
continue
|
|
fi
|
|
'') cfg.params)}
|
|
rm $file
|
|
done
|
|
|
|
# TODO: Ideally this would be removing the *former* cfg.path, though
|
|
# this does not seem really important as changes to it are quite
|
|
# unlikely
|
|
rmdir --ignore-fail-on-non-empty ${cfg.path}
|
|
'';
|
|
};
|
|
} // lib.mapAttrs' (name: { bits, path, ... }: lib.nameValuePair "dhparams-gen-${name}" {
|
|
description = "Generate Diffie-Hellman Parameters for ${name}";
|
|
after = [ "dhparams-init.service" ];
|
|
before = [ "${name}.service" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
unitConfig.ConditionPathExists = "!${path}";
|
|
serviceConfig.Type = "oneshot";
|
|
script = ''
|
|
mkdir -p ${lib.escapeShellArg cfg.path}
|
|
${pkgs.openssl}/bin/openssl dhparam -out ${lib.escapeShellArg path} \
|
|
${toString bits}
|
|
'';
|
|
}) cfg.params;
|
|
};
|
|
}
|