diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 1b116482caeb..57e83a4a27b7 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -3,6 +3,7 @@ with lib; let cfg = config.security.acme; opt = options.security.acme; + user = if cfg.useRoot then "root" else "acme"; # Used to calculate timer accuracy for coalescing numCerts = length (builtins.attrNames cfg.certs); @@ -23,7 +24,7 @@ let # security.acme.certs..group on some of the services. commonServiceConfig = { Type = "oneshot"; - User = "acme"; + User = user; Group = mkDefault "acme"; UMask = 0022; StateDirectoryMode = 750; @@ -101,12 +102,12 @@ let # is configurable on a per-cert basis. userMigrationService = let script = with builtins; '' - chown -R acme .lego/accounts + chown -R ${user} .lego/accounts '' + (concatStringsSep "\n" (mapAttrsToList (cert: data: '' for fixpath in ${escapeShellArg cert} .lego/${escapeShellArg cert}; do if [ -d "$fixpath" ]; then chmod -R u=rwX,g=rX,o= "$fixpath" - chown -R acme:${data.group} "$fixpath" + chown -R ${user}:${data.group} "$fixpath" fi done '') certConfigs)); @@ -268,7 +269,7 @@ let cat key.pem fullchain.pem > full.pem # Group might change between runs, re-apply it - chown 'acme:${data.group}' * + chown '${user}:${data.group}' * # Default permissions make the files unreadable by group + anon # Need to be readable by group @@ -403,7 +404,7 @@ let mv domainhash.txt certificates/ # Group might change between runs, re-apply it - chown 'acme:${data.group}' certificates/* + chown '${user}:${data.group}' certificates/* # Copy all certs to the "real" certs directory if ! cmp -s 'certificates/${keyName}.crt' out/fullchain.pem; then @@ -723,6 +724,18 @@ in { ''; }; + useRoot = mkOption { + type = types.bool; + default = false; + description = '' + Whether to use the root user when generating certs. This is not recommended + for security + compatiblity reasons. If a service requires root owned certificates + consider following the guide on "Using ACME with services demanding root + owned certificates" in the NixOS manual, and only using this as a fallback + or for testing. + ''; + }; + defaults = mkOption { type = types.submodule { options = inheritableOpts {}; }; description = '' diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index 549fa9e64eea..a4ed8fa67bfe 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -232,6 +232,13 @@ in { } ]; + use-root.configuration = { ... }: lib.mkMerge [ + webserverBasicConfig + { + security.acme.useRoot = true; + } + ]; + # Test compatibility with Nginx } // (mkServerConfigs { server = "nginx"; @@ -450,6 +457,12 @@ in { webserver.wait_for_unit("nginx.service") check_connection(client, "slow.example.com") + with subtest("Can set useRoot to true and still use certs normally"): + switch_to(webserver, "use-root") + webserver.wait_for_unit("nginx.service") + webserver.succeed("test \"$(stat -c '%U' /var/lib/acme/* | uniq)\" = \"root\"") + check_connection(client, "a.example.com") + domains = ["http", "dns", "wildcard"] for server, logsrc in [ ("nginx", "journalctl -n 30 -u nginx.service"),