Files
home-network-k3s-impl/conformance/tests/l2-behavioral/default-deny/chainsaw-test.yaml
T

99 lines
4.2 KiB
YAML

# =============================================================================
# L2 BEHAVIORAL SCAFFOLD — Default-deny east-west (R-NET-01)
# Catalog: docs/14-testing-and-conformance.md "Default-deny (R-NET-01)"
# Spec: docs/03-networking-isolation-and-egress.md "Default-deny baseline"
#
# EXEMPLAR: this file is the reference for the tagging convention and step
# style. Other scaffolds follow the same shape (see tests/README.md).
#
# GIVEN a fresh workload in a namespace with no allow rules,
# WHEN it attempts any in-cluster connection except DNS,
# THEN the connection FAILS (fail-closed); DNS still succeeds.
#
# This asserts observable BEHAVIOR (a probe cannot connect), not the mere
# existence of a NetworkPolicy object (R-TEST-01). Safety-relevant: the
# fail-closed direction is also exercised under fault-injection at L3
# (kill-switch / drift), but the baseline deny is a behavioral must-pass.
#
# STATUS: scaffold — cannot run until Phase 2 delivers the default-deny
# baseline (T-2.2). Chainsaw auto-creates/cleans the namespace (hermetic).
# TODOs mark fixtures that land as later phases deliver.
# =============================================================================
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: default-deny
labels:
# --- requirement tags (authoritative; one label per verified R-* ID) ---
conformance.home.k3s/R-NET-01: "true"
annotations:
conformance.home.k3s/requirements: "R-NET-01"
conformance.home.k3s/layer: "L2"
conformance.home.k3s/safety-critical: "false"
conformance.home.k3s/intent: >-
Given a bare workload with no allow rules, only DNS egress succeeds;
every other in-cluster connection is denied.
spec:
steps:
# -- GIVEN: a fresh, unprivileged probe workload with zero allow rules. The
# per-test namespace inherits the platform default-deny baseline (T-2.2).
- name: given-bare-probe-workload
try:
- apply:
# TODO(T-2.2): once the namespaced default-deny CiliumNetworkPolicy
# baseline exists, assert it is present AND that the probe below is
# actually blocked (existence != enforcement, R-TEST-01).
resource:
apiVersion: v1
kind: Pod
metadata:
name: probe
labels: { app: conformance-probe }
spec:
restartPolicy: Never
containers:
- name: probe
image: ghcr.io/kyverno/kyvernopre:latest # TODO: pin a curl/nc probe image
command: ["sleep", "3600"]
- assert:
resource:
apiVersion: v1
kind: Pod
metadata: { name: probe }
status: { phase: Running }
# -- THEN(DNS allowed): DNS egress MUST succeed even under default-deny.
- name: then-dns-succeeds
try:
- script:
# TODO(T-2.2): resolve an in-cluster name via kube-dns; expect rc=0.
content: |
set -euo pipefail
kubectl -n "$NAMESPACE" exec probe -- \
sh -c 'nslookup kubernetes.default.svc.cluster.local' && echo DNS_OK
check:
# bounded, deterministic: no sleeps; chainsaw retries within timeout.
($stdout =~ 'DNS_OK'): true
# -- THEN(everything else denied): a non-DNS in-cluster connection MUST fail.
- name: then-nondns-denied
try:
- script:
# TODO(T-2.2 / T-2.6): target an in-cluster service (e.g. Plex/Gateway)
# on a real port; expect the connection to FAIL closed (non-zero / timeout).
content: |
set -euo pipefail
if kubectl -n "$NAMESPACE" exec probe -- \
sh -c 'nc -z -w 3 <in-cluster-service> 80'; then
echo "LEAK: connection succeeded under default-deny" >&2
exit 1
fi
echo DENIED_OK
check:
($stdout =~ 'DENIED_OK'): true
# -- finally: chainsaw deletes the namespace + probe automatically; this block
# is the explicit hook for any out-of-namespace fixtures (none here).
finally:
- script:
content: 'echo "cleanup handled by chainsaw namespace teardown"'