From 80be04edd5abe6fe6ba00b22dc8e829198e59ece Mon Sep 17 00:00:00 2001 From: nostoromo root Date: Tue, 17 Nov 2020 15:23:07 -0800 Subject: [PATCH] Working backplane dns client/server --- config/fudo/client/dns.nix | 11 +- hosts/nostromo.nix | 124 ---------------------- static/backplane-dns-client/dns-client.rb | 41 +++++++ 3 files changed, 51 insertions(+), 125 deletions(-) diff --git a/config/fudo/client/dns.nix b/config/fudo/client/dns.nix index c2bcced..7a9d348 100644 --- a/config/fudo/client/dns.nix +++ b/config/fudo/client/dns.nix @@ -20,6 +20,12 @@ in { description = "Report host external IPv6 address to Fudo DynDNS server."; }; + sshfp = mkOption { + type = types.bool; + default = true; + description = "Report host SSH fingerprints to the Fudo DynDNS server."; + }; + domain = mkOption { type = types.str; description = "Domain under which this host is registered."; @@ -55,6 +61,8 @@ in { description = "Interface with which this host communicates with the larger internet."; default = null; }; + + # FIXME: take the relevant SSH package }; config = mkIf cfg.enable { @@ -85,8 +93,9 @@ in { StandardOutput = "journal"; User = cfg.user; }; + path = [ pkgs.openssh ]; script = '' - ${pkgs.backplane-dns-client}/bin/backplane-dns-client ${optionalString cfg.ipv4 "-4"} ${optionalString cfg.ipv6 "-6"} ${optionalString (cfg.external-interface != null) "--interface=${cfg.external-interface}"} --domain=${cfg.domain} --server=${cfg.server} --password-file=${cfg.password-file} + ${pkgs.backplane-dns-client}/bin/backplane-dns-client ${optionalString cfg.ipv4 "-4"} ${optionalString cfg.ipv6 "-6"} ${optionalString cfg.sshfp "-f"} ${optionalString (cfg.external-interface != null) "--interface=${cfg.external-interface}"} --domain=${cfg.domain} --server=${cfg.server} --password-file=${cfg.password-file} ''; }; }; diff --git a/hosts/nostromo.nix b/hosts/nostromo.nix index d912e2c..22a1675 100644 --- a/hosts/nostromo.nix +++ b/hosts/nostromo.nix @@ -100,146 +100,22 @@ in { users = { users = { - backplane-powerdns = { - isSystemUser = true; - }; - backplane-dns = { - isSystemUser = true; - }; fudo-client = { isSystemUser = true; }; }; - - groups = { - backplane-powerdns = { - members = [ "backplane-powerdns" ]; - }; - backplane-dns = { - members = [ "backplane-dns" ]; - }; - }; }; fudo = { - password.file-generator = { - dns_backplane_powerdns = { - file = "/srv/backplane/dns/secure/db_powerdns.passwd"; - user = config.services.postgresql.superUser; - group = "backplane-powerdns"; - restart-services = [ - "backplane-dns-config-generator.service" - "postgresql-password-setter.service" - "backplane-powerdns.service" - ]; - }; - dns_backplane_database = { - file = "/srv/backplane/dns/secure/db_backplane.passwd"; - user = config.services.postgresql.superUser; - group = "backplane-dns"; - restart-services = [ - "backplane-dns.service" - "postgresql-password-setter.service" - ]; - }; - }; - - backplane.dns = { - enable = true; - port = 353; - listen-addresses = [ "10.0.0.1" ]; - required-services = [ "fudo-passwords.target" ]; - user = "backplane-dns"; - group = "backplane-dns"; - database = { - username = "backplane_powerdns"; - database = "backplane_dns"; - # Uses an IP to avoid cyclical dependency...not really relevant, but - # whatever - host = "127.0.0.1"; - password-file = "/srv/backplane/dns/secure/db_powerdns.passwd"; - }; - backplane = { - host = "backplane.fudo.org"; - role = "service-dns"; - password-file = "/srv/backplane/dns/secure/backplane.passwd"; - database = { - username = "backplane_dns"; - database = "backplane_dns"; - host = "127.0.0.1"; - password-file = "/srv/backplane/dns/secure/db_backplane.passwd"; - }; - }; - }; - client.dns = { enable = true; ipv4 = true; ipv6 = true; - domain = "dyn.fudo.org"; user = "fudo-client"; external-interface = "eno2"; password-file = "/srv/client/secure/client.passwd"; }; - postgresql = { - enable = true; - ssl-private-key = "/srv/nostromo/certs/private/privkey.pem"; - ssl-certificate = "/srv/nostromo/certs/cert.pem"; - keytab = "/srv/nostromo/keytabs/postgres.keytab"; - required-services = [ "fudo-passwords.target" ]; - - local-networks = [ - "10.0.0.1/24" - "127.0.0.1/8" - ]; - - users = { - backplane_powerdns = { - password-file = "/srv/backplane/dns/secure/db_powerdns.passwd"; - databases = { - backplane_dns = { - access = "CONNECT"; - entity-access = { - "ALL TABLES IN SCHEMA public" = "SELECT"; - }; - }; - }; - }; - backplane_dns = { - password-file = "/srv/backplane/dns/secure/db_backplane.passwd"; - databases = { - backplane_dns = { - access = "CONNECT"; - entity-access = { - "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE"; - "ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE"; - }; - }; - }; - }; - niten = { - databases = { - backplane_dns = { - access = "ALL PRIVILEGES"; - entity-access = { - "ALL TABLES IN SCHEMA public" = "ALL PRIVILEGES"; - "ALL SEQUENCES IN SCHEMA public" = "ALL PRIVILEGES"; - }; - }; - }; - }; - }; - - local-users = ["niten"]; - - databases = { - backplane_dns = { - users = ["niten"]; - }; - }; - }; - secure-dns-proxy = { enable = true; port = 3535; diff --git a/static/backplane-dns-client/dns-client.rb b/static/backplane-dns-client/dns-client.rb index 34570a1..d2fca16 100644 --- a/static/backplane-dns-client/dns-client.rb +++ b/static/backplane-dns-client/dns-client.rb @@ -42,6 +42,11 @@ OptionParser.new do |opts| "Check for a public IPv6 and register with the backplane.") do options[:ipv6] = true end + + opts.on("-f", "--sshfp", + "Register host SSH key fingerprints with the backplane.") do + options[:sshfp] = true + end end.parse! def error(msg) @@ -98,10 +103,12 @@ class XMPPClient def send(msg_content) msg_id = SecureRandom::uuid encoded_payload = payload(msg_content, msg_id).to_json + puts "payload: #{encoded_payload}" msg = Jabber::Message.new(@service_jid, encoded_payload) msg.type = :chat @client.send(msg) response = receive_response(msg_id) + puts "response: #{response}" response and response["status"] == "OK" end @@ -109,6 +116,10 @@ class XMPPClient send(ip_payload(ip)) end + def send_sshfp(fps) + send(sshfp_payload(fps)) + end + def payload(req, msg_id) { version: 1, @@ -126,6 +137,14 @@ class XMPPClient } end + def sshfp_payload(fp) + { + request: :change_sshfp, + domain: @domain, + sshfp: fp + } + end + def register_response_callback @client.add_message_callback do |msg| enqueue_message(JSON.parse(msg.body)) @@ -198,6 +217,13 @@ def interface_addresses(interface) end end +def host_sshfp + keys = `ssh-keygen -r hostname`.split("\n").map do |k| + k.match(/[0-9] [0-9] [a-fA-F0-9]{32,64}$/)[0] + end + keys.compact +end + client = XMPPClient::new(options[:domain], Socket::gethostname, options[:server], @@ -243,6 +269,21 @@ begin puts "#{options[:server]}: no valid public IPv6 found on the local host" end end + + if options[:sshfp] + fps = host_sshfp + if not fps.empty? + puts "#{options[:server]}: #{Socket::gethostname}.#{options[:domain]} IN SSHFP => #{fps}" + if client.send_sshfp(fps) + puts "OK" + else + puts "ERROR" + success = false + end + else + puts "#{options[:server]}: no valid sshfps found" + end + end ensure client.disconnect end