nixos: Working ACME certs
This commit is contained in:
		@@ -176,7 +176,7 @@
 | 
			
		||||
                  }
 | 
			
		||||
                  table inet nat {
 | 
			
		||||
                    chain prerouting {
 | 
			
		||||
                      iifname wan meta l4proto { udp, tcp } th dport domain redirect to :5353
 | 
			
		||||
                      ${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" "estuary"}
 | 
			
		||||
                    }
 | 
			
		||||
                    chain postrouting {
 | 
			
		||||
                      ip saddr ${lib.my.colony.prefixes.all.v4} masquerade
 | 
			
		||||
 
 | 
			
		||||
@@ -13,14 +13,14 @@ let
 | 
			
		||||
 | 
			
		||||
  pdns-file-record = pkgs.writeShellApplication {
 | 
			
		||||
    name = "pdns-file-record";
 | 
			
		||||
    runtimeInputs = [ pkgs.gnused ];
 | 
			
		||||
    runtimeInputs = with pkgs; [ gnused pdns ];
 | 
			
		||||
    text = ''
 | 
			
		||||
      die() {
 | 
			
		||||
        echo "$@" >&2
 | 
			
		||||
        exit 1
 | 
			
		||||
      }
 | 
			
		||||
      usage() {
 | 
			
		||||
        die "usage: $0 <add|del> <fqdn> [content]"
 | 
			
		||||
        die "usage: $0 <zone> <add|del> <fqdn> [content]"
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      add() {
 | 
			
		||||
@@ -47,11 +47,14 @@ let
 | 
			
		||||
      dir=/run/pdns/file-records
 | 
			
		||||
      mkdir -p "$dir"
 | 
			
		||||
 | 
			
		||||
      if [ $# -lt 1 ]; then
 | 
			
		||||
      if [ $# -lt 2 ]; then
 | 
			
		||||
        usage
 | 
			
		||||
      fi
 | 
			
		||||
      zone="$1"
 | 
			
		||||
      shift
 | 
			
		||||
      cmd="$1"
 | 
			
		||||
      shift
 | 
			
		||||
 | 
			
		||||
      case "$cmd" in
 | 
			
		||||
      add)
 | 
			
		||||
        add "$@";;
 | 
			
		||||
@@ -60,11 +63,48 @@ let
 | 
			
		||||
      *)
 | 
			
		||||
        usage;;
 | 
			
		||||
      esac
 | 
			
		||||
 | 
			
		||||
      # TODO: This feels pretty hacky?
 | 
			
		||||
      zDat=/var/lib/pdns/bind-zones/"$zone".dat
 | 
			
		||||
      # shellcheck disable=SC1090
 | 
			
		||||
      source "$zDat"
 | 
			
		||||
      ((serial++))
 | 
			
		||||
      sed -i "s/^serial=.*$/serial=$serial/g" "$zDat"
 | 
			
		||||
      sed "s/@@SERIAL@@/$serial/g" < /etc/pdns/bind-zones/"$zone".zone > /run/pdns/bind-zones/"$zone".zone
 | 
			
		||||
      pdns_control bind-reload-now "$zone"
 | 
			
		||||
    '';
 | 
			
		||||
  };
 | 
			
		||||
in
 | 
			
		||||
{
 | 
			
		||||
  config = {
 | 
			
		||||
    users = {
 | 
			
		||||
      users = {
 | 
			
		||||
        "pdns-file-records" =
 | 
			
		||||
        let
 | 
			
		||||
          script = pkgs.writeShellScript "pdns-file-records-ssh.sh" ''
 | 
			
		||||
            read -r -a args <<< "$SSH_ORIGINAL_COMMAND"
 | 
			
		||||
            exec ${pdns-file-record}/bin/pdns-file-record "''${args[@]}"
 | 
			
		||||
          '';
 | 
			
		||||
        in
 | 
			
		||||
        {
 | 
			
		||||
          group = "pdns";
 | 
			
		||||
          isSystemUser = true;
 | 
			
		||||
          shell = pkgs.bashInteractive;
 | 
			
		||||
          openssh.authorizedKeys.keys = [
 | 
			
		||||
            ''command="${script}" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBSvcgbEesOgvKJLt3FLXPaLOcCIuOUYtZXXtEv6k4Yd''
 | 
			
		||||
          ];
 | 
			
		||||
        };
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    systemd = {
 | 
			
		||||
      services = {
 | 
			
		||||
        pdns.preStart = ''
 | 
			
		||||
          install -d -m 775 /run/pdns/file-records
 | 
			
		||||
        '';
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    services.pdns-recursor = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      dns = {
 | 
			
		||||
@@ -164,7 +204,7 @@ in
 | 
			
		||||
        wildcardPtr6Z = wildcardPtr6 ptrDots6;
 | 
			
		||||
 | 
			
		||||
        fileRecScript = pkgs.writeText "file-record.lua" ''
 | 
			
		||||
          local path = "/run/pdns/file-records/" .. qname:toStringNoDot() .. ".txt"
 | 
			
		||||
          local path = "/run/pdns/file-records/" .. string.lower(qname:toStringNoDot()) .. ".txt"
 | 
			
		||||
          if not os.execute("test -e " .. path) then
 | 
			
		||||
            return {}
 | 
			
		||||
          end
 | 
			
		||||
@@ -195,8 +235,10 @@ in
 | 
			
		||||
 | 
			
		||||
            @ IN ALIAS ${config.networking.fqdn}.
 | 
			
		||||
 | 
			
		||||
            $TTL 3
 | 
			
		||||
            _acme-challenge IN LUA TXT ${fileRecVal}
 | 
			
		||||
 | 
			
		||||
            $TTL 60
 | 
			
		||||
            ${intRecords}
 | 
			
		||||
          '';
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    configuration = { lib, config, assignments, allAssignments, ... }:
 | 
			
		||||
    configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
 | 
			
		||||
    let
 | 
			
		||||
      inherit (lib) mkMerge mkIf;
 | 
			
		||||
      inherit (lib.my) networkdAssignment;
 | 
			
		||||
@@ -29,7 +29,13 @@
 | 
			
		||||
 | 
			
		||||
            secrets = {
 | 
			
		||||
              key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAuvP9DEsffop53Fsh7xIdeVyQSF6tSKrOUs2faq6rip";
 | 
			
		||||
              files."dhparams.pem" = {};
 | 
			
		||||
              files = {
 | 
			
		||||
                "dhparams.pem" = {};
 | 
			
		||||
                "pdns-file-records.key" = {
 | 
			
		||||
                  owner = "acme";
 | 
			
		||||
                  group = "acme";
 | 
			
		||||
                };
 | 
			
		||||
              };
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            firewall = {
 | 
			
		||||
@@ -44,6 +50,51 @@
 | 
			
		||||
            network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          security = {
 | 
			
		||||
            acme = {
 | 
			
		||||
              acceptTerms = true;
 | 
			
		||||
              defaults = {
 | 
			
		||||
                email = "dev@nul.ie";
 | 
			
		||||
                server = "https://acme-staging-v02.api.letsencrypt.org/directory";
 | 
			
		||||
                reloadServices = [ "nginx" ];
 | 
			
		||||
                dnsResolver = "8.8.8.8";
 | 
			
		||||
              };
 | 
			
		||||
 | 
			
		||||
              certs = {
 | 
			
		||||
                "${config.networking.domain}" = {
 | 
			
		||||
                  extraDomainNames = [
 | 
			
		||||
                    "*.${config.networking.domain}"
 | 
			
		||||
                  ];
 | 
			
		||||
                  dnsProvider = "exec";
 | 
			
		||||
                  credentialsFile =
 | 
			
		||||
                  let
 | 
			
		||||
                    script = pkgs.writeShellScript "lego-update-int.sh" ''
 | 
			
		||||
                      case "$1" in
 | 
			
		||||
                      present)
 | 
			
		||||
                        cmd=add;;
 | 
			
		||||
                      cleanup)
 | 
			
		||||
                        cmd=del;;
 | 
			
		||||
                      *)
 | 
			
		||||
                        exit 1;;
 | 
			
		||||
                      esac
 | 
			
		||||
 | 
			
		||||
                      echo "$@"
 | 
			
		||||
                      exec ${pkgs.openssh}/bin/ssh \
 | 
			
		||||
                        -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
 | 
			
		||||
                        -i ${config.age.secrets."pdns-file-records.key".path} \
 | 
			
		||||
                        pdns-file-records@estuary-vm "${config.networking.domain}" "$cmd" "$2" "$3"
 | 
			
		||||
                    '';
 | 
			
		||||
                  in
 | 
			
		||||
                  pkgs.writeText "lego-exec-vars.conf" ''
 | 
			
		||||
                    EXEC_PROPAGATION_TIMEOUT=60
 | 
			
		||||
                    EXEC_POLLING_INTERVAL=2
 | 
			
		||||
                    EXEC_PATH=${script}
 | 
			
		||||
                  '';
 | 
			
		||||
                };
 | 
			
		||||
              };
 | 
			
		||||
            };
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          services = {
 | 
			
		||||
            nginx = {
 | 
			
		||||
              enable = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -128,11 +128,10 @@ in
 | 
			
		||||
 | 
			
		||||
              table inet nat {
 | 
			
		||||
                chain prerouting {
 | 
			
		||||
                  type nat hook prerouting priority 0;
 | 
			
		||||
                  type nat hook prerouting priority dstnat;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                chain postrouting {
 | 
			
		||||
                  type nat hook postrouting priority 100;
 | 
			
		||||
                  type nat hook postrouting priority srcnat;
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -156,6 +156,9 @@ in
 | 
			
		||||
          mkdir -p /var/lib/pdns/bind-zones
 | 
			
		||||
          loadZones start
 | 
			
		||||
        '';
 | 
			
		||||
        postStart = ''
 | 
			
		||||
          chmod -R g+w /run/pdns /var/lib/pdns
 | 
			
		||||
        '';
 | 
			
		||||
 | 
			
		||||
        # pdns reloads existing zones, so the only trigger will be if the zone files themselves change. If any new zones
 | 
			
		||||
        # are added or removed, named.conf will change, in turn changing the overall pdns settings and causing pdns to
 | 
			
		||||
 
 | 
			
		||||
@@ -225,6 +225,16 @@ in
 | 
			
		||||
        my.tmproot.persistence.config.files =
 | 
			
		||||
          concatMap (k: [ k.path "${k.path}.pub" ]) config.services.openssh.hostKeys;
 | 
			
		||||
      })
 | 
			
		||||
      (mkIf (config.security.acme.certs != { }) {
 | 
			
		||||
        my.tmproot.persistence.config.directories = [
 | 
			
		||||
          {
 | 
			
		||||
            directory = "/var/lib/acme";
 | 
			
		||||
            mode = "0750";
 | 
			
		||||
            user = "acme";
 | 
			
		||||
            group = "acme";
 | 
			
		||||
          }
 | 
			
		||||
        ];
 | 
			
		||||
      })
 | 
			
		||||
      (mkIf config.my.build.isDevVM {
 | 
			
		||||
        fileSystems = mkVMOverride {
 | 
			
		||||
          # Hijack the "root" device for persistence in the VM
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user