nixos/acme: ensure web servers using certs can access them

Changed files
+36 -13
nixos
modules
security
services
web-servers
apache-httpd
caddy
nginx
tests
+1 -1
nixos/modules/module-list.nix
···
./programs/zsh/zsh-autosuggestions.nix
./programs/zsh/zsh-syntax-highlighting.nix
./rename.nix
-
./security/acme.nix
+
./security/acme
./security/apparmor.nix
./security/audit.nix
./security/auditd.nix
+1 -1
nixos/modules/security/acme.nix nixos/modules/security/acme/default.nix
···
meta = {
maintainers = lib.teams.acme.members;
-
doc = ./acme.xml;
+
doc = ./doc.xml;
};
}
nixos/modules/security/acme.xml nixos/modules/security/acme/doc.xml
+4
nixos/modules/security/acme/mk-cert-ownership-assertion.nix
···
+
{ cert, group, groups, user }: {
+
assertion = cert.group == group || builtins.any (u: u == user) groups.${cert.group}.members;
+
message = "Group for certificate ${cert.domain} must be ${group}, or user ${user} must be a member of group ${cert.group}";
+
}
+7 -1
nixos/modules/services/web-servers/apache-httpd/default.nix
···
cat ${php.phpIni} > $out
echo "$options" >> $out
'';
+
+
mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix;
in
···
`services.httpd.virtualHosts.<name>.useACMEHost` are mutually exclusive.
'';
}
-
];
+
] ++ map (name: mkCertOwnershipAssertion {
+
inherit (cfg) group user;
+
cert = config.security.acme.certs.${name};
+
groups = config.users.groups;
+
}) dependentCertNames;
warnings =
mapAttrsToList (name: hostOpts: ''
+10 -3
nixos/modules/services/web-servers/caddy/default.nix
···
'';
in
if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform then Caddyfile-formatted else Caddyfile;
+
+
acmeHosts = unique (catAttrs "useACMEHost" acmeVHosts);
+
+
mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix;
in
{
imports = [
···
{ assertion = cfg.adapter != "caddyfile" -> cfg.configFile != configFile;
message = "Any value other than 'caddyfile' is only valid when providing your own `services.caddy.configFile`";
}
-
];
+
] ++ map (name: mkCertOwnershipAssertion {
+
inherit (cfg) group user;
+
cert = config.security.acme.certs.${name};
+
groups = config.users.groups;
+
}) acmeHosts;
services.caddy.extraConfig = concatMapStringsSep "\n" mkVHostConf virtualHosts;
services.caddy.globalConfig = ''
···
security.acme.certs =
let
-
eachACMEHost = unique (catAttrs "useACMEHost" acmeVHosts);
-
reloads = map (useACMEHost: nameValuePair useACMEHost { reloadServices = [ "caddy.service" ]; }) eachACMEHost;
+
reloads = map (useACMEHost: nameValuePair useACMEHost { reloadServices = [ "caddy.service" ]; }) acmeHosts;
in
listToAttrs reloads;
+7 -1
nixos/modules/services/web-servers/nginx/default.nix
···
${user}:{PLAIN}${password}
'') authDef)
);
+
+
mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix;
in
{
···
services.nginx.virtualHosts.<name>.useACMEHost are mutually exclusive.
'';
}
-
];
+
] ++ map (name: mkCertOwnershipAssertion {
+
inherit (cfg) group user;
+
cert = config.security.acme.certs.${name};
+
groups = config.users.groups;
+
}) dependentCertNames;
systemd.services.nginx = {
description = "Nginx Web Server";
+6 -6
nixos/tests/acme.nix
···
baseConfig = { nodes, config, specialConfig ? {} }: lib.mkMerge [
{
security.acme = {
-
defaults = (dnsConfig nodes) // {
-
inherit group;
-
};
+
defaults = (dnsConfig nodes);
# One manual wildcard cert
certs."example.test" = {
domain = "*.example.test";
};
};
+
+
users.users."${config.services."${server}".user}".extraGroups = ["acme"];
services."${server}" = {
enable = true;
···
} // (let
baseCaddyConfig = { nodes, config, ... }: {
security.acme = {
-
defaults = (dnsConfig nodes) // {
-
group = config.services.caddy.group;
-
};
+
defaults = (dnsConfig nodes);
# One manual wildcard cert
certs."example.test" = {
domain = "*.example.test";
};
};
+
+
users.users."${config.services.caddy.user}".extraGroups = ["acme"];
services.caddy = {
enable = true;