+2
nixos/doc/manual/release-notes/rl-2505.section.md
+2
nixos/doc/manual/release-notes/rl-2505.section.md
···
638
638
They are still expected to be working until future version 5.0.0, but will generate warnings in logs.
639
639
Read the [release notes](https://www.authelia.com/blog/4.39-release-notes/) for human readable summaries of the changes.
640
640
641
+
- `security.acme` now supports renewal using CSRs (Certificate Signing Request) through the options `security.acme.*.csr` and `security.acme.*.csrKey`.
642
+
641
643
- `programs.fzf.keybindings` now supports the fish shell.
642
644
643
645
- `gerbera` now has wavpack support.
+47
-13
nixos/modules/security/acme/default.nix
+47
-13
nixos/modules/security/acme/default.nix
···
236
236
237
237
# Create hashes for cert data directories based on configuration
238
238
# Flags are separated to avoid collisions
239
-
hashData = with builtins; ''
240
-
${lib.concatStringsSep " " data.extraLegoFlags} -
241
-
${lib.concatStringsSep " " data.extraLegoRunFlags} -
242
-
${lib.concatStringsSep " " data.extraLegoRenewFlags} -
243
-
${toString acmeServer} ${toString data.dnsProvider}
244
-
${toString data.ocspMustStaple} ${data.keyType}
245
-
'';
239
+
hashData =
240
+
with builtins;
241
+
''
242
+
${lib.concatStringsSep " " data.extraLegoFlags} -
243
+
${lib.concatStringsSep " " data.extraLegoRunFlags} -
244
+
${lib.concatStringsSep " " data.extraLegoRenewFlags} -
245
+
${toString acmeServer} ${toString data.dnsProvider}
246
+
${toString data.ocspMustStaple} ${data.keyType}
247
+
''
248
+
+ (lib.optionalString (data.csr != null) (" - " + data.csr));
246
249
certDir = mkHash hashData;
247
250
# TODO remove domainHash usage entirely. Waiting on go-acme/lego#1532
248
251
domainHash = mkHash "${lib.concatStringsSep " " extraDomains} ${data.domain}";
···
286
289
"--accept-tos" # Checking the option is covered by the assertions
287
290
"--path"
288
291
"."
289
-
"-d"
290
-
data.domain
291
292
"--email"
292
293
data.email
293
-
"--key-type"
294
-
data.keyType
295
294
]
296
295
++ protocolOpts
297
296
++ lib.optionals (acmeServer != null) [
298
297
"--server"
299
298
acmeServer
300
299
]
300
+
++ lib.optionals (data.csr != null) [
301
+
"--csr"
302
+
data.csr
303
+
]
304
+
++ lib.optionals (data.csr == null) [
305
+
"--key-type"
306
+
data.keyType
307
+
"-d"
308
+
data.domain
309
+
]
301
310
++ lib.concatMap (name: [
302
311
"-d"
303
312
name
···
327
336
webroots = lib.remove null (
328
337
lib.unique (builtins.map (certAttrs: certAttrs.webroot) (lib.attrValues config.security.acme.certs))
329
338
);
339
+
340
+
certificateKey = if data.csrKey != null then "${data.csrKey}" else "certificates/${keyName}.key";
330
341
in
331
342
{
332
343
inherit accountHash cert selfsignedDeps;
···
529
540
# Check if we can renew.
530
541
# We can only renew if the list of domains has not changed.
531
542
# We also need an account key. Avoids #190493
532
-
if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then
543
+
if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then
533
544
534
545
# Even if a cert is not expired, it may be revoked by the CA.
535
546
# Try to renew, and silently fail if the cert is not expired.
···
564
575
touch out/renewed
565
576
echo Installing new certificate
566
577
cp -vp 'certificates/${keyName}.crt' out/fullchain.pem
567
-
cp -vp 'certificates/${keyName}.key' out/key.pem
578
+
cp -vp '${certificateKey}' out/key.pem
568
579
cp -vp 'certificates/${keyName}.issuer.crt' out/chain.pem
569
580
ln -sf fullchain.pem out/cert.pem
570
581
cat out/key.pem out/fullchain.pem > out/full.pem
···
845
856
description = "Domain to fetch certificate for (defaults to the entry name).";
846
857
};
847
858
859
+
csr = lib.mkOption {
860
+
type = lib.types.nullOr lib.types.str;
861
+
default = null;
862
+
description = "Path to a certificate signing request to apply when fetching the certificate.";
863
+
};
864
+
865
+
csrKey = lib.mkOption {
866
+
type = lib.types.nullOr lib.types.str;
867
+
default = null;
868
+
description = "Path to the private key to the matching certificate signing request.";
869
+
};
870
+
848
871
extraDomainNames = lib.mkOption {
849
872
type = lib.types.listOf lib.types.str;
850
873
default = [ ];
···
1111
1134
message = ''
1112
1135
Option `security.acme.certs.${cert}.credentialFiles` can only be
1113
1136
used for variables suffixed by "_FILE".
1137
+
'';
1138
+
}
1139
+
1140
+
{
1141
+
assertion = lib.all (
1142
+
certOpts:
1143
+
(certOpts.csr == null && certOpts.csrKey == null)
1144
+
|| (certOpts.csr != null && certOpts.csrKey != null)
1145
+
) certs;
1146
+
message = ''
1147
+
When passing a certificate signing request both `security.acme.certs.${cert}.csr` and `security.acme.certs.${cert}.csrKey` need to be set.
1114
1148
'';
1115
1149
}
1116
1150
]) cfg.certs
+44
nixos/tests/acme/http01-builtin.nix
+44
nixos/tests/acme/http01-builtin.nix
···
99
99
"builtin-3.${domain}".listenHTTP = ":80";
100
100
};
101
101
};
102
+
103
+
csr.configuration =
104
+
let
105
+
conf = pkgs.writeText "openssl.csr.conf" ''
106
+
[req]
107
+
default_bits = 2048
108
+
prompt = no
109
+
default_md = sha256
110
+
req_extensions = req_ext
111
+
distinguished_name = dn
112
+
113
+
[ dn ]
114
+
CN = ${config.networking.fqdn}
115
+
116
+
[ req_ext ]
117
+
subjectAltName = @alt_names
118
+
119
+
[ alt_names ]
120
+
DNS.1 = ${config.networking.fqdn}
121
+
'';
122
+
csrData =
123
+
pkgs.runCommandNoCC "csr-and-key"
124
+
{
125
+
buildInputs = [ pkgs.openssl ];
126
+
}
127
+
''
128
+
mkdir -p $out
129
+
openssl req -new -newkey rsa:2048 -nodes \
130
+
-keyout $out/key.pem \
131
+
-out $out/request.csr \
132
+
-config ${conf}
133
+
'';
134
+
in
135
+
{
136
+
security.acme.certs."${config.networking.fqdn}" = {
137
+
csr = "${csrData}/request.csr";
138
+
csrKey = "${csrData}/key.pem";
139
+
};
140
+
};
102
141
};
103
142
};
104
143
};
···
211
250
212
251
with subtest("Validate permissions (self-signed)"):
213
252
check_permissions(builtin, cert, "acme")
253
+
254
+
with subtest("Can renew using a CSR"):
255
+
builtin.succeed(f"systemctl clean acme-{cert}.service --what=state")
256
+
switch_to(builtin, "csr")
257
+
check_issuer(builtin, cert, "pebble")
214
258
'';
215
259
}