Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
69 lines
3.1 KiB
YAML
69 lines
3.1 KiB
YAML
# =============================================================================
|
|
# L3 FAULT-INJECTION SCAFFOLD — Default-deny fail-closed (R-NET-01, R-NET-02)
|
|
# *SAFETY-CRITICAL*
|
|
# Catalog/spec: docs/14 R-TEST-05 lists default-deny among the behaviors that MUST
|
|
# be proven by fault-injection (not happy-path). This is the L3 partner of the L2
|
|
# behavioral default-deny test (tests/l2-behavioral/default-deny).
|
|
#
|
|
# GIVEN a source that CAN reach a dest only because of an explicit allow rule,
|
|
# WHEN the allow rule is REVOKED (fault injection: delete the CiliumNetworkPolicy),
|
|
# THEN connectivity drops to fail-closed within a bounded window (revocation takes
|
|
# effect immediately — the baseline denies once the allow is gone), while DNS
|
|
# still resolves.
|
|
#
|
|
# This proves the deny is enforced by the live datapath, not merely declared, and
|
|
# that removing access fails closed rather than lingering open.
|
|
#
|
|
# STATUS: scaffold — needs T-2.2 (baseline) + T-2.3 (rendered allow) + T-3.0 harness.
|
|
# =============================================================================
|
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
|
kind: Test
|
|
metadata:
|
|
name: default-deny-failclosed
|
|
labels:
|
|
conformance.home.k3s/R-NET-01: "true"
|
|
conformance.home.k3s/R-NET-02: "true"
|
|
annotations:
|
|
conformance.home.k3s/requirements: "R-NET-01, R-NET-02"
|
|
conformance.home.k3s/layer: "L3"
|
|
conformance.home.k3s/safety-critical: "true"
|
|
conformance.home.k3s/intent: >-
|
|
Revoking an allow rule drops connectivity to fail-closed immediately; DNS
|
|
still works — the datapath enforces default-deny, not just declares it.
|
|
spec:
|
|
steps:
|
|
- name: given-source-allowed-to-dest
|
|
try:
|
|
- apply:
|
|
file: fixtures/allowed-pair.yaml # TODO(T-2.3): source+dest+allow policy
|
|
- script:
|
|
content: |
|
|
set -euo pipefail
|
|
kubectl -n "$NAMESPACE" exec source -- nc -z -w 3 dest 80 && echo ALLOWED_OK
|
|
check: { ($stdout =~ 'ALLOWED_OK'): true }
|
|
- name: when-revoke-allow-then-fail-closed
|
|
try:
|
|
# FAULT INJECTION: delete the allow policy; baseline default-deny remains.
|
|
- script:
|
|
content: |
|
|
set -euo pipefail
|
|
echo "TODO(T-3.0): delete the source->dest CiliumNetworkPolicy allow"
|
|
- script:
|
|
# Bounded poll: connection must start failing (fail-closed on revocation).
|
|
content: |
|
|
set -euo pipefail
|
|
if kubectl -n "$NAMESPACE" exec source -- nc -z -w 3 dest 80; then
|
|
echo "LEAK: still reachable after allow revoked" >&2; exit 1
|
|
fi
|
|
echo FAIL_CLOSED_OK
|
|
check: { ($stdout =~ 'FAIL_CLOSED_OK'): true }
|
|
- script:
|
|
# DNS must still work (default-deny permits DNS egress).
|
|
content: |
|
|
set -euo pipefail
|
|
kubectl -n "$NAMESPACE" exec source -- nslookup kubernetes.default && echo DNS_OK
|
|
check: { ($stdout =~ 'DNS_OK'): true }
|
|
finally:
|
|
- script:
|
|
content: 'echo "cleanup via chainsaw namespace teardown"'
|