Working backplane dns client/server

This commit is contained in:
nostoromo root 2020-11-17 15:23:07 -08:00
parent 3165c259bc
commit 80be04edd5
3 changed files with 51 additions and 125 deletions

View File

@ -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}
'';
};
};

View File

@ -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;

View File

@ -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