From 205eb2704b66417af1389a89b2ef37969cb2aad2 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Mon, 16 Feb 2026 21:16:16 +0000 Subject: [PATCH] [ci skip] Fix Technitium DNS client IP logging: bypass Traefik L4 proxy DNS queries were going through Traefik's IngressRouteUDP, replacing real client IPs with Traefik pod IPs (10.10.169.150) in Technitium logs. Changed Technitium DNS service from NodePort to LoadBalancer with externalTrafficPolicy: Local, removed dns-udp entrypoint and IngressRouteUDP from Traefik, and updated CoreDNS to forward .lan queries to Technitium's LoadBalancer IP directly. --- modules/kubernetes/technitium/main.tf | 39 ++++++++++++-------- modules/kubernetes/traefik/main.tf | 52 +++++++++++---------------- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/modules/kubernetes/technitium/main.tf b/modules/kubernetes/technitium/main.tf index 804476c4..3e018170 100644 --- a/modules/kubernetes/technitium/main.tf +++ b/modules/kubernetes/technitium/main.tf @@ -19,7 +19,7 @@ module "tls_secret" { } # CoreDNS Corefile - manages cluster DNS resolution -# The viktorbarzin.lan block forwards to Technitium via NodePort. +# The viktorbarzin.lan block forwards to Technitium via LoadBalancer. # The cluster.local.viktorbarzin.lan block short-circuits junk queries caused by # ndots:5 search domain expansion (e.g. redis.redis.svc.cluster.local.viktorbarzin.lan) # which would otherwise flood Technitium with NxDomain queries. @@ -67,7 +67,7 @@ resource "kubernetes_config_map" "coredns" { viktorbarzin.lan:53 { #log errors - forward . 10.0.20.101:30053 # Technitium NodePort + forward . 10.0.20.204 # Technitium LoadBalancer cache { success 10000 300 6 denial 10000 300 60 @@ -109,8 +109,24 @@ resource "kubernetes_deployment" "technitium" { } } spec { - node_name = "k8s-node1" # Horrible hack but only way I found to preserve client ip - # if moved, update the corefile for coredns as that's forwarding queries for viktorbarzin.lan + # Prefer nodes running Traefik for network locality + affinity { + pod_affinity { + preferred_during_scheduling_ignored_during_execution { + weight = 100 + pod_affinity_term { + label_selector { + match_expressions { + key = "app.kubernetes.io/name" + operator = "In" + values = ["traefik"] + } + } + topology_key = "kubernetes.io/hostname" + } + } + } + } container { image = "technitium/dns-server:latest" name = "technitium" @@ -199,25 +215,18 @@ resource "kubernetes_service" "technitium-dns" { labels = { "app" = "technitium" } - annotations = { - "metallb.universe.tf/allow-shared-ip" : "shared" - } } spec { - # type = "LoadBalancer" - # external_traffic_policy = "Cluster" - type = "NodePort" + type = "LoadBalancer" port { - name = "technitium-dns" - port = 53 - node_port = 30053 - protocol = "UDP" + name = "technitium-dns" + port = 53 + protocol = "UDP" } external_traffic_policy = "Local" selector = { app = "technitium" - } } } diff --git a/modules/kubernetes/traefik/main.tf b/modules/kubernetes/traefik/main.tf index cb7c51c5..e7c30e79 100644 --- a/modules/kubernetes/traefik/main.tf +++ b/modules/kubernetes/traefik/main.tf @@ -29,6 +29,27 @@ resource "helm_release" "traefik" { "diun.enable" = "true" "diun.include_tags" = "^v\\d+(?:\\.\\d+)?(?:\\.\\d+)?.*$" } + initContainers = [{ + name = "download-plugins" + image = "alpine:3" + command = ["sh", "-c", join("", [ + "set -e; ", + "STORAGE=/plugins-storage; ", + "mkdir -p \"$STORAGE/archives/github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin\"; ", + "mkdir -p \"$STORAGE/archives/github.com/packruler/rewrite-body\"; ", + "wget -q -T 30 -O \"$STORAGE/archives/github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/v1.4.2.zip\" ", + "\"https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/archive/refs/tags/v1.4.2.zip\"; ", + "wget -q -T 30 -O \"$STORAGE/archives/github.com/packruler/rewrite-body/v1.2.0.zip\" ", + "\"https://github.com/packruler/rewrite-body/archive/refs/tags/v1.2.0.zip\"; ", + "printf '{\"github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin\":\"v1.4.2\",\"github.com/packruler/rewrite-body\":\"v1.2.0\"}' ", + "> \"$STORAGE/archives/state.json\"; ", + "echo \"Plugins pre-downloaded successfully\"", + ])] + volumeMounts = [{ + name = "plugins" + mountPath = "/plugins-storage" + }] + }] } updateStrategy = { @@ -91,12 +112,6 @@ resource "helm_release" "traefik" { advertisedPort = 443 } } - dns-udp = { - port = 5353 - exposedPort = 53 - protocol = "UDP" - expose = { default = true } - } whisper-tcp = { port = 10300 exposedPort = 10300 @@ -120,7 +135,6 @@ resource "helm_release" "traefik" { service = { type = "LoadBalancer" annotations = { - # Temporary IP during migration; will move to nginx's 10.0.20.202 once nginx is removed "metallb.universe.tf/loadBalancerIPs" = "10.0.20.202" } spec = { @@ -189,30 +203,6 @@ resource "helm_release" "traefik" { })] } -# DNS UDP passthrough to Technitium -resource "kubernetes_manifest" "dns_udp_ingressroute" { - manifest = { - apiVersion = "traefik.io/v1alpha1" - kind = "IngressRouteUDP" - metadata = { - name = "dns-udp" - namespace = kubernetes_namespace.traefik.metadata[0].name - } - spec = { - entryPoints = ["dns-udp"] - routes = [{ - services = [{ - name = "technitium-dns" - namespace = "technitium" - port = 53 - }] - }] - } - } - - depends_on = [helm_release.traefik] -} - # Dashboard resources module "tls_secret" { source = "../setup_tls_secret"