68 lines
2.5 KiB
Python
68 lines
2.5 KiB
Python
|
|
"""Mechanical checks on deploy/networkpolicies.yaml.
|
||
|
|
|
||
|
|
The bounded-executor rule must stay pod-scoped. Splitting namespaceSelector
|
||
|
|
and podSelector into two `from` elements turns AND into OR and admits every
|
||
|
|
pod in sso (KeyCape, Authelia, LLDAP) or every bounded-executor pod in any
|
||
|
|
namespace. That is a one-character YAML change review can miss.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
yaml = pytest.importorskip("yaml")
|
||
|
|
|
||
|
|
POLICIES = Path(__file__).resolve().parents[1] / "deploy" / "networkpolicies.yaml"
|
||
|
|
|
||
|
|
|
||
|
|
def _policies() -> dict[str, dict]:
|
||
|
|
docs = [d for d in yaml.safe_load_all(POLICIES.read_text(encoding="utf-8")) if d]
|
||
|
|
return {d["metadata"]["name"]: d for d in docs}
|
||
|
|
|
||
|
|
|
||
|
|
def test_default_deny_remains():
|
||
|
|
spec = _policies()["approval-engine-default-deny"]["spec"]
|
||
|
|
assert spec["podSelector"] == {}
|
||
|
|
assert set(spec["policyTypes"]) == {"Ingress", "Egress"}
|
||
|
|
|
||
|
|
|
||
|
|
def test_bounded_executor_ingress_is_pod_scoped_to_sso_on_8080():
|
||
|
|
policy = _policies()["approval-engine-bounded-executor"]
|
||
|
|
assert policy["metadata"]["namespace"] == "approval-engine"
|
||
|
|
spec = policy["spec"]
|
||
|
|
assert spec["podSelector"] == {"matchLabels": {"app.kubernetes.io/name": "approval-engine"}}
|
||
|
|
assert spec["policyTypes"] == ["Ingress"]
|
||
|
|
assert len(spec["ingress"]) == 1
|
||
|
|
rule = spec["ingress"][0]
|
||
|
|
assert rule["from"] == [
|
||
|
|
{
|
||
|
|
"namespaceSelector": {"matchLabels": {"kubernetes.io/metadata.name": "sso"}},
|
||
|
|
"podSelector": {"matchLabels": {"app.kubernetes.io/name": "bounded-executor"}},
|
||
|
|
}
|
||
|
|
]
|
||
|
|
assert rule["ports"] == [{"protocol": "TCP", "port": 8080}]
|
||
|
|
|
||
|
|
|
||
|
|
def test_no_policy_admits_sso_namespace_wide():
|
||
|
|
for name, policy in _policies().items():
|
||
|
|
for rule in policy["spec"].get("ingress", []):
|
||
|
|
for peer in rule.get("from", []):
|
||
|
|
ns = peer.get("namespaceSelector", {}).get("matchLabels", {})
|
||
|
|
if ns.get("kubernetes.io/metadata.name") == "sso":
|
||
|
|
assert "podSelector" in peer, f"{name} admits all of sso"
|
||
|
|
|
||
|
|
|
||
|
|
def test_existing_callers_policy_is_unchanged():
|
||
|
|
rule = _policies()["approval-engine-callers"]["spec"]["ingress"]
|
||
|
|
assert rule == [
|
||
|
|
{
|
||
|
|
"from": [
|
||
|
|
{"namespaceSelector": {"matchLabels": {"kubernetes.io/metadata.name": "secrets-engine"}}},
|
||
|
|
{"namespaceSelector": {"matchLabels": {"railiance.io/approval-engine-client": "true"}}},
|
||
|
|
],
|
||
|
|
"ports": [{"protocol": "TCP", "port": 8080}],
|
||
|
|
}
|
||
|
|
]
|