Unverified Commit 941dfcd1 authored by Franz Pletz's avatar Franz Pletz Committed by GitHub
Browse files

nixos/acme: add compat for IP SANs to minica fallback (#479212)

parents fa020b79 51d1c22f
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -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.
@@ -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
          (
+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";
@@ -34,6 +34,7 @@ in
        environment.systemPackages = [ pkgs.openssl ];

        security.acme.certs."${config.networking.fqdn}" = {
          extraDomainNames = [ ip ];
          listenHTTP = ":80";
        };

@@ -124,6 +125,7 @@ in

                [ alt_names ]
                DNS.1 = ${config.networking.fqdn}
                IP.1 = ${ip}
              '';
              csrData =
                pkgs.runCommand "csr-and-key"
@@ -142,6 +144,7 @@ in
              security.acme.certs."${config.networking.fqdn}" = {
                csr = "${csrData}/request.csr";
                csrKey = "${csrData}/key.pem";
                extraDomainNames = lib.mkForce [ ];
              };
            };
        };
@@ -158,6 +161,7 @@ in
      ${(import ./utils.nix).pythonUtils}

      domain = "${domain}"
      ip = "${ip}"
      cert = "${certName}"
      cert2 = "builtin-2." + domain
      cert3 = "builtin-3." + domain
@@ -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")
@@ -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()
+5 −0
Original line number Diff line number Diff line
@@ -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):