nixos/modules: Add security.pki.caBundle option and make all services use it for CA bundles (#352244)

Previously some modules used `config.environment.etc."ssl/certs/ca-certificates.crt".source`, some used `"/etc/ssl/certs/ca-certificates.crt"`, and some used `"${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"`. These were all bad in one way or another:

- `config.environment.etc."ssl/certs/ca-certificates.crt".source` relies on `source` being set; if `text` is set instead this breaks, introducing a weird undocumented requirement
- `"/etc/ssl/certs/ca-certificates.crt"` is probably okay but very un-nix. It's a magic string, and the path doesn't change when the file changes (and so you can't trigger service reloads, for example, when the contents change in a new system activation)
- `"${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"` silently doesn't include the options from `security.pki`

Co-authored-by: Shelvacu <git@shelvacu.com>
This commit is contained in:
shelvacu 2025-03-08 00:41:08 -08:00 committed by GitHub
parent f5dadc8f64
commit 1a4575f9db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 56 additions and 48 deletions

View file

@ -540,6 +540,8 @@
- `services.avahi.ipv6` now defaults to true.
- All services that require a root certificate bundle now use the value of a new read-only option, `security.pki.caBundle`.
- hddfancontrol has been updated to major release 2. See the [migration guide](https://github.com/desbma/hddfancontrol/tree/master?tab=readme-ov-file#migrating-from-v1x), as there are breaking changes.
- The Home Assistant module has new options {option}`services.home-assistant.blueprints.automation`, `services.home-assistant.blueprints.script`, and {option}`services.home-assistant.blueprints.template` that allow for the declarative installation of [blueprints](https://www.home-assistant.io/docs/blueprint/) into the appropriate configuration directories.

View file

@ -5,7 +5,6 @@
...
}:
let
cfg = config.security.pki;
cacertPackage = pkgs.cacert.override {
@ -88,22 +87,31 @@ in
'';
};
security.pki.caBundle = lib.mkOption {
type = lib.types.path;
readOnly = true;
description = ''
(Read-only) the path to the final bundle of certificate authorities as a single file.
'';
};
};
config = lib.mkIf cfg.installCACerts {
config = lib.mkMerge [
(lib.mkIf cfg.installCACerts {
# NixOS canonical location + Debian/Ubuntu/Arch/Gentoo compatibility.
environment.etc."ssl/certs/ca-certificates.crt".source = caBundle;
# NixOS canonical location + Debian/Ubuntu/Arch/Gentoo compatibility.
environment.etc."ssl/certs/ca-certificates.crt".source = caBundle;
# Old NixOS compatibility.
environment.etc."ssl/certs/ca-bundle.crt".source = caBundle;
# Old NixOS compatibility.
environment.etc."ssl/certs/ca-bundle.crt".source = caBundle;
# CentOS/Fedora compatibility.
environment.etc."pki/tls/certs/ca-bundle.crt".source = caBundle;
# CentOS/Fedora compatibility.
environment.etc."pki/tls/certs/ca-bundle.crt".source = caBundle;
# P11-Kit trust source.
environment.etc."ssl/trust-source".source = "${cacertPackage.p11kit}/etc/ssl/trust-source";
};
# P11-Kit trust source.
environment.etc."ssl/trust-source".source = "${cacertPackage.p11kit}/etc/ssl/trust-source";
})
{ security.pki.caBundle = caBundle; }
];
}

View file

@ -59,7 +59,7 @@ in
BindReadOnlyPaths = [
# gonic can access scrobbling services
"-/etc/resolv.conf"
"-/etc/ssl/certs/ca-certificates.crt"
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
builtins.storeDir
] ++ cfg.settings.music-path
++ lib.optional (cfg.settings.tls-cert != null) cfg.settings.tls-cert

View file

@ -118,9 +118,7 @@ in
BindReadOnlyPaths =
[
# navidrome uses online services to download additional album metadata / covers
"${
config.environment.etc."ssl/certs/ca-certificates.crt".source
}:/etc/ssl/certs/ca-certificates.crt"
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
builtins.storeDir
"/etc"
]

