cluster/services/dns: init
This commit is contained in:
parent
6b998f4ec2
commit
5356ba97c6
12 changed files with 258 additions and 98 deletions
115
cluster/services/dns/admin.nix
Normal file
115
cluster/services/dns/admin.nix
Normal file
|
@ -0,0 +1,115 @@
|
|||
{ cluster, config, hosts, inputs, lib, pkgs, tools, ... }:
|
||||
|
||||
let
|
||||
inherit (hosts.${config.networking.hostName}) interfaces;
|
||||
inherit (tools.meta) domain;
|
||||
inherit (config.links) pdnsAdmin;
|
||||
inherit (cluster.config) vars;
|
||||
|
||||
pdns-api = cluster.config.links.powerdns-api;
|
||||
|
||||
dataDirUI = "/srv/storage/private/powerdns-admin";
|
||||
|
||||
translateConfig = withQuotes: cfg: let
|
||||
pythonValue = val: if lib.isString val then "'${val}'"
|
||||
else if lib.isAttrs val && val ? env then "__import__('os').getenv('${val.env}')"
|
||||
else if lib.isBool val then (if val then "True" else "False")
|
||||
else if lib.isInt val then toString val
|
||||
else throw "translateConfig: unsupported value type";
|
||||
|
||||
quote = str: if withQuotes then pythonValue str else str;
|
||||
|
||||
configList = lib.mapAttrsToList (n: v: "${n}=${quote v}") cfg;
|
||||
in lib.concatStringsSep "\n" configList;
|
||||
|
||||
login = x: "https://login.${domain}/auth/realms/master/protocol/openid-connect/${x}";
|
||||
in {
|
||||
age.secrets = {
|
||||
pdns-admin-oidc-secrets = {
|
||||
file = ./pdns-admin-oidc-secrets.age;
|
||||
mode = "0400";
|
||||
};
|
||||
pdns-admin-salt = {
|
||||
file = ./pdns-admin-salt.age;
|
||||
mode = "0400";
|
||||
owner = "powerdnsadmin";
|
||||
group = "powerdnsadmin";
|
||||
};
|
||||
pdns-admin-secret = {
|
||||
file = ./pdns-admin-secret.age;
|
||||
mode = "0400";
|
||||
owner = "powerdnsadmin";
|
||||
group = "powerdnsadmin";
|
||||
};
|
||||
pdns-api-key = {
|
||||
file = ./pdns-api-key.age;
|
||||
mode = "0400";
|
||||
};
|
||||
};
|
||||
|
||||
links.pdnsAdmin.protocol = "http";
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [ 53 ];
|
||||
allowedUDPPorts = [ 53 ];
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${dataDirUI}' 0700 powerdnsadmin powerdnsadmin - -"
|
||||
];
|
||||
|
||||
services.powerdns = {
|
||||
enable = true;
|
||||
extraConfig = translateConfig false {
|
||||
api = "yes";
|
||||
webserver-allow-from = "127.0.0.1, ${vars.meshNet.cidr}";
|
||||
webserver-address = pdns-api.ipv4;
|
||||
webserver-port = pdns-api.portStr;
|
||||
api-key = "$scrypt$ln=14,p=1,r=8$ZRgztsniH1y+F7P/RkXq/w==$QTil5kbJPzygpeQRI2jgo5vK6fGol9YS/NVR95cmWRs=";
|
||||
};
|
||||
};
|
||||
|
||||
services.powerdns-admin = {
|
||||
enable = true;
|
||||
secretKeyFile = config.age.secrets.pdns-admin-secret.path;
|
||||
saltFile = config.age.secrets.pdns-admin-salt.path;
|
||||
extraArgs = [ "-b" pdnsAdmin.tuple ];
|
||||
config = translateConfig true {
|
||||
SQLALCHEMY_DATABASE_URI = "sqlite:///${dataDirUI}/pda.db";
|
||||
PDNS_VERSION = pkgs.pdns.version;
|
||||
PDNS_API_URL = pdns-api.url;
|
||||
PDNS_API_KEY.env = "PDNS_API_KEY";
|
||||
|
||||
SIGNUP_ENABLED = false;
|
||||
OIDC_OAUTH_ENABLED = true;
|
||||
OIDC_OAUTH_KEY = "net.privatevoid.dnsadmin1";
|
||||
OIDC_OAUTH_SECRET.env = "OIDC_OAUTH_SECRET";
|
||||
OIDC_OAUTH_SCOPE = "openid profile email roles";
|
||||
|
||||
OIDC_OAUTH_API_URL = login "";
|
||||
OIDC_OAUTH_TOKEN_URL = login "token";
|
||||
OIDC_OAUTH_AUTHORIZE_URL = login "auth";
|
||||
OIDC_OAUTH_LOGOUT_URL = login "logout";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.powerdns-admin.serviceConfig = {
|
||||
BindPaths = [ dataDirUI ];
|
||||
EnvironmentFile = [
|
||||
config.age.secrets.pdns-api-key.path
|
||||
config.age.secrets.pdns-admin-oidc-secrets.path
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."dnsadmin.${domain}" = lib.recursiveUpdate
|
||||
(tools.nginx.vhosts.proxy pdnsAdmin.url)
|
||||
# backend sends really big headers for some reason
|
||||
# increase buffer size accordingly
|
||||
{
|
||||
locations."/".extraConfig = ''
|
||||
proxy_busy_buffers_size 512k;
|
||||
proxy_buffers 4 512k;
|
||||
proxy_buffer_size 256k;
|
||||
'';
|
||||
};
|
||||
}
|
41
cluster/services/dns/authoritative.nix
Normal file
41
cluster/services/dns/authoritative.nix
Normal file
|
@ -0,0 +1,41 @@
|
|||
{ cluster, config, hosts, inputs, lib, pkgs, tools, ... }:
|
||||
|
||||
let
|
||||
inherit (hosts.${config.networking.hostName}) interfaces;
|
||||
inherit (cluster.config) vars;
|
||||
|
||||
patroni = cluster.config.links.patroni-pg-access;
|
||||
pdns-api = cluster.config.links.powerdns-api;
|
||||
|
||||
translateConfig = cfg: let
|
||||
configList = lib.mapAttrsToList (n: v: "${n}=${v}") cfg;
|
||||
in lib.concatStringsSep "\n" configList;
|
||||
in {
|
||||
age.secrets = {
|
||||
pdns-db-credentials = {
|
||||
file = ./pdns-db-credentials.age;
|
||||
mode = "0400";
|
||||
owner = "pdns";
|
||||
group = "pdns";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [ 53 ];
|
||||
allowedUDPPorts = [ 53 ];
|
||||
};
|
||||
|
||||
services.powerdns = {
|
||||
enable = true;
|
||||
extraConfig = translateConfig {
|
||||
launch = "gpgsql";
|
||||
local-address = interfaces.primary.addr;
|
||||
gpgsql-host = patroni.ipv4;
|
||||
gpgsql-port = patroni.portStr;
|
||||
gpgsql-dbname = "powerdns";
|
||||
gpgsql-user = "powerdns";
|
||||
gpgsql-extra-connection-parameters = "passfile=${config.age.secrets.pdns-db-credentials.path}";
|
||||
version-string = "Private Void DNS";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
{ config, hosts, inputs, pkgs, tools, ... }:
|
||||
# TODO: is this secure?
|
||||
|
||||
let
|
||||
inherit (hosts.${config.networking.hostName}) interfaces;
|
||||
inherit (tools.meta) domain;
|
||||
inherit (config.links) localRecursor;
|
||||
inherit (inputs.self.packages.${pkgs.system}) stevenblack-hosts;
|
||||
dot = config.security.acme.certs."securedns.${domain}";
|
||||
in {
|
||||
imports = [ ./zones.nix ];
|
||||
in
|
||||
|
||||
{
|
||||
links.localRecursor = {};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [ 53 853 ];
|
||||
allowedUDPPorts = [ 53 853 ];
|
||||
allowedTCPPorts = [ 853 ];
|
||||
allowedUDPPorts = [ 853 ];
|
||||
};
|
||||
|
||||
systemd.services.coredns = {
|
||||
|
@ -19,6 +23,7 @@ in {
|
|||
"dot-key.pem:${dot.directory}/key.pem"
|
||||
];
|
||||
};
|
||||
|
||||
security.acme.certs."securedns.${domain}" = {
|
||||
group = "nginx";
|
||||
webroot = "/var/lib/acme/acme-challenge";
|
||||
|
@ -28,52 +33,42 @@ in {
|
|||
"coredns.service"
|
||||
];
|
||||
};
|
||||
|
||||
services.coredns = {
|
||||
enable = true;
|
||||
config = ''
|
||||
. {
|
||||
bind ${interfaces.vstub.addr}
|
||||
hosts ${inputs.self.packages.${pkgs.system}.stevenblack-hosts} {
|
||||
bind 127.0.0.1
|
||||
hosts ${stevenblack-hosts} {
|
||||
fallthrough
|
||||
}
|
||||
chaos "Private Void DNS" info@privatevoid.net
|
||||
forward . 127.0.0.1
|
||||
forward . ${localRecursor.tuple}
|
||||
}
|
||||
tls://.:853 {
|
||||
bind ${interfaces.primary.addr}
|
||||
tls {$CREDENTIALS_DIRECTORY}/dot-cert.pem {$CREDENTIALS_DIRECTORY}/dot-key.pem
|
||||
hosts ${inputs.self.packages.${pkgs.system}.stevenblack-hosts} {
|
||||
hosts ${stevenblack-hosts} {
|
||||
fallthrough
|
||||
}
|
||||
chaos "Private Void DNS" info@privatevoid.net
|
||||
forward . ${interfaces.primary.addr}
|
||||
forward . ${localRecursor.tuple}
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
services.bind = {
|
||||
services.pdns-recursor = {
|
||||
enable = true;
|
||||
# TODO: un-hardcode all ip addresses
|
||||
listenOn = [ interfaces.primary.addr "127.0.0.1" ];
|
||||
ipv4Only = true;
|
||||
|
||||
cacheNetworks = [ "10.0.0.0/8" ];
|
||||
extraConfig = ''
|
||||
acl "trusted" {
|
||||
127.0.0.0/8;
|
||||
::1/128;
|
||||
${interfaces.vstub.addr}/32;
|
||||
10.100.0.0/16;
|
||||
10.10.0.0/16;
|
||||
};
|
||||
acl "publicservers" {
|
||||
116.202.226.86/32;
|
||||
};
|
||||
'';
|
||||
extraOptions = ''
|
||||
recursion yes;
|
||||
allow-recursion { trusted; ${interfaces.primary.addr}/32; };
|
||||
dnssec-validation no;
|
||||
'';
|
||||
dnssecValidation = "process";
|
||||
forwardZones = {
|
||||
# optimize queries against our own domain
|
||||
"${domain}" = interfaces.primary.addr;
|
||||
};
|
||||
dns = {
|
||||
inherit (localRecursor) port;
|
||||
address = localRecursor.ipv4;
|
||||
allowFrom = [ "127.0.0.1" ];
|
||||
};
|
||||
};
|
||||
}
|
32
cluster/services/dns/default.nix
Normal file
32
cluster/services/dns/default.nix
Normal file
|
@ -0,0 +1,32 @@
|
|||
{ config, ... }:
|
||||
|
||||
let
|
||||
inherit (config.vars) hosts;
|
||||
in
|
||||
{
|
||||
links = {
|
||||
dnsResolver = {
|
||||
ipv4 = hosts.VEGAS.interfaces.vstub.addr;
|
||||
port = 53;
|
||||
};
|
||||
powerdns-api = {
|
||||
ipv4 = config.vars.mesh.VEGAS.meshIp;
|
||||
protocol = "http";
|
||||
};
|
||||
};
|
||||
services.dns = {
|
||||
nodes = {
|
||||
master = [ "VEGAS" ];
|
||||
slave = [ "prophet" ];
|
||||
coredns = [ "VEGAS" ];
|
||||
};
|
||||
nixos = {
|
||||
master = [
|
||||
./authoritative.nix
|
||||
./admin.nix
|
||||
];
|
||||
slave = ./authoritative.nix;
|
||||
coredns = ./coredns.nix;
|
||||
};
|
||||
};
|
||||
}
|
BIN
cluster/services/dns/pdns-admin-oidc-secrets.age
Normal file
BIN
cluster/services/dns/pdns-admin-oidc-secrets.age
Normal file
Binary file not shown.
11
cluster/services/dns/pdns-admin-salt.age
Normal file
11
cluster/services/dns/pdns-admin-salt.age
Normal file
|
@ -0,0 +1,11 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 NO562A d/YNanH/cHoFLPp8WcCXHh/LQLRwaUa95JiRLbgb8RI
|
||||
UPEHpnHHTU6dGKi2MbApEspcpt1lFtFZ4XJjShL7OoE
|
||||
-> ssh-ed25519 5/zT0w Rv9ZS5P2Eca3npPLR7yym/XTRSDfVmgRwH1pAGR79T8
|
||||
4A/KXc2wxxokfDAwWYf0ZTUEzQ8ldkC+zRNZY3KjBTs
|
||||
-> ssh-ed25519 d3WGuA 2R0kaVjuhU3wT9pjj214zkEaHYNSlMxf9Z+MfBssHwY
|
||||
EU5LWk6xfohWM/3sAqYtUvFmRgIPxOLXHnlqbsQ3+ok
|
||||
-> -|(-grease W=cc~ O2q5
|
||||
FZzh/ZwDS2EqvVZ9NErmUwCMN72op1Qy
|
||||
--- Ducan3ugRJC3dmWLr7+FKok+WmInOgOzW0ccYeqAFAQ
|
||||
Ì•ãÆ*Q. SC<53>ûf¹‰*`5<>„ÑÖw"~ÍxwÜ*–ã\‹êÙ"²ÅtŒ '’É0ï™<C3AF>L£ï
|
12
cluster/services/dns/pdns-admin-secret.age
Normal file
12
cluster/services/dns/pdns-admin-secret.age
Normal file
|
@ -0,0 +1,12 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 NO562A hUR+UdHnpazhANM8DKToI5Th3lv1aAuxZ1IQKvCOv34
|
||||
PvsiSym8YdleDULLnWuTs1x08KO3EmAg/AAjulgrgqE
|
||||
-> ssh-ed25519 5/zT0w qMXS2xLOLv/+l6brG11i+3FwHdrhlmxZBNtBiU9hu2g
|
||||
BlFYPvH4mFJRMHTlHwnBdJb6QcugylwZuT5bgSKcQa0
|
||||
-> ssh-ed25519 d3WGuA k2fRQ3+HyZP+bb/gkVKQqUmbITJLPm9tGp67DbRfiCs
|
||||
RX9CACfYpYKvSqyfXjvEokTGsp4+ECQBD8i1ehD5xRg
|
||||
-> IB@F$9G-grease
|
||||
cXRgUVdIPGEjft1CJA
|
||||
--- si16Det/GwF7GLHLt0ha8v4rFFeJXyhEylIiqzZVAK8
|
||||
Ö°å¤pÐǺ#ê4^©—
~u
UuçaòQ´™Bâj˜(N)qÃ<"¤%ì’,V9û5ZÔh§#W«[»ò¶”"Mÿ&”îäøÖýá+%Œ«„SQ€B÷Þ›ÕÀèÕyàÜî<aéó]P‚$´Ä±B¨½qQÑÉQ‡M‰TËt°
|
||||
·s¹mÿ~qW–Ö«çêõÜ×Ì=.Q“"ù”–Þø¶ÏnqRk<52>=ÏcÿçüßÃqv¢¾>#ŠÏ«²tïwq,÷ »3YyIq}Ê“ì>sgíz™ûs±Þ ¸Æ†FÄPê|ÍüÅ¡=ùÃþ~KQR,DZuÐ+ÕºZGHëa=‹©;ÀõC.ÏuVShÅ$Và€AË9Ð=
?•¢
|
BIN
cluster/services/dns/pdns-api-key.age
Normal file
BIN
cluster/services/dns/pdns-api-key.age
Normal file
Binary file not shown.
15
cluster/services/dns/pdns-db-credentials.age
Normal file
15
cluster/services/dns/pdns-db-credentials.age
Normal file
|
@ -0,0 +1,15 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 NO562A /puQyDz+IepPqd8PTnD+YUp1obCh4gO1/7GGKaUAcRk
|
||||
ydUvPiZyl9OZ3gVlhDxPkFf4PiPmQQtFoL9PK4pcA5Y
|
||||
-> ssh-ed25519 5/zT0w MUEtkOeKzCBDBjoJjfkRnTmwl3pa0Qo07EKOpQp8RTQ
|
||||
rUEyKc2BiQIxoPxTpoDPDfeJie2cfocwyT/VmIQcqL8
|
||||
-> ssh-ed25519 d3WGuA 0pGUj+2YukJEgbIZ++iUKwfCp8yGiU2iUuyk0NFlYSg
|
||||
/O3DY0EO3odBXvQNM14PdkrRmCLHOIvOIdgTsq5jBsQ
|
||||
-> ssh-ed25519 6YMlxg Us2lOVb1NCc8yTqT/pe8UEb6qNePw7onN7J2z0mkb0s
|
||||
WWtatJOs1krHZxmFddhmDOEfMNvGKBPFdAUnekKaccE
|
||||
-> H7;a-ODO-grease <iF?
|
||||
3z2aQlpJcCIhfAyzypdzUXfLZGGhYM7Rgp0uVOZYH7V1p/jspvJhrFyWKpcjfblj
|
||||
qyjXRWASpQzl4jT5g1oUFB8u8A
|
||||
--- lVvMLw/p/T07fWOaz/+IGn7uQgfb9BwXE8Wnh4F3JzA
|
||||
äZÅî™å<¼ÔÝõŒ?EIÂãHÂç+*ïéM¹»œjk?/BÎâ4`ù7S^’t<>‡¨ÄU®`Soý1xjÒ®õz7D>ÄßñÀÜNy¾˜!`X@)ÿݱ?n6ú§(<ªãƒÀ|bG¨M…àµBd¼3Ú§—$±i#qåhðgP…j¸Þ¼äÒ…VT¯¸ :¡Å½Óõ¬và{Ïùâªò“‡ÿ´û?4Ï&0<>5O%D|u{<7B>ç*“2û¾„B!à'(.0Ö<EFBFBD>Ó°ßKg‚±Ñ¼ƒ"&LKq•<DÛòóÔqµ[;x²Pœ»]<5D>}ŽkÛëලXdfú›Óïy_ï
|
||||
LÌC?†éhH(c¥I•¥<E280A2>½ÁyZÏ¿ãÐ|}#Å:w
vìÇ5A¾ ÍzÈËrí÷:¥½› ÷
|
|
@ -1,65 +0,0 @@
|
|||
{ lib, tools, ... }:
|
||||
|
||||
# upstream's zone generator is pretty bad, so...
|
||||
|
||||
# TODO: make this prettier
|
||||
|
||||
let
|
||||
inherit (tools.meta) domain;
|
||||
inherit (tools) nginx identity;
|
||||
|
||||
externalSlave = { name, masters ? [ identity.dns.master.addr ], notify ? "no", alsoNotify ? [ "none" ] }: let
|
||||
zoneName = "${name}";
|
||||
file = "/var/named/slaves/ext_${zoneName}.db";
|
||||
mastersFormatted = builtins.concatStringsSep "; " masters;
|
||||
notifiersFormatted = builtins.concatStringsSep "; " alsoNotify;
|
||||
in ''
|
||||
zone "${zoneName}." IN {
|
||||
type slave;
|
||||
masters { ${mastersFormatted}; };
|
||||
file "${file}";
|
||||
allow-transfer { trusted; publicservers; };
|
||||
allow-query { any; };
|
||||
notify ${notify};
|
||||
also-notify { ${notifiersFormatted}; };
|
||||
};
|
||||
'';
|
||||
internalSlave' = domain: name: let
|
||||
zoneName = "${name}${domain}";
|
||||
file = "/var/named/slaves/int_${zoneName}.db";
|
||||
in ''
|
||||
zone "${zoneName}." IN {
|
||||
type slave;
|
||||
masters { ${identity.dns.master.addr}; };
|
||||
file "${file}";
|
||||
allow-transfer { trusted; };
|
||||
allow-query { trusted; };
|
||||
notify no;
|
||||
};
|
||||
'';
|
||||
internalSlave = internalSlave' ".${domain}";
|
||||
revSlave = internalSlave' ".in-addr.arpa";
|
||||
toAttr = value: { inherit (value) name; inherit value; };
|
||||
in
|
||||
{
|
||||
services.bind.extraConfig = builtins.concatStringsSep "\n" ([
|
||||
(externalSlave { name = domain; notify = "explicit"; alsoNotify = [ "116.202.226.86" ]; })
|
||||
(externalSlave { name = "imagine-using-oca.ml"; notify = "explicit"; alsoNotify = [ "116.202.226.86" ]; })
|
||||
(externalSlave { name = "animus.com"; masters = [ "116.202.226.86" ]; })
|
||||
] ++ map internalSlave [
|
||||
"virtual-machines"
|
||||
"core"
|
||||
"services"
|
||||
"ext"
|
||||
"int"
|
||||
"vpn"
|
||||
"find"
|
||||
] ++ map revSlave [
|
||||
"0.10.10"
|
||||
"1.10.10"
|
||||
"2.10.10"
|
||||
"100.10"
|
||||
] ++ map (internalSlave' "") [
|
||||
"void"
|
||||
]);
|
||||
}
|
|
@ -19,7 +19,6 @@
|
|||
./services/api
|
||||
./services/backbone-routing
|
||||
./services/bitwarden
|
||||
./services/dns
|
||||
./services/fbi
|
||||
./services/gitlab
|
||||
./services/hydra
|
||||
|
|
|
@ -4,6 +4,11 @@ let
|
|||
systemKeys = x: x.ssh.id.publicKey or null;
|
||||
in with hosts;
|
||||
{
|
||||
"cluster/services/dns/pdns-admin-oidc-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS ];
|
||||
"cluster/services/dns/pdns-admin-salt.age".publicKeys = max ++ map systemKeys [ VEGAS ];
|
||||
"cluster/services/dns/pdns-admin-secret.age".publicKeys = max ++ map systemKeys [ VEGAS ];
|
||||
"cluster/services/dns/pdns-api-key.age".publicKeys = max ++ map systemKeys [ VEGAS ];
|
||||
"cluster/services/dns/pdns-db-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
|
||||
"cluster/services/patroni/passwords/replication.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
|
||||
"cluster/services/patroni/passwords/rewind.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
|
||||
"cluster/services/patroni/passwords/superuser.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];
|
||||
|
|
Loading…
Reference in a new issue