Loading nixos/modules/security/acme/default.nix +18 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,16 @@ let mkAccountHash = acmeServer: data: mkHash "${toString acmeServer} ${data.keyType} ${data.email}"; accountDirRoot = "/var/lib/acme/.lego/accounts/"; isIP = address: let isIPv6 = lib.length (lib.splitString ":" address) > 2; isIPv4 = (lib.match "^([0-9]+\\.){3}[0-9]+$" address) != null; in isIPv6 || isIPv4; isDomainName = name: !isIP name; # Lockdir is acme-setup.service's RuntimeDirectory. # Since that service is a oneshot with RemainAfterExit, # the folder will exist during all renewal services. Loading Loading @@ -389,10 +399,14 @@ let exit 0 fi minica \ --ca-key ca/key.pem \ --ca-cert ca/cert.pem \ --domains ${lib.escapeShellArg (builtins.concatStringsSep "," ([ data.domain ] ++ extraDomains))} minica ${ lib.cli.toCommandLineShellGNU { } { ca-key = "ca/key.pem"; ca-cert = "ca/cert.pem"; domains = lib.concatStringsSep "," (lib.filter isDomainName ([ data.domain ] ++ extraDomains)); ip-addresses = lib.concatStringsSep "," (lib.filter isIP ([ data.domain ] ++ extraDomains)); } } # Create files to match directory layout for real certificates ( Loading nixos/tests/acme/http01-builtin.nix +7 −1 Original line number Diff line number Diff line { config, lib, pkgs, ... }: let domain = "example.test"; ip = "192.168.1.2"; in { name = "http01-builtin"; Loading Loading @@ -34,6 +34,7 @@ in environment.systemPackages = [ pkgs.openssl ]; security.acme.certs."${config.networking.fqdn}" = { extraDomainNames = [ ip ]; listenHTTP = ":80"; }; Loading Loading @@ -124,6 +125,7 @@ in [ alt_names ] DNS.1 = ${config.networking.fqdn} IP.1 = ${ip} ''; csrData = pkgs.runCommand "csr-and-key" Loading @@ -142,6 +144,7 @@ in security.acme.certs."${config.networking.fqdn}" = { csr = "${csrData}/request.csr"; csrKey = "${csrData}/key.pem"; extraDomainNames = lib.mkForce [ ]; }; }; }; Loading @@ -158,6 +161,7 @@ in ${(import ./utils.nix).pythonUtils} domain = "${domain}" ip = "${ip}" cert = "${certName}" cert2 = "builtin-2." + domain cert3 = "builtin-3." + domain Loading @@ -173,6 +177,7 @@ in check_issuer(builtin, cert, "pebble") check_domain(builtin, cert, cert) check_ip(builtin, cert, ip) with subtest("Validate permissions"): check_permissions(builtin, cert, "acme") Loading Loading @@ -300,6 +305,7 @@ in builtin.wait_for_unit("renew-triggered.target") check_issuer(builtin, cert, "pebble") check_ip(builtin, cert, ip) with subtest("Generate self-signed certs"): acme.shutdown() Loading nixos/tests/acme/python-utils.py +5 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,11 @@ def check_domain(node, cert_name, domain, fail=False) -> None: cmd = f"openssl x509 -noout -checkhost '{domain}' -in /var/lib/acme/{cert_name}/cert.pem" run(node, cmd, fail=fail) # Ensures the provided ip address matches with the given cert def check_ip(node, cert_name, ip_address, fail=False) -> None: cmd = f"openssl x509 -noout -checkip '{ip_address}' -in /var/lib/acme/{cert_name}/cert.pem" run(node, cmd, fail=fail) # Ensures the required values for OCSP stapling are present # Pebble doesn't provide a full OCSP responder, so just checks the URL def check_stapling(node, cert_name, ca_domain, fail=False): Loading Loading
nixos/modules/security/acme/default.nix +18 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,16 @@ let mkAccountHash = acmeServer: data: mkHash "${toString acmeServer} ${data.keyType} ${data.email}"; accountDirRoot = "/var/lib/acme/.lego/accounts/"; isIP = address: let isIPv6 = lib.length (lib.splitString ":" address) > 2; isIPv4 = (lib.match "^([0-9]+\\.){3}[0-9]+$" address) != null; in isIPv6 || isIPv4; isDomainName = name: !isIP name; # Lockdir is acme-setup.service's RuntimeDirectory. # Since that service is a oneshot with RemainAfterExit, # the folder will exist during all renewal services. Loading Loading @@ -389,10 +399,14 @@ let exit 0 fi minica \ --ca-key ca/key.pem \ --ca-cert ca/cert.pem \ --domains ${lib.escapeShellArg (builtins.concatStringsSep "," ([ data.domain ] ++ extraDomains))} minica ${ lib.cli.toCommandLineShellGNU { } { ca-key = "ca/key.pem"; ca-cert = "ca/cert.pem"; domains = lib.concatStringsSep "," (lib.filter isDomainName ([ data.domain ] ++ extraDomains)); ip-addresses = lib.concatStringsSep "," (lib.filter isIP ([ data.domain ] ++ extraDomains)); } } # Create files to match directory layout for real certificates ( Loading
nixos/tests/acme/http01-builtin.nix +7 −1 Original line number Diff line number Diff line { config, lib, pkgs, ... }: let domain = "example.test"; ip = "192.168.1.2"; in { name = "http01-builtin"; Loading Loading @@ -34,6 +34,7 @@ in environment.systemPackages = [ pkgs.openssl ]; security.acme.certs."${config.networking.fqdn}" = { extraDomainNames = [ ip ]; listenHTTP = ":80"; }; Loading Loading @@ -124,6 +125,7 @@ in [ alt_names ] DNS.1 = ${config.networking.fqdn} IP.1 = ${ip} ''; csrData = pkgs.runCommand "csr-and-key" Loading @@ -142,6 +144,7 @@ in security.acme.certs."${config.networking.fqdn}" = { csr = "${csrData}/request.csr"; csrKey = "${csrData}/key.pem"; extraDomainNames = lib.mkForce [ ]; }; }; }; Loading @@ -158,6 +161,7 @@ in ${(import ./utils.nix).pythonUtils} domain = "${domain}" ip = "${ip}" cert = "${certName}" cert2 = "builtin-2." + domain cert3 = "builtin-3." + domain Loading @@ -173,6 +177,7 @@ in check_issuer(builtin, cert, "pebble") check_domain(builtin, cert, cert) check_ip(builtin, cert, ip) with subtest("Validate permissions"): check_permissions(builtin, cert, "acme") Loading Loading @@ -300,6 +305,7 @@ in builtin.wait_for_unit("renew-triggered.target") check_issuer(builtin, cert, "pebble") check_ip(builtin, cert, ip) with subtest("Generate self-signed certs"): acme.shutdown() Loading
nixos/tests/acme/python-utils.py +5 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,11 @@ def check_domain(node, cert_name, domain, fail=False) -> None: cmd = f"openssl x509 -noout -checkhost '{domain}' -in /var/lib/acme/{cert_name}/cert.pem" run(node, cmd, fail=fail) # Ensures the provided ip address matches with the given cert def check_ip(node, cert_name, ip_address, fail=False) -> None: cmd = f"openssl x509 -noout -checkip '{ip_address}' -in /var/lib/acme/{cert_name}/cert.pem" run(node, cmd, fail=fail) # Ensures the required values for OCSP stapling are present # Pebble doesn't provide a full OCSP responder, so just checks the URL def check_stapling(node, cert_name, ca_domain, fail=False): Loading