nixos/dhparams: remove (#524658)
This commit is contained in:
@@ -394,7 +394,6 @@
|
||||
./security/ca.nix
|
||||
./security/chromium-suid-sandbox.nix
|
||||
./security/default.nix
|
||||
./security/dhparams.nix
|
||||
./security/doas.nix
|
||||
./security/duosec.nix
|
||||
./security/google_oslogin.nix
|
||||
|
||||
@@ -125,6 +125,9 @@ in
|
||||
(mkRemovedOptionModule [ "programs" "yabar" ]
|
||||
"programs.yabar has been removed from NixOS. This is because the yabar repository has been archived upstream."
|
||||
)
|
||||
(mkRemovedOptionModule [ "security" "dhparams" ] ''
|
||||
The security.dhparams module has been removed as RFC 7919 has shown that generating your own params is problematic.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "security" "hideProcessInformation" ] ''
|
||||
The hidepid module was removed, since the underlying machinery
|
||||
is broken when using cgroups-v2.
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
options,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) literalExpression mkOption types;
|
||||
cfg = config.security.dhparams;
|
||||
opt = options.security.dhparams;
|
||||
|
||||
bitType = types.addCheck types.int (b: b >= 16) // {
|
||||
name = "bits";
|
||||
description = "integer of at least 16 bits";
|
||||
};
|
||||
|
||||
paramsSubmodule =
|
||||
{ name, config, ... }:
|
||||
{
|
||||
options.bits = mkOption {
|
||||
type = bitType;
|
||||
default = cfg.defaultBitSize;
|
||||
defaultText = literalExpression "config.${opt.defaultBitSize}";
|
||||
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`.
|
||||
'';
|
||||
};
|
||||
|
||||
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.literalExpression "{ 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
|
||||
`config.security.dhparams.params.«name».path`.
|
||||
|
||||
::: {.note}
|
||||
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.
|
||||
:::
|
||||
|
||||
::: {.warning}
|
||||
If you are removing all dhparams from this list, you
|
||||
have to leave {option}`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. Of course this only applies if
|
||||
{option}`security.dhparams.stateful` is
|
||||
`true`.
|
||||
:::
|
||||
|
||||
::: {.note}
|
||||
**For module implementers:** It's recommended
|
||||
to not set a specific bit size here, so that users can easily
|
||||
override this by setting
|
||||
{option}`security.dhparams.defaultBitSize`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
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`. Otherwise the files are
|
||||
created within the Nix store.
|
||||
|
||||
::: {.note}
|
||||
If this is `false` the resulting store
|
||||
path will be non-deterministic and will be rebuilt every time the
|
||||
`openssl` package changes.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
defaultBitSize = mkOption {
|
||||
type = bitType;
|
||||
default = 2048;
|
||||
description = ''
|
||||
This allows to override the default bit size for all of the
|
||||
Diffie-Hellman parameters set in
|
||||
{option}`security.dhparams.params`.
|
||||
'';
|
||||
};
|
||||
|
||||
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` is
|
||||
`true`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf cfg.enable {
|
||||
warnings = [
|
||||
''
|
||||
The `security.dhparams` module is deprecated and scheduled for removal in NixOS 26.11.
|
||||
Generating your own params has been shown to be problematic in RFC 7919 (2016).
|
||||
|
||||
Remove any uses of DHE and migrate to ECDHE (RFC 8422, 2018) and
|
||||
Hybrid PQ (draft-ietf-tls-ecdhe-mlkem, 2026) key exchange algorithms.
|
||||
''
|
||||
];
|
||||
})
|
||||
(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" ];
|
||||
requiredBy = [ "${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;
|
||||
})
|
||||
];
|
||||
|
||||
}
|
||||
@@ -455,7 +455,6 @@ in
|
||||
dependency-track = runTest ./dependency-track.nix;
|
||||
devpi-server = runTest ./devpi-server.nix;
|
||||
dex-oidc = runTest ./dex-oidc.nix;
|
||||
dhparams = runTest ./dhparams.nix;
|
||||
dictd = runTest ./dictd.nix;
|
||||
disable-installer-tools = runTest ./disable-installer-tools.nix;
|
||||
discourse = runTest {
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
{
|
||||
name = "dhparams";
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
security.dhparams.enable = true;
|
||||
environment.systemPackages = [ pkgs.openssl ];
|
||||
|
||||
specialisation = {
|
||||
gen1.configuration =
|
||||
{ config, ... }:
|
||||
{
|
||||
security.dhparams.params = {
|
||||
# Use low values here because we don't want the test to run for ages.
|
||||
foo.bits = 1024;
|
||||
# Also use the old format to make sure the type is coerced in the right
|
||||
# way.
|
||||
bar = 1025;
|
||||
};
|
||||
|
||||
systemd.services.foo = {
|
||||
description = "Check systemd Ordering";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "shutdown.target" ];
|
||||
conflicts = [ "shutdown.target" ];
|
||||
unitConfig = {
|
||||
# This is to make sure that the dhparams generation of foo occurs
|
||||
# before this service so we need this service to start as early as
|
||||
# possible to provoke a race condition.
|
||||
DefaultDependencies = false;
|
||||
|
||||
# We check later whether the service has been started or not.
|
||||
ConditionPathExists = config.security.dhparams.params.foo.path;
|
||||
};
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
# The reason we only provide an ExecStop here is to ensure that we don't
|
||||
# accidentally trigger an error because a file system is not yet ready
|
||||
# during very early startup (we might not even have the Nix store
|
||||
# available, for example if future changes in NixOS use systemd mount
|
||||
# units to do early file system initialisation).
|
||||
serviceConfig.ExecStop = "${pkgs.coreutils}/bin/true";
|
||||
};
|
||||
};
|
||||
gen2.configuration = {
|
||||
security.dhparams.params.foo.bits = 1026;
|
||||
};
|
||||
gen3.configuration = { };
|
||||
gen4.configuration = {
|
||||
security.dhparams.stateful = false;
|
||||
security.dhparams.params.foo2.bits = 1027;
|
||||
security.dhparams.params.bar2.bits = 1028;
|
||||
};
|
||||
gen5.configuration = {
|
||||
security.dhparams.defaultBitSize = 1029;
|
||||
security.dhparams.params.foo3 = { };
|
||||
security.dhparams.params.bar3 = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
let
|
||||
getParamPath =
|
||||
gen: name:
|
||||
let
|
||||
node = "gen${toString gen}";
|
||||
in
|
||||
nodes.machine.config.specialisation.${node}.configuration.security.dhparams.params.${name}.path;
|
||||
|
||||
switchToGeneration =
|
||||
gen:
|
||||
let
|
||||
switchCmd = "${nodes.machine.config.system.build.toplevel}/specialisation/gen${toString gen}/bin/switch-to-configuration test";
|
||||
in
|
||||
''
|
||||
with machine.nested("switch to generation ${toString gen}"):
|
||||
machine.succeed("${switchCmd}")
|
||||
'';
|
||||
|
||||
in
|
||||
''
|
||||
import re
|
||||
|
||||
|
||||
def assert_param_bits(path, bits):
|
||||
with machine.nested(f"check bit size of {path}"):
|
||||
output = machine.succeed(f"openssl dhparam -in {path} -text")
|
||||
pattern = re.compile(r"^\s*DH Parameters:\s+\((\d+)\s+bit\)\s*$", re.M)
|
||||
match = pattern.match(output)
|
||||
if match is None:
|
||||
raise Exception("bla")
|
||||
if match[1] != str(bits):
|
||||
raise Exception(f"bit size should be {bits} but it is {match[1]} instead.")
|
||||
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
${switchToGeneration 1}
|
||||
|
||||
with subtest("verify startup order"):
|
||||
machine.succeed("systemctl is-active foo.service")
|
||||
|
||||
with subtest("check bit sizes of dhparam files"):
|
||||
assert_param_bits("${getParamPath 1 "foo"}", 1024)
|
||||
assert_param_bits("${getParamPath 1 "bar"}", 1025)
|
||||
|
||||
${switchToGeneration 2}
|
||||
|
||||
with subtest("check whether bit size has changed"):
|
||||
assert_param_bits("${getParamPath 2 "foo"}", 1026)
|
||||
|
||||
with subtest("ensure that dhparams file for 'bar' was deleted"):
|
||||
machine.fail("test -e ${getParamPath 1 "bar"}")
|
||||
|
||||
${switchToGeneration 3}
|
||||
|
||||
with subtest("ensure that 'security.dhparams.path' has been deleted"):
|
||||
machine.fail("test -e ${nodes.machine.config.specialisation.gen3.configuration.security.dhparams.path}")
|
||||
|
||||
${switchToGeneration 4}
|
||||
|
||||
with subtest("check bit sizes dhparam files"):
|
||||
assert_param_bits(
|
||||
"${getParamPath 4 "foo2"}", 1027
|
||||
)
|
||||
assert_param_bits(
|
||||
"${getParamPath 4 "bar2"}", 1028
|
||||
)
|
||||
|
||||
with subtest("check whether dhparam files are in the Nix store"):
|
||||
machine.succeed(
|
||||
"expr match ${getParamPath 4 "foo2"} ${builtins.storeDir}",
|
||||
"expr match ${getParamPath 4 "bar2"} ${builtins.storeDir}",
|
||||
)
|
||||
|
||||
${switchToGeneration 5}
|
||||
|
||||
with subtest("check whether defaultBitSize works as intended"):
|
||||
assert_param_bits("${getParamPath 5 "foo3"}", 1029)
|
||||
assert_param_bits("${getParamPath 5 "bar3"}", 1029)
|
||||
'';
|
||||
}
|
||||
Reference in New Issue
Block a user