Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# These verbs also let a tenant change any namespaced CiliumNetworkPolicy, and
# Cilium combines matching allow rules, so RBAC alone does not make the
# namespace boundary hold. Admission does: the
# `restrict-tenant-network-policies` ClusterPolicy requires every tenant ingress
# `restrict-tenant-network-policies` ValidatingPolicy requires every tenant ingress
# source and egress destination to carry a real constraint, refuses the broad
# `all`/`world`/`cluster` entities and the world-equivalent CIDRs, and reserves
# the generated `default-deny` and `allow-dns` names — so these verbs stay
Expand Down
2 changes: 1 addition & 1 deletion scripts/tests/tenant-webapp-admission/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func evaluate(f fixture, policies map[string]*policiesv1beta1.ValidatingPolicy)
if target == nil {
target = f.OldObject
}
resources := map[string]string{"WebApp": "webapps", "Deployment": "deployments", "Service": "services", "HTTPRoute": "httproutes", "ExternalSecret": "externalsecrets", "SecretStore": "secretstores", "PushSecret": "pushsecrets", "ConfigMap": "configmaps", "Team": "teams", "TeamRepository": "teamrepositories", "TeamMembership": "teammemberships"}
resources := map[string]string{"CiliumNetworkPolicy": "ciliumnetworkpolicies", "WebApp": "webapps", "Deployment": "deployments", "Service": "services", "HTTPRoute": "httproutes", "ExternalSecret": "externalsecrets", "SecretStore": "secretstores", "PushSecret": "pushsecrets", "ConfigMap": "configmaps", "Team": "teams", "TeamRepository": "teamrepositories", "TeamMembership": "teammemberships"}
gvk := target.GroupVersionKind()
resource, ok := resources[gvk.Kind]
if !ok || gvk.Version == "" {
Expand Down
343 changes: 238 additions & 105 deletions scripts/tests/test-restrict-tenant-network-policies.sh

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions scripts/tests/test-tenant-controller-namespace-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"
work="$(mktemp -d)"
trap 'rm -rf -- "$work"' EXIT
failures=0
while IFS=$'\t' read -r family passed denied; do
while IFS=$'\t' read -r family passed denied skipped; do
for owner in ksail kro; do
OWNER="$owner" yq '(.namespaceSelector[] | select(.labels."app.kubernetes.io/managed-by" == "ksail") | .labels."app.kubernetes.io/managed-by") = strenv(OWNER)' \
"$root/tests/$family/values.yaml" >"$work/values.yaml"
Expand All @@ -15,18 +15,18 @@ while IFS=$'\t' read -r family passed denied; do
fi
status=0
kyverno apply "$root/k8s/bases/infrastructure/cluster-policies/best-practices/$family.yaml" "${args[@]}" >"$work/output" 2>&1 || status=$?
expected="pass: $passed, fail: $denied, warn: 0, error: 0, skip: 0"
expected="pass: $passed, fail: $denied, warn: 0, error: 0, skip: $skipped"
if [[ "$status" != 1 ]] || ! grep -Fq "$expected" "$work/output"; then
printf 'FAIL: %s owner=%s expected %s (exit 1), got exit %s\n' "$family" "$owner" "$expected" "$status" >&2
tail -n 3 "$work/output" >&2
failures=$((failures + 1))
fi
done
done <<'CASES'
restrict-tenant-secret-stores 5 7
restrict-tenant-issuer-refs 4 3
restrict-tenant-route-hostnames 3 13
restrict-tenant-network-policies 309 78
restrict-tenant-secret-stores 5 7 0
restrict-tenant-issuer-refs 4 3 0
restrict-tenant-route-hostnames 3 13 0
restrict-tenant-network-policies 18 80 1
CASES
[[ "$failures" == 0 ]] || exit 1
echo 'PASS: all four tenant admission families evaluate their full controls under ksail and kro ownership'
44 changes: 23 additions & 21 deletions scripts/tests/test-validate-kyverno-fixture-evaluation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,48 +85,50 @@ else
fi

# #3145: kubectl's shorthand kind makes every rule match nothing.
root="$(copy shorthand-kinds restrict-tenant-network-policies)"
sed -i.bak -E 's#- CiliumNetworkPolicy$#- CiliumNetworkPolicy.cilium.io#' \
"${root}/${policies}/restrict-tenant-network-policies.yaml"
root="$(copy shorthand-kinds restrict-arc-retirement-credential-sync-rewritten)"
sed -i.bak -E 's#kinds: \[external-secrets\.io/v1/ExternalSecret\]#kinds: [ExternalSecret.external-secrets.io]#' \
"${root}/${policies}/restrict-arc-retirement.yaml"
grep -qF 'kinds: [ExternalSecret.external-secrets.io]' "${root}/${policies}/restrict-arc-retirement.yaml" ||
fail "shorthand kinds: the edit no longer applies to restrict-arc-retirement.yaml"
if kyverno_passes "shorthand kinds" "${root}"; then
expect_fail "shorthand kinds" "${root}" 1 "declares result: fail (kyverno reported it Excluded)"
fi

# #3152: a deleted rule leaves its rows Excluded.
root="$(copy deleted-rule restrict-tenant-network-policies)"
yq -i 'del(.spec.rules[] | select(.name == "cnp-ingress-sources-must-be-constrained"))' \
"${root}/${policies}/restrict-tenant-network-policies.yaml"
root="$(copy deleted-rule restrict-arc-retirement-listener-pod)"
yq -i 'del(.spec.rules[] | select(.name == "fence-retired-listener-pod"))' \
"${root}/${policies}/restrict-arc-retirement.yaml"
if kyverno_passes "deleted rule" "${root}"; then
expect_fail "deleted rule" "${root}" 1 "names rule cnp-ingress-sources-must-be-constrained of policy restrict-tenant-network-policies, which the policies it loads do not define"
expect_fail "deleted rule" "${root}" 1 "names rule fence-retired-listener-pod of policy restrict-arc-retirement, which the policies it loads do not define"
fi

# #3152: a renamed rule is the same break under another name.
root="$(copy renamed-rule restrict-tenant-network-policies)"
yq -i '(.spec.rules[] | select(.name == "cnp-ingress-sources-must-be-constrained") | .name) = "cnp-ingress-sources"' \
"${root}/${policies}/restrict-tenant-network-policies.yaml"
root="$(copy renamed-rule restrict-arc-retirement-listener-pod)"
yq -i '(.spec.rules[] | select(.name == "fence-retired-listener-pod") | .name) = "fence-retired-listener"' \
"${root}/${policies}/restrict-arc-retirement.yaml"
if kyverno_passes "renamed rule" "${root}"; then
expect_fail "renamed rule" "${root}" 1 "names rule cnp-ingress-sources-must-be-constrained"
expect_fail "renamed rule" "${root}" 1 "names rule fence-retired-listener-pod"
fi

# A rule named only by `skip` rows passes the Excluded check, so only the
# existence check can catch its removal.
root="$(copy skip-only restrict-tenant-network-policies)"
root="$(copy skip-only restrict-arc-retirement-listener-pod)"
mkdir -p "${root}/skip-only"
mv "${root}/tests/restrict-tenant-network-policies" "${root}/skip-only/"
yq -i '.results |= map(select(.result == "skip"))' "${root}/skip-only/restrict-tenant-network-policies/kyverno-test.yaml"
mv "${root}/tests/restrict-arc-retirement-listener-pod" "${root}/skip-only/"
yq -i '.results |= map(select(.result == "skip"))' "${root}/skip-only/restrict-arc-retirement-listener-pod/kyverno-test.yaml"
expect_pass "a skip-only fixture whose rule exists" "${root}" skip-only
yq -i 'del(.spec.rules[] | select(.name == "cnp-ingress-sources-must-be-constrained"))' \
"${root}/${policies}/restrict-tenant-network-policies.yaml"
yq -i 'del(.spec.rules[] | select(.name == "fence-retired-listener-pod"))' \
"${root}/${policies}/restrict-arc-retirement.yaml"
if kyverno_passes "skip-only rule removed" "${root}" skip-only; then
expect_fail "skip-only rule removed" "${root}" 1 "names rule cnp-ingress-sources-must-be-constrained" skip-only
expect_fail "skip-only rule removed" "${root}" 1 "names rule fence-retired-listener-pod" skip-only
fi

# #3392: a results entry naming a resource the test never loads gets no row at all.
root="$(copy renamed-resource restrict-tenant-network-policies)"
yq -i '(.results[].resources[] | select(. == "tenant-ns/attack-toservices-foreign-named")) = "tenant-ns/attack-toservices-foreign-renamed"' \
"${root}/tests/restrict-tenant-network-policies/kyverno-test.yaml"
root="$(copy renamed-resource restrict-arc-retirement-listener-pod)"
yq -i '(.results[].resources[] | select(. == "arc-systems/listener-restored")) = "arc-systems/listener-renamed"' \
"${root}/tests/restrict-arc-retirement-listener-pod/kyverno-test.yaml"
if kyverno_passes "renamed resource" "${root}"; then
expect_fail "renamed resource" "${root}" 1 "tenant-ns/attack-toservices-foreign-renamed, but kyverno ran no assertion for it"
expect_fail "renamed resource" "${root}" 1 "arc-systems/listener-renamed, but kyverno ran no assertion for it"
fi

# A generate row names the object it generates, which need not share its trigger's name.
Expand Down
8 changes: 2 additions & 6 deletions tests/policy-failure-actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@
"restrict-homepage-service-groups": "Enforce",
"require-homepage-href-for-non-root-routes": "Enforce",
"restrict-tenant-issuer-refs": "Enforce",
"restrict-tenant-network-policies/cnp-ingress-sources-must-be-constrained": "Enforce",
"restrict-tenant-network-policies/cnp-egress-destinations-must-be-constrained": "Enforce",
"restrict-tenant-network-policies/cnp-must-not-opt-out-of-default-deny": "Enforce",
"restrict-tenant-network-policies/cnp-generated-policy-names-are-reserved": "Enforce",
"restrict-tenant-network-policies/cnp-must-use-the-singular-spec-container": "Enforce",
"restrict-tenant-route-hostnames": "Enforce",
"restrict-tenant-secret-stores": "Enforce",
"restrict-tenant-webapps": "Enforce",
Expand All @@ -38,5 +33,6 @@
"restrict-arc-retirement/preserve-retirement-journal": "Enforce",
"restrict-arc-retirement/preserve-retiring-namespace": "Enforce",
"restrict-arc-openbao-listener-settings": "Enforce",
"restrict-github-team-external-identity": "Enforce"
"restrict-github-team-external-identity": "Enforce",
"restrict-tenant-network-policies": "Enforce"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
---
# One row per resource: fail when any check refuses it. Which check refuses it is
# in per-check.yaml, which scripts/tests/test-restrict-tenant-network-policies.sh
# runs. The policy reads namespace labels through namespaceObject in matchConditions,
# so the CLI needs the namespace labels declared explicitly.
apiVersion: cli.kyverno.io/v1alpha1
kind: Test
metadata:
Expand All @@ -11,15 +15,9 @@ resources:
variables: values.yaml
userinfo: user-info.yaml
results:
# The background controller creates and re-synchronises the generated floor.
# Both objects carry a reserved name, so without this carve-out the policy
# would refuse the very default-deny it exists to protect. The sibling shell
# test proves the same two bodies ARE denied under the tenant identity, so
# these skips cannot be a namespace-label mismatch in disguise.
- policy: restrict-tenant-network-policies
rule: cnp-generated-policy-names-are-reserved
resources:
- tenant-ns/default-deny
- tenant-ns/allow-dns
kind: CiliumNetworkPolicy
result: skip
resources:
- tenant-ns/allow-dns
- tenant-ns/default-deny
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
apiVersion: cli.kyverno.io/v1alpha1
kind: Test
metadata:
name: restrict-tenant-network-policies-kyverno-author
policies:
- >-
../../../k8s/bases/infrastructure/cluster-policies/best-practices/restrict-tenant-network-policies.yaml
resources:
- resources.yaml
variables: values.yaml
userinfo: user-info.yaml
results:
# The background controller creates and re-synchronises the generated floor.
# Both objects carry a reserved name, so without this carve-out the policy
# would refuse the very default-deny it exists to protect. The sibling shell
# test proves the same two bodies ARE denied under the tenant identity, so
# these skips cannot be a namespace-label mismatch in disguise.
- policy: restrict-tenant-network-policies
rule: cnp-generated-policy-names-are-reserved
resources:
- tenant-ns/default-deny
- tenant-ns/allow-dns
kind: CiliumNetworkPolicy
result: skip
Loading
Loading