openova/platform/network-policies
e3mrah 68c68eaf7a
feat(bp-network-policies): land default-deny CCNP + system-namespace + DNS allow templates (slice H8, #1095) (#1116)
New platform/network-policies/ Blueprint scaffold per design doc §3.9 row 8.
Ships the cluster-wide zero-trust primitives that EPIC-5 (#1100) activates
as part of the networking roll-out.

What ships:
- platform/network-policies/blueprint.yaml — bp-network-policies 1.0.0
- platform/network-policies/chart/Chart.yaml — Helm chart, no upstream sub-chart
- platform/network-policies/chart/values.yaml — gate (enabled: false default)
- platform/network-policies/chart/templates/default-deny.yaml — CCNP that
  denies all ingress + egress at endpointSelector: {} (full-cluster scope)
- platform/network-policies/chart/templates/allow-system-namespaces.yaml —
  CCNP allowing full traffic for kube-system, flux-system, cilium,
  cert-manager, catalyst, openova-system, monitoring, ingress (set is
  parametric via .Values.allowSystemNamespaces — operator extends per
  Sovereign for gitea/harbor/loki etc.)
- platform/network-policies/chart/templates/allow-egress-dns.yaml — CCNP
  permitting UDP/TCP/53 to CoreDNS from every Pod (without this the cluster
  is unbootable under default-deny — first DNS lookup fails)

Why a separate Blueprint, not bp-cilium:
- bp-cilium is foundational, installed on every cluster on day 0.
  Default-deny breaks every workload that hasn't been allowlisted, so it
  cannot ship in bp-cilium without operator opt-in semantics.
- Separate Blueprint with enabled: false default preserves the safety
  boundary. EPIC-5 wires the activation when the rest of the zero-trust
  story is ready.

Per-namespace intra-namespace allow is intentionally NOT in this slice:
- Cilium CCNPs cannot express "same namespace as the source Pod" without
  listing every namespace, which contradicts dynamic Org provisioning.
- That allow rule is rendered as a per-namespace CiliumNetworkPolicy (CNP,
  namespace-scoped) by organization-controller (slice C1 of #1095) at
  Organization creation time. README + values.yaml note this for
  downstream Implementers.

Per docs/INVIOLABLE-PRINCIPLES.md #4, every policy parameter
(allowSystemNamespaces list, dnsNamespace, dnsServiceName) is in
values.yaml, not hardcoded.

Validated:
- helm template with default values: 0 resources rendered (gate works)
- helm template with enabled=true: exactly 3 CCNPs rendered (default-deny,
  allow-system-namespaces, allow-egress-dns), all parse cleanly through
  python yaml.safe_load_all
- CCNP CRD validation will happen on Sovereigns where bp-cilium is
  installed; local k3s here uses flannel so server-side dry-run is
  unavailable

Refs: #1094, #1095, #1100, docs/EPICS-1-6-unified-design.md §3.9 row 8 +
§8 (EPIC-5), ADR-0001 §2 (zero-trust).

Co-authored-by: hatiyildiz <hatiyildiz@noreply.openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:40:30 +04:00
..
chart feat(bp-network-policies): land default-deny CCNP + system-namespace + DNS allow templates (slice H8, #1095) (#1116) 2026-05-08 22:40:30 +04:00
blueprint.yaml feat(bp-network-policies): land default-deny CCNP + system-namespace + DNS allow templates (slice H8, #1095) (#1116) 2026-05-08 22:40:30 +04:00
README.md feat(bp-network-policies): land default-deny CCNP + system-namespace + DNS allow templates (slice H8, #1095) (#1116) 2026-05-08 22:40:30 +04:00

bp-network-policies

Status: Phase-0 scaffold (#1095 slice H8). Activated by EPIC-5 (#1100). Updated: 2026-05-08

Default-deny CiliumClusterwideNetworkPolicy baseline + a small set of allow-templates that turn the cluster zero-trust by default while keeping the Catalyst control plane operational.

This Blueprint is not in the bootstrap-kit. Installing it on a running cluster will sever every flow it doesn't explicitly allow — operators must install deliberately, per-Sovereign, with the allow-list adjusted for their workloads. EPIC-5 ships the wiring that turns it on as part of the zero-trust roll-out.

What it ships

Template Effect
default-deny.yaml CiliumClusterwideNetworkPolicy 00-default-deny denies all ingress + egress at namespace selector level. Order 0 (highest priority for layer-1 catch-all).
allow-system-namespaces.yaml Allows full ingress/egress for the Catalyst control-plane namespaces (kube-system, flux-system, cilium, cert-manager, catalyst, openova-system, plus monitoring and ingress namespaces) so the platform itself stays up.
allow-egress-dns.yaml Allows egress to CoreDNS in kube-system from every namespace. Without this, every Pod fails on DNS lookup.

Pod-to-Pod within the SAME namespace is intentionally NOT handled here. Cilium CiliumClusterwideNetworkPolicy cannot express "same namespace as the source Pod" without enumerating every namespace explicitly — that's a per-tenant concern. The organization-controller (slice C1 of #1095) renders a per-namespace CiliumNetworkPolicy (CNP, namespace-scoped) at Organization creation time, with implicit same-namespace allow semantics.

Per-Application policies (allow app-Xapp-Y cross-namespace, allow Org acme egress to the public internet on port 443, etc.) are authored by the application-controller (slice C4 in #1095) at install time from Blueprint.spec.networking.egress declarations — they are not part of this Blueprint.

Activation contract

# values.yaml override (or per-Sovereign overlay)
enabled: true
allowSystemNamespaces:
  - kube-system
  - flux-system
  - cilium
  - cert-manager
  - catalyst
  - openova-system
  - monitoring
  - ingress

When enabled: false (the default), no policies render — installing this chart is a no-op until the operator opts in.

Verification

After installing with enabled: true:

# Two Pods in the same namespace — should reach each other
kubectl run -n acme test-a --image=busybox -- sleep 3600
kubectl run -n acme test-b --image=busybox -- sleep 3600
kubectl exec -n acme test-a -- wget -qO- test-b.acme.svc:80   # OK

# Two Pods in different namespaces — should NOT reach each other
kubectl run -n bank test-c --image=busybox -- sleep 3600
kubectl exec -n acme test-a -- wget -qO- test-c.bank.svc:80   # blocked

Cilium Hubble (turned on in EPIC-5) shows the deny events with the matching policy.

Why a separate Blueprint, not bp-cilium templates

bp-cilium is foundational infra installed on every cluster on day 0; default-deny breaks every workload that hasn't been allowlisted. Shipping the policy as a separate, opt-in Blueprint preserves the safety boundary: bp-cilium is always-on, bp-network-policies is operator-on after the allowlist is sized.

References

  • docs/EPICS-1-6-unified-design.md §3.9 row 8 + §8 (EPIC-5 Networking)
  • ADR-0001 §2 (zero-trust)
  • platform/cilium/README.md