From d9317cd69a189da7d184eadee1afef27a9f921c0 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 10 Aug 2024 13:06:59 +0200 Subject: [PATCH 1/4] cluster/services/dns: use patroni incandescence --- cluster/services/dns/acme-dns-db-credentials.age | 16 ---------------- cluster/services/dns/authoritative.nix | 9 +++++---- cluster/services/dns/default.nix | 10 ++++++++++ 3 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 cluster/services/dns/acme-dns-db-credentials.age diff --git a/cluster/services/dns/acme-dns-db-credentials.age b/cluster/services/dns/acme-dns-db-credentials.age deleted file mode 100644 index f0b6cb7..0000000 --- a/cluster/services/dns/acme-dns-db-credentials.age +++ /dev/null @@ -1,16 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 NO562A YndVtONpmfFXYB1ASnPHsfczl1UbgZ2vccIrX2pEgx0 -VzH2UD583L6wBLMCo6faIGyHR4+zXXOUTgQduEiFOxI --> ssh-ed25519 5/zT0w +67r5S6PSFEgnrTu3eZpOd3eemZUdDOE+kjUw6GDgUM -jPzlW7hePFgsABUjryePu5yergQ2Qjczmmoxuo6CK+U --> ssh-ed25519 TCgorQ DGJPjJYpeibxM+8OwofUCdttIT2OdNbvQ66wpWQM8XU -JCNQ3bT21j2ZsxbzA6FieKIui6lsvk1p0nvNOT7YtFo --> ssh-ed25519 d3WGuA hIl5yluwf1f0DP5ZW1MalGPCj4XFYOu2sofwJSQZ6RE -BSHoe4cdRJlPrkc+taUIaIIUknexlGttzz2d9I3jtmk --> ssh-ed25519 YIaSKQ EbqXS/XFQHSXCbzDJmg4gGUxP9TX3+vOxWtNQDJ8ih4 -hNaWzoFG2iVef4Gm30LilGXYNsVkhmVt9dOvBo02mbM --> V]i@xRtJ-grease -NEPxMUZa76GclWOasWptt6QS7frMclp9o+kD4KCLJB7ucFOYK7xxWfAEMkjtadfP -m0bbgbw7Jcs9/lA8VNAG2D5jTBayGgpkBQZ4 ---- ViqZD8mJEKIMCZ5Q+wRQWR2FX/LMEfUwoumUtHlYabQ -KAÉû¹ÝgZü<šë*DfV6·=äG»+eœ`ºpª±ï÷­6°º[Û‘Û û¸¢ºÐý-H1»Ã›Íí[fV.¾¢HÁ"OhÐñŒ½j•ùö8ïßß$‰;Û‘&5äxw§/mŒëÖ‘ß^7î‘f5ÔµyÏŽÓûC‚´6”¹U•æýi-R=/_R„·==æà½1˜'Ò qÞ·ŒvÜcwø \ No newline at end of file diff --git a/cluster/services/dns/authoritative.nix b/cluster/services/dns/authoritative.nix index 5082224..27606df 100644 --- a/cluster/services/dns/authoritative.nix +++ b/cluster/services/dns/authoritative.nix @@ -43,9 +43,6 @@ in { links.localAuthoritativeDNS = {}; age.secrets = { - acmeDnsDbCredentials = { - file = ./acme-dns-db-credentials.age; - }; acmeDnsDirectKey = { file = ./acme-dns-direct-key.age; }; @@ -78,8 +75,12 @@ in { }; }; + services.locksmith.waitForSecrets.acme-dns = [ + "patroni-acmedns" + ]; + systemd.services.acme-dns.serviceConfig.EnvironmentFile = with config.age.secrets; [ - acmeDnsDbCredentials.path + "/run/locksmith/patroni-acmedns" acmeDnsDirectKey.path ]; diff --git a/cluster/services/dns/default.nix b/cluster/services/dns/default.nix index 6c2ed43..fa75ceb 100644 --- a/cluster/services/dns/default.nix +++ b/cluster/services/dns/default.nix @@ -58,6 +58,16 @@ in }; }; + patroni = { + databases.acmedns = {}; + users.acmedns = { + locksmith = { + nodes = config.services.dns.nodes.authoritative; + format = "envFile"; + }; + }; + }; + dns.records = { securedns.consulService = "securedns"; "acme-dns-challenge.internal".consulService = "acme-dns"; From 79478c44ed402b56920ba681930d0b7cadeaf31d Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 10 Aug 2024 13:37:36 +0200 Subject: [PATCH 2/4] cluster/services/acme-client: implement augment for external ACME services --- cluster/services/acme-client/augment.nix | 60 ++++++++++++++++++++++++ cluster/services/acme-client/default.nix | 1 + 2 files changed, 61 insertions(+) create mode 100644 cluster/services/acme-client/augment.nix diff --git a/cluster/services/acme-client/augment.nix b/cluster/services/acme-client/augment.nix new file mode 100644 index 0000000..a16a559 --- /dev/null +++ b/cluster/services/acme-client/augment.nix @@ -0,0 +1,60 @@ +{ config, pkgs, ... }: + +let + lift = config; +in + +{ + nowhere.names = { + "acme-v02.api.letsencrypt.org" = "stepCa"; + "api.buypass.com" = "stepCa"; + }; + + nodes.nowhere = { config, ... }: { + links.stepCa.protocol = "https"; + + environment.etc.step-ca-password.text = ""; + + services = { + step-ca = { + enable = true; + address = config.links.stepCa.ipv4; + inherit (config.links.stepCa) port; + intermediatePasswordFile = "/etc/step-ca-password"; + settings = { + root = "${lift.nowhere.certs.ca}/ca.pem"; + crt = "${lift.nowhere.certs.intermediate}/cert.pem"; + key = "${lift.nowhere.certs.intermediate}/cert-key.pem"; + address = config.links.stepCa.tuple; + db = { + type = "badgerv2"; + dataSource = "/var/lib/step-ca/db"; + }; + authority.provisioners = [ + { + type = "ACME"; + name = "snakeoil"; + challenges = [ + "dns-01" + "http-01" + ]; + } + ]; + }; + }; + + nginx.virtualHosts = { + "acme-v02.api.letsencrypt.org".locations."/".extraConfig = '' + rewrite /directory /acme/snakeoil/directory break; + ''; + "api.buypass.com".locations."/".extraConfig = '' + rewrite /acme/directory /acme/snakeoil/directory break; + ''; + }; + }; + }; + + defaults.environment.etc."dummy-secrets/acmeDnsApiKey".text = "ACME_DNS_DIRECT_STATIC_KEY=simulacrum"; + defaults.environment.etc."dummy-secrets/acmeDnsDirectKey".text = "ACME_DNS_DIRECT_STATIC_KEY=simulacrum"; + defaults.environment.etc."dummy-secrets/acmeDnsDbCredentials".text = "PGPASSWORD=simulacrum"; +} diff --git a/cluster/services/acme-client/default.nix b/cluster/services/acme-client/default.nix index 07346c2..ed2c82d 100644 --- a/cluster/services/acme-client/default.nix +++ b/cluster/services/acme-client/default.nix @@ -2,5 +2,6 @@ services.acme-client = { nodes.client = [ "checkmate" "grail" "thunderskin" "VEGAS" "prophet" ]; nixos.client = ./client.nix; + simulacrum.augments = ./augment.nix; }; } From e0d513be3014cc4c94b3c10a730f5cc58b076dc4 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 16 Aug 2024 02:16:11 +0200 Subject: [PATCH 3/4] cluster/services/dns: never reload coredns --- cluster/services/dns/coredns.nix | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cluster/services/dns/coredns.nix b/cluster/services/dns/coredns.nix index 1b3e439..23448f1 100644 --- a/cluster/services/dns/coredns.nix +++ b/cluster/services/dns/coredns.nix @@ -35,10 +35,13 @@ in ]; before = [ "acme-securedns.${domain}.service" ]; wants = [ "acme-finished-securedns.${domain}.target" ]; - serviceConfig.LoadCredential = [ - "dot-cert.pem:${dot.directory}/fullchain.pem" - "dot-key.pem:${dot.directory}/key.pem" - ]; + serviceConfig = { + LoadCredential = [ + "dot-cert.pem:${dot.directory}/fullchain.pem" + "dot-key.pem:${dot.directory}/key.pem" + ]; + ExecReload = lib.mkForce []; + }; }; security.acme.certs."securedns.${domain}" = { From f5b085a074b2e3973ac644b182fe3ad31d142702 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 16 Aug 2024 02:16:28 +0200 Subject: [PATCH 4/4] cluster/services/dns: test in simulacrum --- cluster/services/dns/default.nix | 5 +++++ cluster/services/dns/test.nix | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 cluster/services/dns/test.nix diff --git a/cluster/services/dns/default.nix b/cluster/services/dns/default.nix index fa75ceb..50be452 100644 --- a/cluster/services/dns/default.nix +++ b/cluster/services/dns/default.nix @@ -56,6 +56,11 @@ in coredns = ./coredns.nix; client = ./client.nix; }; + simulacrum = { + enable = true; + deps = [ "consul" "acme-client" "patroni" ]; + settings = ./test.nix; + }; }; patroni = { diff --git a/cluster/services/dns/test.nix b/cluster/services/dns/test.nix new file mode 100644 index 0000000..33dab32 --- /dev/null +++ b/cluster/services/dns/test.nix @@ -0,0 +1,35 @@ +{ cluster, ... }: + +let + inherit (cluster._module.specialArgs.depot.lib.meta) domain; +in +{ + nodes.nowhere = { pkgs, ... }: { + passthru = cluster; + environment.systemPackages = [ + pkgs.knot-dns + pkgs.openssl + ]; + }; + + testScript = '' + import json + nodeNames = json.loads('${builtins.toJSON cluster.config.services.dns.nodes.authoritative}') + dotNames = json.loads('${builtins.toJSON cluster.config.services.dns.nodes.coredns}') + nodes = [ n for n in machines if n.name in nodeNames ] + dotServers = [ n for n in machines if n.name in dotNames ] + + start_all() + + with subtest("should allow external name resolution for own domain"): + for node in nodes: + node.wait_for_unit("coredns.service") + nowhere.wait_until_succeeds("[[ $(kdig +short securedns.${domain} | wc -l) -ne 0 ]]", timeout=60) + nowhere.fail("[[ $(kdig +short example.com | wc -l) -ne 0 ]]") + + with subtest("should have valid certificate on DoT endpoint"): + for node in dotServers: + node.wait_for_unit("acme-finished-securedns.${domain}.target") + nowhere.wait_until_succeeds("openssl