Skip to content

CoreDNS Split-Horizon DNS for bogocat.com

This document describes how CoreDNS is configured to forward *.bogocat.com queries to OPNsense, enabling split-horizon DNS for the unified hostname architecture.

Problem

Pods inside K8s need to reach services like auth.bogocat.com and portal.bogocat.com. Without configuration:

  1. K8s uses CoreDNS for DNS resolution
  2. CoreDNS forwards unknown domains to upstream DNS (Cloudflare/Google)
  3. External DNS returns the VPS IP (5.161.45.147)
  4. Pod traffic hairpins: Pod → VPS → WireGuard → K8s → Service

This is inefficient and can cause TLS/routing issues.

Solution

Configure CoreDNS to forward the bogocat.com zone to OPNsense (10.89.97.1), which has host overrides pointing *.bogocat.com to the K8s ingress IP (10.89.97.220).

Pod DNS query: auth.bogocat.com
CoreDNS (bogocat.com zone)
Forward to OPNsense (10.89.97.1)
Returns: 10.89.97.220 (K8s Ingress)
Pod connects directly to ingress (no hairpin)

Configuration

The CoreDNS ConfigMap in kube-system namespace includes a dedicated server block for bogocat.com:

bogocat.com:53 {
    errors
    cache 30
    forward . 10.89.97.1
}

.:53 {
    # ... default config ...
}

How to Apply

# Backup current config
kubectl get configmap coredns -n kube-system -o yaml > /tmp/coredns-backup.yaml

# Patch to add bogocat.com forwarding
kubectl patch configmap coredns -n kube-system --type='json' -p='[
  {"op": "replace", "path": "/data/Corefile", "value": "bogocat.com:53 {\n    errors\n    cache 30\n    forward . 10.89.97.1\n}\n\n.:53 {\n    errors\n    health\n    ready\n    kubernetes cluster.local in-addr.arpa ip6.arpa {\n      pods insecure\n      fallthrough in-addr.arpa ip6.arpa\n    }\n    hosts /etc/coredns/NodeHosts {\n      ttl 60\n      reload 15s\n      fallthrough\n    }\n    prometheus :9153\n    forward . /etc/resolv.conf\n    cache 30\n    loop\n    reload\n    loadbalance\n    import /etc/coredns/custom/*.override\n}\nimport /etc/coredns/custom/*.server"}
]'

# Restart CoreDNS
kubectl rollout restart deployment coredns -n kube-system

Verify

# Test from inside cluster
kubectl run dns-test --rm -it --restart=Never --image=busybox:latest -- nslookup auth.bogocat.com

# Expected output:
# Name:    auth.bogocat.com
# Address: 10.89.97.220

Adding New Subdomains

When adding a new *.bogocat.com service:

  1. Add host override in OPNsense (Services → Unbound DNS → Host Overrides)
  2. CoreDNS automatically picks it up (no K8s changes needed)

This is the key benefit - OPNsense remains the single source of truth for internal DNS.

Dependencies

  • OPNsense must be reachable from K8s nodes at 10.89.97.1
  • OPNsense Unbound DNS must have host overrides for *.bogocat.com

Troubleshooting

DNS not resolving inside pods

# Check CoreDNS logs
kubectl logs -n kube-system -l k8s-app=kube-dns

# Verify CoreDNS config
kubectl get configmap coredns -n kube-system -o jsonpath='{.data.Corefile}'

# Test from a pod
kubectl run dns-test --rm -it --restart=Never --image=busybox:latest -- nslookup portal.bogocat.com

OPNsense not responding

# Test from a K8s node
nslookup portal.bogocat.com 10.89.97.1

# Check OPNsense is listening on 53
nc -zv 10.89.97.1 53