add dns role
This commit is contained in:
parent
24e8170453
commit
7b3c103b5b
7 changed files with 251 additions and 0 deletions
12
mapping.nix
12
mapping.nix
|
@ -15,6 +15,18 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dns = rec {
|
||||||
|
master = "master-dns-aur-lasuite-federez";
|
||||||
|
secondary = [
|
||||||
|
"dns-mtz-lasuite-federez"
|
||||||
|
"dns-ren-lasuite-federez"
|
||||||
|
];
|
||||||
|
hosts = [ master ] ++ secondary;
|
||||||
|
_inherit = [
|
||||||
|
./shared/dns.nix
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
# For instance:
|
# For instance:
|
||||||
# psql = rec {
|
# psql = rec {
|
||||||
# master = "some-node-1";
|
# master = "some-node-1";
|
||||||
|
|
BIN
secrets/dns/tsig.age
Normal file
BIN
secrets/dns/tsig.age
Normal file
Binary file not shown.
BIN
secrets/mail/dkim.age
Normal file
BIN
secrets/mail/dkim.age
Normal file
Binary file not shown.
|
@ -35,6 +35,17 @@ let
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN3YPa6rCr7re5CmZ1T4Zh6k9U9E6eVs7KgLpOEKT+Kx root@bastion-aur-lasuite-federez"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN3YPa6rCr7re5CmZ1T4Zh6k9U9E6eVs7KgLpOEKT+Kx root@bastion-aur-lasuite-federez"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
system-dns = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOCkwjv+R6OgPdcv+4aaymDHnHgWKA4Ez2h0D2dRD0Jr root@dns-mtz-lasuite-federez"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFOARZoBC95SxV2tL5hbE20vnOS7VIyn4/ACeVdpIZ2D root@dns-ren-lasuite-federez"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHb5RKh1JEfStK1ZlJnvw9SH+GgZYJVC6GebbWWgtvwW root@master-dns-aur-lasuite-federez"
|
||||||
|
];
|
||||||
|
|
||||||
|
system-mail = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIv9JPqMuWRU1tQ5R8rMcxfv5etDwuvGH4LzOWx98v0t root@mail-mtz-lasuite-federez"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJQ24UID4nGKru/to8wSoJ6LMcKwP3d9kZG7dlew0g9S root@mail-ren-lasuite-federez"
|
||||||
|
];
|
||||||
|
|
||||||
asyncnomi = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIENo/g3BZ1bJViYE6EY4VZO96a4q8U4nWKjTprQJtjEH asyncnomi" ];
|
asyncnomi = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIENo/g3BZ1bJViYE6EY4VZO96a4q8U4nWKjTprQJtjEH asyncnomi" ];
|
||||||
gamma = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKhuKmuBPLAtQSjy4E4UaEmf8Qj56414r+adAJ6BgmO8 gamma" ];
|
gamma = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKhuKmuBPLAtQSjy4E4UaEmf8Qj56414r+adAJ6BgmO8 gamma" ];
|
||||||
jeltz = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHabXDr/vrx361yaxKK58jHJB77TNVZvqhkIiaTB7ECI jeltz" ];
|
jeltz = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHabXDr/vrx361yaxKK58jHJB77TNVZvqhkIiaTB7ECI jeltz" ];
|
||||||
|
@ -82,4 +93,12 @@ in
|
||||||
"bastion/wg-private-zone-1.age".publicKeys = system-bastion ++ users;
|
"bastion/wg-private-zone-1.age".publicKeys = system-bastion ++ users;
|
||||||
"bastion/wg-private-zone-2.age".publicKeys = system-bastion ++ users;
|
"bastion/wg-private-zone-2.age".publicKeys = system-bastion ++ users;
|
||||||
"bastion/wg-private-zone-3.age".publicKeys = system-bastion ++ users;
|
"bastion/wg-private-zone-3.age".publicKeys = system-bastion ++ users;
|
||||||
|
|
||||||
|
# DNS secrets
|
||||||
|
|
||||||
|
"dns/tsig.age".publicKeys = system-dns ++ users;
|
||||||
|
|
||||||
|
# Mail secrets
|
||||||
|
|
||||||
|
"mail/dkim.age".publicKeys = system-mail ++ users;
|
||||||
}
|
}
|
7
shared/dns.nix
Normal file
7
shared/dns.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# Import dependencies
|
||||||
|
imports = [
|
||||||
|
./dns/knot.nix
|
||||||
|
];
|
||||||
|
}
|
3
shared/dns/dkim.nix
Normal file
3
shared/dns/dkim.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
dkim_pub = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0ki3RIIQaUhimeaE6AATJCA6l9Wh9Qi+RZppylD/Ivi53z0ikp07oc3o31HCbK/mSj7ewD+WUxhfytAkyPsZn1q4WNLuxXcE+cto9IbLWxzc3uKpxmY8VEOL5xWQaiiCW4GE6wzOSLaD5w6+x9I54U3JEEOiheFBJCLwpjoCv+osoSYKuQUnYMQPfz6m4gYS9kfhbSo1Xg+GxwwfpzpXcnStBZQfAl7L3w4TeftpDIUV3Xmn2kud84ldhnOMSAWelApvzSGmeiXRbozeWWTdxbw3UU1QL/h7kjEW2TkNXINHhHRvmoqyjzzZzeQ5DN7ETMEHpFsqSWdBnW2MM/VaTaUrcOuXjN6U2QymRA01byybROLxkdeV2PtPpZnCwzBbYuB2qFqFhQKEep9X6OYdUlVXZOlcfGPY3dj2sYwV045TcWMMSiAaKqF+jVILxXa3RqaeGsMEe52QLtxLvqLbPmdlTg7J8+jShJngzB1qne0vvMZT7tu7ez4lJsua+H5kqpuLIxSjQ1ea+XzWApr1JzktCMluh7SaY1AWFp/epCGhtjByy2dzgYYc/Ij1ieaAa2XdR57WZx4G9WaKCpSc8SOWn+TxCBRssd6fIAOe69WYD5Db35xoQFXPL9wRSgw5GzkBkHzHYwu+IjORjZNtB1/mMQWsnRl/QPW1rGQZeikCAwEAAQ==";
|
||||||
|
}
|
210
shared/dns/knot.nix
Normal file
210
shared/dns/knot.nix
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Import nodes
|
||||||
|
nodes = import ./../../nodes.nix;
|
||||||
|
myNode = nodes."${config.hostName}";
|
||||||
|
|
||||||
|
# And mapping
|
||||||
|
mapping = import ./../../mapping.nix;
|
||||||
|
|
||||||
|
dkim = import ./dkim.nix;
|
||||||
|
|
||||||
|
supportsIPv4 = nd: lib.hasAttr "ip4" nd;
|
||||||
|
supportsIPv6 = nd: lib.hasAttr "ip6" nd;
|
||||||
|
|
||||||
|
timestampDerivation = pkgs.runCommand "timestamp" {} ''
|
||||||
|
echo -n $(date +%s) > $out
|
||||||
|
'';
|
||||||
|
timestamp = builtins.readFile timestampDerivation;
|
||||||
|
|
||||||
|
# Domain key
|
||||||
|
domainkey = ''
|
||||||
|
v=DKIM1; k=rsa; p=${dkim.dkim_pub}'';
|
||||||
|
segments = ((lib.stringLength domainkey) / 255);
|
||||||
|
domainkeySplitted = map (x: lib.substring (x*255) 255 domainkey) (lib.range 0 segments);
|
||||||
|
|
||||||
|
|
||||||
|
#####
|
||||||
|
## Knot specific
|
||||||
|
#####
|
||||||
|
|
||||||
|
# Define remote based on current role
|
||||||
|
remotes = if myNode == mapping.dns.master then
|
||||||
|
map (hostname: {
|
||||||
|
id = hostname;
|
||||||
|
address = "172.19.${toString nodes.${hostname}.zone}.${toString nodes.${hostname}.id}@53";
|
||||||
|
}) mapping.dns.secondary
|
||||||
|
else
|
||||||
|
[{
|
||||||
|
id = mapping.dns.master;
|
||||||
|
address = "172.19.${toString nodes.${mapping.dns.master}.zone}.${toString nodes.${mapping.dns.master}.id}@53";
|
||||||
|
}];
|
||||||
|
|
||||||
|
remotesNames = map (remote: remote.id) remotes;
|
||||||
|
|
||||||
|
# Remotes ACL
|
||||||
|
remotesACL = if myNode == mapping.dns.master then
|
||||||
|
map (hostname: {
|
||||||
|
id = "acl_${hostname}";
|
||||||
|
address = "172.19.${toString nodes.${hostname}.zone}.${toString nodes.${hostname}.id}@53";
|
||||||
|
action = "transfer";
|
||||||
|
}) mapping.dns.secondary
|
||||||
|
else
|
||||||
|
[{
|
||||||
|
id = "acl_${mapping.dns.master}";
|
||||||
|
address = "172.19.${toString nodes.${mapping.dns.master}.zone}.${toString nodes.${mapping.dns.master}.id}@53";
|
||||||
|
action = "notify";
|
||||||
|
}];
|
||||||
|
|
||||||
|
remotesACLNames = map (remote: remote.id) remotesACL;
|
||||||
|
|
||||||
|
# Other ACL
|
||||||
|
letsencryptACL = if myNode == mapping.dns.master then
|
||||||
|
[{
|
||||||
|
id = "acl_le_challenge";
|
||||||
|
address = [
|
||||||
|
"172.19.0.0/16"
|
||||||
|
"fc00::/96"
|
||||||
|
];
|
||||||
|
action = "update";
|
||||||
|
update-type = "TXT";
|
||||||
|
key = "letsencrypt";
|
||||||
|
}]
|
||||||
|
else [];
|
||||||
|
|
||||||
|
#####
|
||||||
|
## Zone specific
|
||||||
|
#####
|
||||||
|
|
||||||
|
# host to dn
|
||||||
|
hostToDomain = hostname: builtins.replaceStrings ["-"] ["."] hostname;
|
||||||
|
|
||||||
|
# Gen NS
|
||||||
|
toNSRecord = host: "IN NS ${hostToDomain host}.net.";
|
||||||
|
nsRecords = map toNSRecord mapping.dns.secondary;
|
||||||
|
|
||||||
|
dnsSecondaryConfigs = lib.filterAttrs (peerName: _peerConfig: lib.elem peerName mapping.dns.secondary) nodes;
|
||||||
|
|
||||||
|
# Gen A NS
|
||||||
|
nsARecords = lib.flatten (lib.mapAttrsToList (hostname: node:
|
||||||
|
lib.optional (supportsIPv4 node) "${hostToDomain hostname}.net. IN A ${node.ip4}"
|
||||||
|
) dnsSecondaryConfigs);
|
||||||
|
|
||||||
|
# Gen AAAA NS
|
||||||
|
nsAAAARecords = lib.flatten (lib.mapAttrsToList (hostname: node:
|
||||||
|
lib.optional (supportsIPv6 node) "${hostToDomain hostname}.net. IN AAAA ${node.ip6}"
|
||||||
|
) dnsSecondaryConfigs);
|
||||||
|
|
||||||
|
# Zone conf
|
||||||
|
zoneFilePath = "/var/lib/knot/zones/zone-lasuite-federez-net";
|
||||||
|
zone-lasuite-federez-net = pkgs.writeText "zone-lasuite-federez-net" ''
|
||||||
|
$ORIGIN lasuite.federez.net.
|
||||||
|
$TTL 60
|
||||||
|
@ IN SOA ${builtins.head nsRecords}. monitoring.lasuite.federez.net. (
|
||||||
|
${timestamp} ; serial
|
||||||
|
60 ; refresh
|
||||||
|
60 ; retry
|
||||||
|
60 ; expire
|
||||||
|
60 ) ; minimum TTL
|
||||||
|
|
||||||
|
IN TXT "v=spf1 a:lasuite.federez.net ~all"
|
||||||
|
|
||||||
|
${builtins.concatStringsSep "\n" nsRecords}
|
||||||
|
|
||||||
|
${builtins.concatStringsSep "\n" nsARecords}
|
||||||
|
${builtins.concatStringsSep "\n" nsAAAARecords}
|
||||||
|
|
||||||
|
_dmarc IN TXT "v=DMARC1; p=quarantine; ruf=mailto:postmaster@lasuite.federez.net"
|
||||||
|
_mta-sts IN TXT "v=STSv1; id=1"
|
||||||
|
_smtp._tls IN TXT "v=TLSRPTv1;rua=mailto:postmaster@lasuite.federez.net"
|
||||||
|
default._domainkey IN TXT "${lib.concatStringsSep "\" \"" domainkeySplitted}"
|
||||||
|
cause-toujours IN TXT "v=spf1 a:lasuite.federez.net ~all"
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
age.secrets = {
|
||||||
|
"tsig" = {
|
||||||
|
file = ./../../secrets/dns/tsig.age;
|
||||||
|
owner = "knot";
|
||||||
|
group = "knot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Ensure the directory exists and is writable
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/lib/knot/zones 0755 knot knot -"
|
||||||
|
"f /var/lib/knot/zones/zone-lasuite-federez-net 0644 knot knot -"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Knot messes with resolvd
|
||||||
|
services.resolved.enable = false;
|
||||||
|
networking.resolvconf.extraConfig = ''
|
||||||
|
name_servers="1.1.1.1 1.0.0.1 2606:4700:4700::1111"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Attach knot to writeZoneFile to force knot to restart after rebuild (otherwise no changes will be detected)
|
||||||
|
systemd.services.knot = {
|
||||||
|
partOf = [ "writeZoneFile.service" ];
|
||||||
|
restartTriggers = [ zone-lasuite-federez-net ];
|
||||||
|
reloadIfChanged = lib.mkForce false;
|
||||||
|
};
|
||||||
|
services.knot = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.knot-dns;
|
||||||
|
|
||||||
|
# To regenerate the secret use:
|
||||||
|
# nix-shell -p knot-dns
|
||||||
|
# keymgr tsig generate -t letsencrypt hmac-sha512
|
||||||
|
keyFiles = [
|
||||||
|
config.age.secrets.tsig.path
|
||||||
|
];
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
listen = [
|
||||||
|
"0.0.0.0@53"
|
||||||
|
"::@53"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
remote = remotes;
|
||||||
|
|
||||||
|
acl = remotesACL ++ otherACL;
|
||||||
|
|
||||||
|
zone = if myNode == mapping.dns.master then [
|
||||||
|
{
|
||||||
|
domain = "lasuite.federez.net";
|
||||||
|
file = zoneFilePath;
|
||||||
|
notify = remotesNames;
|
||||||
|
acl = remotesACLNames ++ [
|
||||||
|
"acl_le_challenge"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
] else [
|
||||||
|
{
|
||||||
|
domain = "lasuite.federez.net";
|
||||||
|
master = builtins.head remotesNames;
|
||||||
|
acl = remotesACLNames;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
log = [
|
||||||
|
{
|
||||||
|
target = "syslog";
|
||||||
|
any = "debug";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Write the generated zone file to the writable path
|
||||||
|
systemd.services.writeZoneFile = {
|
||||||
|
before = [ "knot.service" ];
|
||||||
|
description = "Write initial zone file for lasuite.federez.net";
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.coreutils}/bin/cp '${zone-lasuite-federez-net}' ${zoneFilePath}";
|
||||||
|
};
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue