nixos: Working ACME certs

This commit is contained in:
Jack O'Sullivan 2022-06-06 00:18:24 +01:00
parent b472f4fe2e
commit 7da7458a34
10 changed files with 126 additions and 18 deletions

View File

@ -176,7 +176,7 @@
} }
table inet nat { table inet nat {
chain prerouting { 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 { chain postrouting {
ip saddr ${lib.my.colony.prefixes.all.v4} masquerade ip saddr ${lib.my.colony.prefixes.all.v4} masquerade

View File

@ -13,14 +13,14 @@ let
pdns-file-record = pkgs.writeShellApplication { pdns-file-record = pkgs.writeShellApplication {
name = "pdns-file-record"; name = "pdns-file-record";
runtimeInputs = [ pkgs.gnused ]; runtimeInputs = with pkgs; [ gnused pdns ];
text = '' text = ''
die() { die() {
echo "$@" >&2 echo "$@" >&2
exit 1 exit 1
} }
usage() { usage() {
die "usage: $0 <add|del> <fqdn> [content]" die "usage: $0 <zone> <add|del> <fqdn> [content]"
} }
add() { add() {
@ -47,11 +47,14 @@ let
dir=/run/pdns/file-records dir=/run/pdns/file-records
mkdir -p "$dir" mkdir -p "$dir"
if [ $# -lt 1 ]; then if [ $# -lt 2 ]; then
usage usage
fi fi
zone="$1"
shift
cmd="$1" cmd="$1"
shift shift
case "$cmd" in case "$cmd" in
add) add)
add "$@";; add "$@";;
@ -60,11 +63,48 @@ let
*) *)
usage;; usage;;
esac 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 in
{ {
config = { 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 = { services.pdns-recursor = {
enable = true; enable = true;
dns = { dns = {
@ -164,7 +204,7 @@ in
wildcardPtr6Z = wildcardPtr6 ptrDots6; wildcardPtr6Z = wildcardPtr6 ptrDots6;
fileRecScript = pkgs.writeText "file-record.lua" '' 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 if not os.execute("test -e " .. path) then
return {} return {}
end end
@ -195,8 +235,10 @@ in
@ IN ALIAS ${config.networking.fqdn}. @ IN ALIAS ${config.networking.fqdn}.
$TTL 3
_acme-challenge IN LUA TXT ${fileRecVal} _acme-challenge IN LUA TXT ${fileRecVal}
$TTL 60
${intRecords} ${intRecords}
''; '';
}; };

View File

@ -16,7 +16,7 @@
}; };
}; };
configuration = { lib, config, assignments, allAssignments, ... }: configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
let let
inherit (lib) mkMerge mkIf; inherit (lib) mkMerge mkIf;
inherit (lib.my) networkdAssignment; inherit (lib.my) networkdAssignment;
@ -29,7 +29,13 @@
secrets = { secrets = {
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAuvP9DEsffop53Fsh7xIdeVyQSF6tSKrOUs2faq6rip"; key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAuvP9DEsffop53Fsh7xIdeVyQSF6tSKrOUs2faq6rip";
files."dhparams.pem" = {}; files = {
"dhparams.pem" = {};
"pdns-file-records.key" = {
owner = "acme";
group = "acme";
};
};
}; };
firewall = { firewall = {
@ -44,6 +50,51 @@
network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal; 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 = { services = {
nginx = { nginx = {
enable = true; enable = true;

View File

@ -128,11 +128,10 @@ in
table inet nat { table inet nat {
chain prerouting { chain prerouting {
type nat hook prerouting priority 0; type nat hook prerouting priority dstnat;
} }
chain postrouting { chain postrouting {
type nat hook postrouting priority 100; type nat hook postrouting priority srcnat;
} }
} }

View File

@ -156,6 +156,9 @@ in
mkdir -p /var/lib/pdns/bind-zones mkdir -p /var/lib/pdns/bind-zones
loadZones start 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 # 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 # are added or removed, named.conf will change, in turn changing the overall pdns settings and causing pdns to

View File

@ -225,6 +225,16 @@ in
my.tmproot.persistence.config.files = my.tmproot.persistence.config.files =
concatMap (k: [ k.path "${k.path}.pub" ]) config.services.openssh.hostKeys; 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 { (mkIf config.my.build.isDevVM {
fileSystems = mkVMOverride { fileSystems = mkVMOverride {
# Hijack the "root" device for persistence in the VM # Hijack the "root" device for persistence in the VM

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,12 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Lqn0Yw 8O/4DNOBVj9N2QBh4iAcpQPFYKK884dVYBGii6QvMFs -> ssh-ed25519 Lqn0Yw ybVbnUjgm3QGOZPv9A/q6zPXjZbuYe4krqe+qjrkziw
enBLaFlBILu61uFQwV6v8PyWG0M0JkmSfpk/tztrLls SIEEGlziouUT3pzxw+C7p2IO2sDJ3xmaTrHaDGFgLOs
-> X25519 6X2M/VOMrMTIdgg9dRlVQmF2LWq5W53rNLzZ8UAJWVM -> X25519 bq/2lRh9a3BwhwR6o9TXeuXA5AGdtlrQm8/JOyAzUEU
xFEKeZD+w68RyK+jlyFB82oQ6a6+FCBmYcjvc/8Wg9M I5xRPDb6rUcNBXqOXefFkO2HvlYIJAG+OFkZygywkqg
-> uVBC-grease -> 0g#WDK-grease .DWBEk*
70cjnfhD0khuuiGtBG7MwE2CSEgmClW9/wQeZhAdOQ4 Vf8DHmVCY3bfTT+CPPm5dELSid+aZJquOxjEccmkZXVKtefHlwLRx6Dh3HT5IZqR
--- hykfNiGB0dkhlbOabguSHtVFYtAtlFK6ld7GU8E3+WI Pl2j/4SQvVf1MrPjtbkMwBhxh9zPZa7WQIBGeF6oB2kl9vyc65lXpaxRSMs2eVsv
Låú;sâ‹É5MÄ%²u «Ó††3#%5«#‰1gõuû¡Újt¦ËïÜc“7<E2809C><37>™žì9¬r^­ìªOȸߥ´É—·bcobvÊNæ¼éƒ©`½Rù»÷ŠÌ ;èƒØ6æ?ʱ!'â<>ªØ
--- /eCT0Rqu+we6CXUSP3dpd+blpQxwOG0t5rDiGfffXPs
FÕ
ðf<EFBFBD>§¯<19>~"[®ù%?—}Âí1ÿP~½äÒ‹$ÑNrnh*y¢ _É…÷ùï!ë¨*™©h\Ž‡è…ÀMÖú¶ õß…x•sÞ”ëFdÀ3¯u/$9ô½ þ¢ÜâŠºÖ Р§è&ði¥v