nixos/dhparams: Turn params into a submodule

We're going to implement an option which allows us to turn off stateful
handling of Diffie-Hellman parameter files by putting them into the Nix
store.

However, modules now might need a way to reference these files, so we
add a now path option to every param specified, which carries a
read-only value of the path where to find the corresponding DH params
file.

I've also improved the description of security.dhparams.params a bit so
that it uses <warning/> and <note/>.

The NixOS VM test also reflects this change and checks whether the old
way to specify the bit size still works.

Signed-off-by: aszlig <aszlig@nix.build>
Cc: @Ekleog
This commit is contained in:
aszlig 2018-04-26 06:19:48 +02:00
parent 4de774a63b
commit 761266bd18
No known key found for this signature in database
GPG key ID: 684089CE67EBB691
2 changed files with 57 additions and 23 deletions

View file

@ -1,10 +1,38 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.security.dhparams;
in
{
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 = "${cfg.path}/${name}.pem";
};
in {
options = {
security.dhparams = {
params = mkOption {
@ -14,21 +42,23 @@ in
The value is the size (in bits) of the DH params to generate. The
generated DH params path can be found in
<filename><replaceable>security.dhparams.path</replaceable>/<replaceable>name</replaceable>.pem</filename>.
<literal>config.security.dhparams.params.<replaceable>name</replaceable>.path</literal>.
Note: The name of the DH params is taken as being the name of the
service it serves: the params will be generated before the said
service is started.
<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: If you are removing all dhparams from this list, you have
to leave security.dhparams.enable 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.
<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.</para></warning>
'';
type = with types; attrsOf int;
type = with types; let
coerce = bits: { inherit bits; };
in attrsOf (coercedTo types.int coerce (submodule paramsSubmodule));
default = {};
example = { nginx = 3072; };
example = literalExample "{ nginx.bits = 3072; }";
};
path = mkOption {
@ -71,10 +101,10 @@ in
if [ ! -f "$file" ]; then
continue
fi
'' + concatStrings (mapAttrsToList (name: value:
'' + concatStrings (mapAttrsToList (name: { bits, ... }:
''
if [ "$file" == "${cfg.path}/${name}.pem" ] && \
${pkgs.openssl}/bin/openssl dhparam -in "$file" -text | head -n 1 | grep "(${toString value} bit)" > /dev/null; then
${pkgs.openssl}/bin/openssl dhparam -in "$file" -text | head -n 1 | grep "(${toString bits} bit)" > /dev/null; then
continue
fi
''
@ -89,7 +119,7 @@ in
'';
};
} //
mapAttrs' (name: value: nameValuePair "dhparams-gen-${name}" {
mapAttrs' (name: { bits, ... }: nameValuePair "dhparams-gen-${name}" {
description = "Generate Diffie-Hellman parameters for ${name} if they don't exist yet";
after = [ "dhparams-init.service" ];
before = [ "${name}.service" ];
@ -99,7 +129,7 @@ in
''
mkdir -p ${cfg.path}
if [ ! -f ${cfg.path}/${name}.pem ]; then
${pkgs.openssl}/bin/openssl dhparam -out ${cfg.path}/${name}.pem ${toString value}
${pkgs.openssl}/bin/openssl dhparam -out ${cfg.path}/${name}.pem ${toString bits}
fi
'';
}) cfg.params;

View file

@ -9,8 +9,13 @@ in import ./make-test.nix {
nodes.generation1 = { pkgs, config, ... }: {
imports = [ common ];
security.dhparams.params.foo = 16;
security.dhparams.params.bar = 17;
security.dhparams.params = {
# Use low values here because we don't want the test to run for ages.
foo.bits = 16;
# Also use the old format to make sure the type is coerced in the right
# way.
bar = 17;
};
systemd.services.foo = {
description = "Check systemd Ordering";
@ -22,7 +27,7 @@ in import ./make-test.nix {
DefaultDependencies = false;
# We check later whether the service has been started or not.
ConditionPathExists = "${config.security.dhparams.path}/foo.pem";
ConditionPathExists = config.security.dhparams.params.foo.path;
};
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
@ -37,7 +42,7 @@ in import ./make-test.nix {
nodes.generation2 = {
imports = [ common ];
security.dhparams.params.foo = 18;
security.dhparams.params.foo.bits = 18;
};
nodes.generation3 = common;
@ -45,8 +50,7 @@ in import ./make-test.nix {
testScript = { nodes, ... }: let
getParamPath = gen: name: let
node = "generation${toString gen}";
inherit (nodes.${node}.config.security.dhparams) path;
in "${path}/${name}.pem";
in nodes.${node}.config.security.dhparams.params.${name}.path;
assertParamBits = gen: name: bits: let
path = getParamPath gen name;