summary refs log tree commit diff
diff options
context:
space:
mode:
authoraszlig <aszlig@nix.build>2018-04-26 06:38:02 +0200
committeraszlig <aszlig@nix.build>2018-04-26 08:04:50 +0200
commit3e11ff6e0d9fb21a962408407f24b465b30fe96f (patch)
tree99245ead49830503f7a5ce0f67150232b08795e5
parent761266bd18cf1117a11d2fd6168259f7fe867122 (diff)
downloadnixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.tar
nixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.tar.gz
nixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.tar.bz2
nixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.tar.lz
nixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.tar.xz
nixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.tar.zst
nixpkgs-3e11ff6e0d9fb21a962408407f24b465b30fe96f.zip
nixos/dhparams: Introduce a 'stateful' option
This option allows us to turn off stateful generation of Diffie-Hellman
parameters, which in some way is still stateful as the generated DH
params file is non-deterministic.

However what we can avoid with this is to have an increased surface for
failures during system startup, because generation of the parameters is
done during build-time.

Another advantage of this is that we no longer need to take care of
cleaning up the files that are no longer used and in my humble opinion I
would have preferred that #11505 (which puts the dhparams in the Nix
store) would have been merged instead of #22634 (which we have now).

Luckily we can still change that and this change gives the user the
option to put the dhparams into the Nix store.

Beside of the more obvious advantages pointed out here, this also
effects test runtime if more services are starting to use this (for
example see #39507 and #39288), because generating DH params could take
a long time depending on the bit size which adds up to test runtime.

If we generate the DH params in a separate derivation, subsequent test
runs won't need to wait for DH params generation during bootup.

Of course, tests could still mock this by force-disabling the service
and adding a service or activation script that places pre-generated DH
params in /var/lib/dhparams but this would make tests less readable and
the workaround would have to be made for each test affected.

Note that the 'stateful' option is still true by default so that we are
backwards-compatible with existing systems.

Signed-off-by: aszlig <aszlig@nix.build>
Cc: @Ekleog, @abbradar, @fpletz
-rw-r--r--nixos/modules/security/dhparams.nix39
-rw-r--r--nixos/tests/dhparams.nix21
2 files changed, 52 insertions, 8 deletions
diff --git a/nixos/modules/security/dhparams.nix b/nixos/modules/security/dhparams.nix
index 7c9fe986e57..64b296eea5b 100644
--- a/nixos/modules/security/dhparams.nix
+++ b/nixos/modules/security/dhparams.nix
@@ -29,7 +29,11 @@ let
       '';
     };
 
-    config.path = "${cfg.path}/${name}.pem";
+    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 {
@@ -52,7 +56,9 @@ in {
             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>
+            existing ones won't be cleaned up. Of course this only applies if
+            <option>security.dhparams.stateful</option> is
+            <literal>true</literal>.</para></warning>
           '';
         type = with types; let
           coerce = bits: { inherit bits; };
@@ -61,12 +67,29 @@ in {
         example = literalExample "{ nginx.bits = 3072; }";
       };
 
+      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 {
-        description =
-          ''
-            Path to the directory in which Diffie-Hellman parameters will be
-            stored.
-          '';
+        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>.
+        '';
         type = types.str;
         default = "/var/lib/dhparams";
       };
@@ -82,7 +105,7 @@ in {
     };
   };
 
-  config = mkIf cfg.enable {
+  config = mkIf (cfg.enable && cfg.stateful) {
     systemd.services = {
       dhparams-init = {
         description = "Cleanup old Diffie-Hellman parameters";
diff --git a/nixos/tests/dhparams.nix b/nixos/tests/dhparams.nix
index ead5f2efce7..da75391e4ce 100644
--- a/nixos/tests/dhparams.nix
+++ b/nixos/tests/dhparams.nix
@@ -47,6 +47,13 @@ in import ./make-test.nix {
 
   nodes.generation3 = common;
 
+  nodes.generation4 = {
+    imports = [ common ];
+    security.dhparams.stateful = false;
+    security.dhparams.params.foo2.bits = 18;
+    security.dhparams.params.bar2.bits = 19;
+  };
+
   testScript = { nodes, ... }: let
     getParamPath = gen: name: let
       node = "generation${toString gen}";
@@ -105,5 +112,19 @@ in import ./make-test.nix {
         'test -e ${nodes.generation3.config.security.dhparams.path}'
       );
     };
+
+    ${switchToGeneration 4}
+
+    subtest "check bit sizes dhparam files", sub {
+      ${assertParamBits 4 "foo2" 18}
+      ${assertParamBits 4 "bar2" 19}
+    };
+
+    subtest "check whether dhparam files are in the Nix store", sub {
+      $machine->succeed(
+        'expr match ${getParamPath 4 "foo2"} ${builtins.storeDir}',
+        'expr match ${getParamPath 4 "bar2"} ${builtins.storeDir}',
+      );
+    };
   '';
 }