View file

@ -213,7 +213,7 @@ in
rm -f config/autoregister.properties
ln -s "${pkgs.writeText "autoregister.properties" cfg.agentConfig}" config/autoregister.properties
${pkgs.git}/bin/git config --global --add http.sslCAinfo /etc/ssl/certs/ca-certificates.crt
${pkgs.git}/bin/git config --global --add http.sslCAinfo ${config.security.pki.caBundle}
${pkgs.jre}/bin/java ${lib.concatStringsSep " " cfg.startupOptions} \
${lib.concatStringsSep " " cfg.extraOptions} \
-jar ${pkgs.gocd-agent}/go-agent/agent-bootstrapper.jar \

View file

@ -217,7 +217,7 @@ in
path = cfg.packages;
script = ''
${pkgs.git}/bin/git config --global --add http.sslCAinfo /etc/ssl/certs/ca-certificates.crt
${pkgs.git}/bin/git config --global --add http.sslCAinfo ${config.security.pki.caBundle}
${pkgs.jre}/bin/java -server ${concatStringsSep " " cfg.startupOptions} \
${concatStringsSep " " cfg.extraOptions} \
-jar ${pkgs.gocd-server}/go-server/lib/go.jar

View file

@ -591,10 +591,11 @@ in
tlsTrustedAuthorities = lib.mkOption {
type = lib.types.str;
default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
defaultText = lib.literalExpression ''"''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"'';
default = config.security.pki.caBundle;
defaultText = lib.literalExpression "config.security.pki.caBundle";
example = lib.literalExpression ''"''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"'';
description = ''
File containing trusted certification authorities (CA) to verify certificates of mailservers contacted for mail delivery. This basically sets smtp_tls_CAfile and enables opportunistic tls. Defaults to NixOS trusted certification authorities.
File containing trusted certification authorities (CA) to verify certificates of mailservers contacted for mail delivery. This sets [smtp_tls_CAfile](https://www.postfix.org/postconf.5.html#smtp_tls_CAfile). Defaults to system trusted certificates (see `security.pki.*` options).
'';
};

View file

@ -162,7 +162,7 @@ in
};
environment = {
NODE_ENV = "production";
NODE_EXTRA_CA_CERTS = "/etc/ssl/certs/ca-certificates.crt";
NODE_EXTRA_CA_CERTS = config.security.pki.caBundle;
HOSTNAME = cfg.host;
PORT = toString cfg.port;
};

View file

@ -244,7 +244,7 @@ let
${optionalString (cfg.smtp.authentication != null) "authentication: :${cfg.smtp.authentication},"}
enable_starttls_auto: ${boolToString cfg.smtp.enableStartTLSAuto},
tls: ${boolToString cfg.smtp.tls},
ca_file: "/etc/ssl/certs/ca-certificates.crt",
ca_file: "${config.security.pki.caBundle}",
openssl_verify_mode: '${cfg.smtp.opensslVerifyMode}'
}
end

View file

