mirror of
https://github.com/sstent/nixos-cluster.git
synced 2026-01-25 14:42:55 +00:00
150 lines
4.0 KiB
Nix
150 lines
4.0 KiB
Nix
{
|
|
lib,
|
|
pkgs,
|
|
config,
|
|
...
|
|
}: let
|
|
# 1. Merged Hosts Template
|
|
consulAllHostsTemplate = pkgs.writeText "consul-all-hosts.ctmpl" ''
|
|
# --- Static Hosts from Consul KV ---
|
|
{{ printf "\n" }}
|
|
{{- range ls "dns/hosts" -}}
|
|
{{ .Value }} {{ .Key }}
|
|
{{ printf "\n" }}
|
|
{{- end -}}
|
|
|
|
# --- Dynamic Hosts from Consul Services (Traefik Tags) ---
|
|
{{ printf "\n" }}
|
|
{{- range services -}}
|
|
{{- range service .Name -}}
|
|
{{- /* Determine IP: Use Service Address, fall back to Node Address */ -}}
|
|
{{- $ip := .Address -}}
|
|
{{- if eq $ip "" -}}
|
|
{{- $ip = .NodeAddress -}}
|
|
{{- end -}}
|
|
|
|
{{- /* Scan Tags */ -}}
|
|
{{- range .Tags -}}
|
|
{{- if . | regexMatch "traefik.http.routers.*.rule=Host" -}}
|
|
|
|
{{- /* 1. Extract content inside Host(...) */ -}}
|
|
{{- $content := . | regexReplaceAll ".*Host\\(([^)]+)\\).*" "$1" -}}
|
|
|
|
{{- /* 2. Clean up quotes and spaces */ -}}
|
|
{{- $clean := $content | regexReplaceAll "[`'\"\\s]" "" -}}
|
|
|
|
{{- /* 3. Split by comma and print */ -}}
|
|
{{- range split "," $clean -}}
|
|
{{- if ne . "" -}}
|
|
{{ $ip }} {{ . }}
|
|
{{ printf "\n" }}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
'';
|
|
|
|
# 2. Wrapper script to ensure clean execution and environment setup
|
|
consulTemplateWrapper = pkgs.writeShellScript "consul-template-wrapper" ''
|
|
# Only render the single merged template file
|
|
${pkgs.consul-template}/bin/consul-template \
|
|
-template "${consulAllHostsTemplate}:/etc/coredns/consul-all-hosts:${pkgs.systemd}/bin/systemctl reload coredns" \
|
|
-log-level info
|
|
'';
|
|
|
|
in {
|
|
# --- CoreDNS Configuration ---
|
|
environment.etc."coredns/Corefile".text = ''
|
|
# Forward Consul DNS queries to the local Consul Agent
|
|
consul:53 {
|
|
forward . 127.0.0.1:8600
|
|
cache 30
|
|
errors
|
|
log
|
|
}
|
|
|
|
# Handle custom domain
|
|
fbleagh.duckdns.org:53 {
|
|
# CRITICAL FIX: Use only one hosts file/plugin definition
|
|
hosts /etc/coredns/consul-all-hosts {
|
|
fallthrough
|
|
}
|
|
# Fallback to upstream DNS
|
|
forward . 192.168.4.1 8.8.8.8
|
|
cache 30
|
|
errors
|
|
log
|
|
}
|
|
|
|
# Handle all other DNS queries
|
|
.:53 {
|
|
forward . 192.168.4.1 8.8.8.8
|
|
cache 30
|
|
errors
|
|
log
|
|
}
|
|
'';
|
|
|
|
systemd.tmpfiles.rules = [
|
|
"f /etc/coredns/consul-all-hosts 0644 root root - #"
|
|
];
|
|
|
|
# --- Consul Template Service ---
|
|
systemd.services.consul-template = {
|
|
description = "Consul Template for CoreDNS Hosts";
|
|
wantedBy = ["multi-user.target"];
|
|
after = ["consul.service" "coredns.service" "network.target"];
|
|
requires = ["coredns.service"];
|
|
|
|
serviceConfig = {
|
|
# Use the robust wrapper script
|
|
ExecStart = "${consulTemplateWrapper}";
|
|
|
|
Restart = "always";
|
|
RestartSec = "10s";
|
|
};
|
|
};
|
|
|
|
# --- CoreDNS Service ---
|
|
systemd.services.coredns = {
|
|
description = "CoreDNS DNS server";
|
|
wantedBy = ["multi-user.target"];
|
|
requires = ["consul.service"];
|
|
after = ["network.target" "consul.service"];
|
|
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
ExecStart = "${pkgs.coredns}/bin/coredns -conf /etc/coredns/Corefile";
|
|
ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR1 $MAINPID";
|
|
Restart = "on-failure";
|
|
RestartSec = "5s";
|
|
DynamicUser = true;
|
|
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
|
|
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
|
|
NoNewPrivileges = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = true;
|
|
PrivateTmp = true;
|
|
ReadWritePaths = "/etc/coredns";
|
|
};
|
|
};
|
|
|
|
# --- Helper Scripts and Firewall ---
|
|
environment.systemPackages = [
|
|
pkgs.consul-template
|
|
(pkgs.writeShellScriptBin "debug-consul-template" ''
|
|
echo "Rendering template to stdout..."
|
|
${pkgs.consul-template}/bin/consul-template \
|
|
-template "${consulAllHostsTemplate}:-" \
|
|
-dry | grep -v "^$"
|
|
'') # <--- This is the crucial closing of the multi-line string
|
|
];
|
|
|
|
networking.firewall = {
|
|
allowedTCPPorts = [53];
|
|
allowedUDPPorts = [53];
|
|
};
|
|
}
|