89 lines
4.3 KiB
YAML
89 lines
4.3 KiB
YAML
# =============================================================================
|
|
# 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
|
|
# <svc>.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 Cilium L2 `shared` gateway pool 192.168.1.53-.60) — 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 <svc>.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 (192.168.1.53-.60), 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
|
|
# (Cilium L2 `shared` pool 192.168.1.53-.60), proving pods hairpin through the Gateway.
|
|
out="$(nslookup "$host" 2>/dev/null)"
|
|
echo "$out"
|
|
ip="$(echo "$out" | awk '/^Address: /{print $2}' | grep -E '^192\.168\.1\.(5[3-9]|60)$' | 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 (192.168.1.53-.60);"
|
|
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
|