Loading nixos/modules/security/acme/default.nix +21 −10 Original line number Diff line number Diff line Loading @@ -15,9 +15,21 @@ let numCerts = lib.length (builtins.attrNames cfg.certs); _24hSecs = 60 * 60 * 24; # The placerholder email address used by lego in case none gets passed placeholderEmail = "noemail@example.com"; # Used to make unique paths for each cert/account config set mkHash = with builtins; val: lib.substring 0 20 (hashString "sha256" val); mkAccountHash = acmeServer: data: mkHash "${toString acmeServer} ${data.keyType} ${data.email}"; mkAccountHash = acmeServer: data: mkHash ( lib.concatStringsSep " " [ (toString acmeServer) data.keyType (if (data.email != null) then data.email else placeholderEmail) ] ); accountDirRoot = "/var/lib/acme/.lego/accounts/"; isIP = Loading Loading @@ -273,6 +285,8 @@ let "--accept-tos" # Checking the option is covered by the assertions "--path" "." ] ++ lib.optionals (data.email != null) [ "--email" data.email ] Loading Loading @@ -580,7 +594,12 @@ let # Check if a new order is needed # We can only renew if the list of domains has not changed. # We also need an account key. Avoids #190493 if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && \ [ -e 'certificates/${keyName}.crt' ] && \ [ -n "$(find accounts -name '${ if (data.email != null) then data.email else placeholderEmail }.key')" ]; then # Even if a cert is not expired, it may be revoked by the CA. # Try to renew, and silently fail if the cert is not expired. # Avoids #85794 and resolves #129838 Loading Loading @@ -1118,14 +1137,6 @@ in certs = lib.attrValues cfg.certs; in [ { assertion = cfg.defaults.email != null || lib.all (certOpts: certOpts.email != null) certs; message = '' You must define `security.acme.certs.<name>.email` or `security.acme.defaults.email` to register with the CA. Note that using many different addresses for certs may trigger account rate limits. ''; } { assertion = cfg.acceptTerms; message = '' Loading nixos/tests/acme/http01-builtin.nix +21 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,14 @@ in }; accountchange.configuration = { security.acme.certs."${config.networking.fqdn}".email = "admin@example.test"; # Providing an email address is optional security.acme.certs."${config.networking.fqdn}".email = null; }; emailplaceholder.configuration = { # but Lego will default to this email address, which should not # result in any change when configured security.acme.certs."${config.networking.fqdn}".email = "noemail@example.com"; }; keytype.configuration = { Loading Loading @@ -157,6 +164,7 @@ in certName = nodes.builtin.networking.fqdn; caDomain = nodes.acme.test-support.acme.caDomain; in # python '' ${(import ./utils.nix).pythonUtils} Loading Loading @@ -217,11 +225,23 @@ in hash_after = builtin.succeed(f"sha256sum /var/lib/acme/{cert}/cert.pem") # Has to do a full run to register account, which creates new certs. assert hash != hash_after, "Certificate was not renewed" hash = hash_after builtin.succeed("systemctl stop renew-triggered.target") switch_to(builtin, "emailplaceholder") builtin.wait_for_unit("renew-triggered.target") # Check that there are still two account directories builtin.succeed("test $(ls -1 /var/lib/acme/.lego/accounts | tee /dev/stderr | wc -l) -eq 2") hash_after = builtin.succeed(f"sha256sum /var/lib/acme/{cert}/cert.pem") assert hash == hash_after, "Implicit to explicit email placeholder renewed the certificate" # Remove the new account directory builtin.succeed( "cd /var/lib/acme/.lego/accounts" " && ls -1 --sort=time | tee /dev/stderr | head -1 | xargs rm -rf" ) # old_hash will be used in the preservation tests later old_hash = hash_after Loading Loading
nixos/modules/security/acme/default.nix +21 −10 Original line number Diff line number Diff line Loading @@ -15,9 +15,21 @@ let numCerts = lib.length (builtins.attrNames cfg.certs); _24hSecs = 60 * 60 * 24; # The placerholder email address used by lego in case none gets passed placeholderEmail = "noemail@example.com"; # Used to make unique paths for each cert/account config set mkHash = with builtins; val: lib.substring 0 20 (hashString "sha256" val); mkAccountHash = acmeServer: data: mkHash "${toString acmeServer} ${data.keyType} ${data.email}"; mkAccountHash = acmeServer: data: mkHash ( lib.concatStringsSep " " [ (toString acmeServer) data.keyType (if (data.email != null) then data.email else placeholderEmail) ] ); accountDirRoot = "/var/lib/acme/.lego/accounts/"; isIP = Loading Loading @@ -273,6 +285,8 @@ let "--accept-tos" # Checking the option is covered by the assertions "--path" "." ] ++ lib.optionals (data.email != null) [ "--email" data.email ] Loading Loading @@ -580,7 +594,12 @@ let # Check if a new order is needed # We can only renew if the list of domains has not changed. # We also need an account key. Avoids #190493 if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && \ [ -e 'certificates/${keyName}.crt' ] && \ [ -n "$(find accounts -name '${ if (data.email != null) then data.email else placeholderEmail }.key')" ]; then # Even if a cert is not expired, it may be revoked by the CA. # Try to renew, and silently fail if the cert is not expired. # Avoids #85794 and resolves #129838 Loading Loading @@ -1118,14 +1137,6 @@ in certs = lib.attrValues cfg.certs; in [ { assertion = cfg.defaults.email != null || lib.all (certOpts: certOpts.email != null) certs; message = '' You must define `security.acme.certs.<name>.email` or `security.acme.defaults.email` to register with the CA. Note that using many different addresses for certs may trigger account rate limits. ''; } { assertion = cfg.acceptTerms; message = '' Loading
nixos/tests/acme/http01-builtin.nix +21 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,14 @@ in }; accountchange.configuration = { security.acme.certs."${config.networking.fqdn}".email = "admin@example.test"; # Providing an email address is optional security.acme.certs."${config.networking.fqdn}".email = null; }; emailplaceholder.configuration = { # but Lego will default to this email address, which should not # result in any change when configured security.acme.certs."${config.networking.fqdn}".email = "noemail@example.com"; }; keytype.configuration = { Loading Loading @@ -157,6 +164,7 @@ in certName = nodes.builtin.networking.fqdn; caDomain = nodes.acme.test-support.acme.caDomain; in # python '' ${(import ./utils.nix).pythonUtils} Loading Loading @@ -217,11 +225,23 @@ in hash_after = builtin.succeed(f"sha256sum /var/lib/acme/{cert}/cert.pem") # Has to do a full run to register account, which creates new certs. assert hash != hash_after, "Certificate was not renewed" hash = hash_after builtin.succeed("systemctl stop renew-triggered.target") switch_to(builtin, "emailplaceholder") builtin.wait_for_unit("renew-triggered.target") # Check that there are still two account directories builtin.succeed("test $(ls -1 /var/lib/acme/.lego/accounts | tee /dev/stderr | wc -l) -eq 2") hash_after = builtin.succeed(f"sha256sum /var/lib/acme/{cert}/cert.pem") assert hash == hash_after, "Implicit to explicit email placeholder renewed the certificate" # Remove the new account directory builtin.succeed( "cd /var/lib/acme/.lego/accounts" " && ls -1 --sort=time | tee /dev/stderr | head -1 | xargs rm -rf" ) # old_hash will be used in the preservation tests later old_hash = hash_after Loading