diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 51392f6ce885..e209c36cee45 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -168,7 +168,7 @@ let selfsignService = { description = "Generate self-signed certificate for ${cert}"; after = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ]; - wants = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ]; + requires = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ]; path = with pkgs; [ minica ]; @@ -232,6 +232,15 @@ let # Only try loading the credentialsFile if the dns challenge is enabled EnvironmentFile = mkIf useDns data.credentialsFile; + + # Run as root (Prefixed with +) + ExecStartPost = "+" + (pkgs.writeShellScript "acme-postrun" '' + cd /var/lib/acme/${escapeShellArg cert} + if [ -e renewed ]; then + rm renewed + ${data.postRun} + fi + ''); }; # Working directory will be /tmp @@ -255,9 +264,8 @@ let # Copy all certs to the "real" certs directory CERT='certificates/${keyName}.crt' - CERT_CHANGED=no if [ -e "$CERT" ] && ! cmp -s "$CERT" out/fullchain.pem; then - CERT_CHANGED=yes + touch out/renewed echo Installing new certificate cp -vp 'certificates/${keyName}.crt' out/fullchain.pem cp -vp 'certificates/${keyName}.key' out/key.pem @@ -265,12 +273,6 @@ let ln -sf fullchain.pem out/cert.pem cat out/key.pem out/fullchain.pem > out/full.pem fi - - if [ "$CERT_CHANGED" = "yes" ]; then - cd out - set +euo pipefail - ${data.postRun} - fi ''; }; }; @@ -344,7 +346,7 @@ let example = "cp full.pem backup.pem"; description = '' Commands to run after new certificates go live. Note that - these commands run as the acme user and configured group. + these commands run as the root user. Executed in the same directory with the new certificate. ''; @@ -648,7 +650,7 @@ in { # Create some targets which can be depended on to be "active" after cert renewals systemd.targets = mapAttrs' (cert: conf: nameValuePair "acme-finished-${cert}" { wantedBy = [ "default.target" ]; - wants = [ "acme-${cert}.service" "acme-selfsigned-${cert}.service" ]; + requires = [ "acme-${cert}.service" "acme-selfsigned-${cert}.service" ]; after = [ "acme-${cert}.service" "acme-selfsigned-${cert}.service" ]; }) certConfigs; }) diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index 90ae06542c4c..223945907da9 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -79,8 +79,15 @@ in import ./make-test-python.nix ({ lib, ... }: { # Cert config changes will not cause the nginx configuration to change. # This tests that the reload service is correctly triggered. + # It also tests that postRun is exec'd as root specialisation.cert-change.configuration = { pkgs, ... }: { security.acme.certs."a.example.test".keyType = "ec384"; + security.acme.certs."a.example.test".postRun = '' + set -euo pipefail + touch test + chown root:root test + echo testing > test + ''; }; # Now adding an alias to ensure that the certs are updated @@ -283,6 +290,7 @@ in import ./make-test-python.nix ({ lib, ... }: { switch_to(webserver, "cert-change") webserver.wait_for_unit("acme-finished-a.example.test.target") check_connection_key_bits(client, "a.example.test", "384") + webserver.succeed("grep testing /var/lib/acme/a.example.test/test") with subtest("Can request certificate with HTTPS-01 when nginx startup is delayed"): switch_to(webserver, "slow-startup")