···638638 They are still expected to be working until future version 5.0.0, but will generate warnings in logs.
639639 Read the [release notes](https://www.authelia.com/blog/4.39-release-notes/) for human readable summaries of the changes.
640640641641+- `security.acme` now supports renewal using CSRs (Certificate Signing Request) through the options `security.acme.*.csr` and `security.acme.*.csrKey`.
642642+641643- `programs.fzf.keybindings` now supports the fish shell.
642644643645- `gerbera` now has wavpack support.
+47-13
nixos/modules/security/acme/default.nix
···236236237237 # Create hashes for cert data directories based on configuration
238238 # Flags are separated to avoid collisions
239239- hashData = with builtins; ''
240240- ${lib.concatStringsSep " " data.extraLegoFlags} -
241241- ${lib.concatStringsSep " " data.extraLegoRunFlags} -
242242- ${lib.concatStringsSep " " data.extraLegoRenewFlags} -
243243- ${toString acmeServer} ${toString data.dnsProvider}
244244- ${toString data.ocspMustStaple} ${data.keyType}
245245- '';
239239+ hashData =
240240+ with builtins;
241241+ ''
242242+ ${lib.concatStringsSep " " data.extraLegoFlags} -
243243+ ${lib.concatStringsSep " " data.extraLegoRunFlags} -
244244+ ${lib.concatStringsSep " " data.extraLegoRenewFlags} -
245245+ ${toString acmeServer} ${toString data.dnsProvider}
246246+ ${toString data.ocspMustStaple} ${data.keyType}
247247+ ''
248248+ + (lib.optionalString (data.csr != null) (" - " + data.csr));
246249 certDir = mkHash hashData;
247250 # TODO remove domainHash usage entirely. Waiting on go-acme/lego#1532
248251 domainHash = mkHash "${lib.concatStringsSep " " extraDomains} ${data.domain}";
···286289 "--accept-tos" # Checking the option is covered by the assertions
287290 "--path"
288291 "."
289289- "-d"
290290- data.domain
291292 "--email"
292293 data.email
293293- "--key-type"
294294- data.keyType
295294 ]
296295 ++ protocolOpts
297296 ++ lib.optionals (acmeServer != null) [
298297 "--server"
299298 acmeServer
300299 ]
300300+ ++ lib.optionals (data.csr != null) [
301301+ "--csr"
302302+ data.csr
303303+ ]
304304+ ++ lib.optionals (data.csr == null) [
305305+ "--key-type"
306306+ data.keyType
307307+ "-d"
308308+ data.domain
309309+ ]
301310 ++ lib.concatMap (name: [
302311 "-d"
303312 name
···327336 webroots = lib.remove null (
328337 lib.unique (builtins.map (certAttrs: certAttrs.webroot) (lib.attrValues config.security.acme.certs))
329338 );
339339+340340+ certificateKey = if data.csrKey != null then "${data.csrKey}" else "certificates/${keyName}.key";
330341 in
331342 {
332343 inherit accountHash cert selfsignedDeps;
···529540 # Check if we can renew.
530541 # We can only renew if the list of domains has not changed.
531542 # We also need an account key. Avoids #190493
532532- if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then
543543+ if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then
533544534545 # Even if a cert is not expired, it may be revoked by the CA.
535546 # Try to renew, and silently fail if the cert is not expired.
···564575 touch out/renewed
565576 echo Installing new certificate
566577 cp -vp 'certificates/${keyName}.crt' out/fullchain.pem
567567- cp -vp 'certificates/${keyName}.key' out/key.pem
578578+ cp -vp '${certificateKey}' out/key.pem
568579 cp -vp 'certificates/${keyName}.issuer.crt' out/chain.pem
569580 ln -sf fullchain.pem out/cert.pem
570581 cat out/key.pem out/fullchain.pem > out/full.pem
···845856 description = "Domain to fetch certificate for (defaults to the entry name).";
846857 };
847858859859+ csr = lib.mkOption {
860860+ type = lib.types.nullOr lib.types.str;
861861+ default = null;
862862+ description = "Path to a certificate signing request to apply when fetching the certificate.";
863863+ };
864864+865865+ csrKey = lib.mkOption {
866866+ type = lib.types.nullOr lib.types.str;
867867+ default = null;
868868+ description = "Path to the private key to the matching certificate signing request.";
869869+ };
870870+848871 extraDomainNames = lib.mkOption {
849872 type = lib.types.listOf lib.types.str;
850873 default = [ ];
···11111134 message = ''
11121135 Option `security.acme.certs.${cert}.credentialFiles` can only be
11131136 used for variables suffixed by "_FILE".
11371137+ '';
11381138+ }
11391139+11401140+ {
11411141+ assertion = lib.all (
11421142+ certOpts:
11431143+ (certOpts.csr == null && certOpts.csrKey == null)
11441144+ || (certOpts.csr != null && certOpts.csrKey != null)
11451145+ ) certs;
11461146+ message = ''
11471147+ When passing a certificate signing request both `security.acme.certs.${cert}.csr` and `security.acme.certs.${cert}.csrKey` need to be set.
11141148 '';
11151149 }
11161150 ]) cfg.certs