# ============================================================================= # L2 BEHAVIORAL — split-horizon INTERNAL resolution (R-DNS-01 / R-DNS-03) [RUNNABLE] # Catalog: docs/14 "DNS/exposure (R-DNS-*)" # Spec: docs/09 "Split-horizon resolution (R-DNS-03)" — internal clients resolve # .home.keithjackson.dev to the INTERNAL Gateway VIP, not the public hairpin. # Impl: platform/coredns/coredns-custom.yaml (k3s CoreDNS `import *.server`; template plugin # answers the whole home.keithjackson.dev zone with ${GATEWAY_VIP}). # # GIVEN the split-horizon coredns-custom ConfigMap is reconciled into k3s CoreDNS, # WHEN an in-cluster pod resolves a platform hostname over its PUBLIC name # (keycloak.home.keithjackson.dev) using the default cluster resolver (CoreDNS 10.43.0.10), # THEN the answer is the in-cluster Gateway VIP (the L2-announced LB range 10.73.0.24x) — NOT a # public/off-cluster IP. This is what lets pod->public-hostname traffic hairpin through the # Gateway with the correct SNI (*.home.keithjackson.dev) so the wildcard cert validates # (R-DNS-01 "services reachable at .home..."; R-DNS-03 split-horizon). # # Complements dns-exposure (R-DNS-02, the EXTERNAL/public-record side). Together they cover the # split-horizon pair: external answer = public record (R-DNS-02); internal answer = Gateway VIP # (R-DNS-01/03). # # CLEANUP: chainsaw deletes the per-test namespace (Job included) at teardown. Read-only otherwise. # chainsaw v0.2.12: Job + status assert; no test-level finally. # ============================================================================= apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test metadata: name: dns-internal-resolution labels: conformance.home.k3s/R-DNS-01: "true" conformance.home.k3s/R-DNS-03: "true" annotations: conformance.home.k3s/requirements: "R-DNS-01,R-DNS-03" conformance.home.k3s/layer: "L2" conformance.home.k3s/safety-critical: "false" conformance.home.k3s/executable: "true" conformance.home.k3s/intent: >- An in-cluster pod resolving keycloak.home.keithjackson.dev via cluster DNS gets the internal Gateway VIP (10.73.0.24x), not the public hairpin — split-horizon in-cluster resolution. spec: timeouts: apply: 60s assert: 2m exec: 2m steps: - name: then-cluster-dns-answers-with-the-internal-gateway-vip try: - apply: resource: apiVersion: batch/v1 kind: Job metadata: name: dns-internal-probe spec: backoffLimit: 2 activeDeadlineSeconds: 100 template: spec: restartPolicy: Never containers: - name: probe image: busybox:1.36.1 command: - sh - -c - | set -u host="keycloak.home.keithjackson.dev" # Resolve via the DEFAULT cluster resolver (CoreDNS, /etc/resolv.conf -> # 10.43.0.10). Split-horizon must answer with the in-cluster Gateway VIP # (L2 pool 10.73.0.24x), proving pods hairpin through the Gateway. out="$(nslookup "$host" 2>/dev/null)" echo "$out" ip="$(echo "$out" | awk '/^Address: /{print $2}' | grep -E '^10\.73\.0\.24[0-9]$' | head -1)" if [ -n "$ip" ]; then echo "INTERNAL_RESOLUTION_OK $host -> $ip (in-cluster Gateway VIP)" exit 0 fi echo "FAIL: $host did not resolve to the in-cluster Gateway VIP (10.73.0.24x);" echo " split-horizon coredns-custom not in effect (got a public/off-cluster answer)." exit 1 - assert: resource: apiVersion: batch/v1 kind: Job metadata: name: dns-internal-probe status: succeeded: 1