@ -285,7 +285,7 @@ in
in
{
PORTUNUS_SERVER_HTTP_SECURE = "true";
PORTUNUS_SLAPD_TLS_CA_CERTIFICATE = "/etc/ssl/certs/ca-certificates.crt";
PORTUNUS_SLAPD_TLS_CA_CERTIFICATE = config.security.pki.caBundle;
PORTUNUS_SLAPD_TLS_CERTIFICATE = "${acmeDirectory}/cert.pem";
PORTUNUS_SLAPD_TLS_DOMAIN_NAME = cfg.domain;
PORTUNUS_SLAPD_TLS_PRIVATE_KEY = "${acmeDirectory}/key.pem";

View file

@ -45,6 +45,7 @@ let
BindReadOnlyPaths = [
"${cfg.configFile}:${env.RAD_HOME}/config.json"
"${if lib.types.path.check cfg.publicKey then cfg.publicKey else pkgs.writeText "radicle.pub" cfg.publicKey}:${env.RAD_HOME}/keys/radicle.pub"
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
];
KillMode = "process";
StateDirectory = [ "radicle" ];
@ -57,7 +58,6 @@ let
{
BindReadOnlyPaths = [
"-/etc/resolv.conf"
"/etc/ssl/certs/ca-certificates.crt"
"/run/systemd"
];
AmbientCapabilities = "";

View file

@ -118,9 +118,7 @@ in
RuntimeDirectory = "tandoor-recipes";
BindReadOnlyPaths = [
"${
config.environment.etc."ssl/certs/ca-certificates.crt".source
}:/etc/ssl/certs/ca-certificates.crt"
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
builtins.storeDir
"-/etc/resolv.conf"
"-/etc/nsswitch.conf"

View file

@ -53,7 +53,8 @@ in
ca = lib.mkOption {
type = lib.types.path;
default = "/etc/ssl/certs/ca-certificates.crt";
default = config.security.pki.caBundle;
defaultText = lib.literalExpression "config.security.pki.caBundle";
description = ''
Path to CA certificates file in PEM format, for server
SSL certificate validation.
@ -72,7 +73,6 @@ in
};
default = { };
example = {
ca = "/etc/ssl/certs/ca-certificates.crt";
debug = true;
server = "https://ocsinventory.localhost:8080/ocsinventory";
tag = "01234567890123";

View file

@ -371,7 +371,8 @@ in
cert_path = lib.mkOption {
type = lib.types.path;
default = "/etc/ssl/certs/ca-certificates.crt";
default = config.security.pki.caBundle;
defaultText = lib.literalExpression "config.security.pki.caBundle";
description = ''
The path to a TLS certificate bundle used to verify
the server's certificate.

View file

@ -24,7 +24,7 @@ in
default = { };
example = {
PORT = "4000";
NODE_EXTRA_CA_CERTS = "/etc/ssl/certs/ca-certificates.crt";
NODE_EXTRA_CA_CERTS = lib.literalExpression "config.security.pki.caBundle";
};
description = ''
Additional configuration for Uptime Kuma, see

View file

@ -57,7 +57,8 @@ in
};
options.ca_file = lib.mkOption {
type = lib.types.path;
default = "/etc/ssl/certs/ca-certificates.crt";
default = config.security.pki.caBundle;
defaultText = lib.literalExpression "config.security.pki.caBundle";
description = ''
Specifies which file should be used as the list of trusted CA
when negotiating a TLS session.

View file

@ -282,9 +282,8 @@ in
# This allows setting absolute key/crt paths
ca-directory = "/var/empty";
certificate-directory = "/run/privoxy/certs";
trusted-cas-file = "/etc/ssl/certs/ca-certificates.crt";
trusted-cas-file = config.security.pki.caBundle;
});
};
imports =

View file

@ -123,7 +123,7 @@ in
description = ''
Define the client configurations.
By default, verifyChain and OCSPaia are enabled and a CAFile is provided from pkgs.cacert.
By default, verifyChain and OCSPaia are enabled and CAFile is set to `security.pki.caBundle`.
See "SERVICE-LEVEL OPTIONS" in {manpage}`stunnel(8)`.
'';
@ -144,7 +144,7 @@ in
applyDefaults =
c:
{
CAFile = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
CAFile = config.security.pki.caBundle;
OCSPaia = true;
verifyChain = true;
}

View file

@ -195,7 +195,7 @@ in {
interface = mkDefault ([ "127.0.0.1" ] ++ (optional config.networking.enableIPv6 "::1"));
access-control = mkDefault ([ "127.0.0.0/8 allow" ] ++ (optional config.networking.enableIPv6 "::1/128 allow"));
auto-trust-anchor-file = mkIf cfg.enableRootTrustAnchor rootTrustAnchorFile;
tls-cert-bundle = mkDefault "/etc/ssl/certs/ca-certificates.crt";
tls-cert-bundle = mkDefault config.security.pki.caBundle;
# prevent race conditions on system startup when interfaces are not yet
# configured
ip-freebind = mkDefault true;

View file

@ -118,7 +118,7 @@ in
User = cfg.user;
Group = cfg.group;
WorkingDirectory = cfg.home;
ExecStartPre = "${pkgs.git}/bin/git config --global --replace-all http.sslCAinfo /etc/ssl/certs/ca-certificates.crt";
ExecStartPre = "${pkgs.git}/bin/git config --global --replace-all http.sslCAinfo ${config.security.pki.caBundle}";
ExecStart = "${cfg.package}/bin/houndd -addr ${cfg.listen} -conf /etc/hound/config.json";
};
};

View file

@ -218,7 +218,7 @@ in
environment =
cfg.envVars
// {
CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
CURL_CA_BUNDLE = config.security.pki.caBundle;
}
// config.networking.proxy.envVars;

View file

@ -361,7 +361,7 @@ in
wantedBy = [ "multi-user.target" ];
environment = {
CURL_CA_BUNDLE = etc."ssl/certs/ca-certificates.crt".source;
CURL_CA_BUNDLE = config.security.pki.caBundle;
TRANSMISSION_WEB_HOME = lib.mkIf (cfg.webHome != null) cfg.webHome;
};

View file

@ -239,7 +239,7 @@ in
"-/etc/resolv.conf"
"-/run/systemd"
"/etc/hosts"
"/etc/ssl/certs/ca-certificates.crt"
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
];
};
};

View file

@ -117,7 +117,7 @@ in
"-/etc/localtime"
"-/etc/nsswitch.conf"
"-/etc/resolv.conf"
"-/etc/ssl/certs/ca-certificates.crt"
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
];
BindPaths = optional (cfg.settings.storage.type == "postgres") "/var/run/postgresql";
# ProtectClock= adds DeviceAllow=char-rtc r

View file

@ -132,7 +132,7 @@ in
"opcache.memory_consumption" = "128";
"opcache.revalidate_freq" = "1";
"opcache.fast_shutdown" = "1";
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
"openssl.cafile" = config.security.pki.caBundle;
catch_workers_output = "yes";
upload_max_filesize = cfg.maxUploadSize;

View file

@ -19,7 +19,7 @@ let
"opcache.memory_consumption" = "128";
"opcache.revalidate_freq" = "1";
"opcache.fast_shutdown" = "1";
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
"openssl.cafile" = config.security.pki.caBundle;
catch_workers_output = "yes";
};
@ -400,7 +400,7 @@ in {
phpOptions = mkOption {
type = with types; attrsOf (oneOf [ str int ]);
defaultText = literalExpression (generators.toPretty { } defaultPHPSettings);
defaultText = literalExpression (generators.toPretty { } (defaultPHPSettings // { "openssl.cafile" = literalExpression "config.security.pki.caBundle"; }));
description = ''
Options for PHP's php.ini file for nextcloud.

View file

@ -16,7 +16,7 @@ let
env = {
NODE_CONFIG_DIR = "/var/lib/peertube/config";
NODE_ENV = "production";
NODE_EXTRA_CA_CERTS = "/etc/ssl/certs/ca-certificates.crt";
NODE_EXTRA_CA_CERTS = config.security.pki.caBundle;
NPM_CONFIG_CACHE = "/var/cache/peertube/.npm";
NPM_CONFIG_PREFIX = cfg.package;
HOME = cfg.package;

View file

@ -113,7 +113,7 @@ in
wantedBy = [ "multi-user.target" ];
restartTriggers = [ config.environment.etc."sogo/sogo.conf.raw".source ];
environment.LDAPTLS_CACERT = "/etc/ssl/certs/ca-certificates.crt";
environment.LDAPTLS_CACERT = config.security.pki.caBundle;
serviceConfig = {
Type = "forking";