Ablauf: Wie ein Paket durch die drei Tiers läuft
Der OVN-Kubernetes-Controller übersetzt Netzwerk-Policies in OVN-ACLs. Jedes Paket durchläuft die Tiers in fester Reihenfolge – und sobald ein Tier eine Entscheidung trifft, ist Schluss: Die restlichen Tiers werden übersprungen.
Die drei Tiers und ihre Reihenfolge
| Tier | Typ | Geltungsbereich | Wer definiert |
|---|---|---|---|
| 1 | ANP (AdminNetworkPolicy) | clusterweit, höchste Priorität | Cluster-Admin |
| 2 | NP (NetworkPolicy) | namespace-scoped | Namespace-Owner / Entwickler |
| 3 | BANP (BaselineAdminNetworkPolicy) | clusterweit, niedrigste Priorität | Cluster-Admin |
| – | Default Allow | Kubernetes-Standard, wenn nichts greift | niemand |
Der Pfad eines Pakets, wenn kein Tier vorzeitig entscheidet:
Tier 1: AdminNetworkPolicy (ANP)
Clusterweite Regeln mit der höchsten Priorität, definiert von Cluster-Admins und von Namespace-Ownern nicht überschreibbar. Jedes Paket wird zuerst gegen die ANP-Regeln geprüft.
Was in Tier 1 passieren kann
| Ergebnis | Aktion | Nächster Schritt |
|---|---|---|
| ALLOW | Paket wird durchgelassen | Tier 2 & 3 werden übersprungen |
| DENY | Paket wird verworfen (drop) | Tier 2 & 3 werden übersprungen |
| PASS | ANP trifft zu, delegiert die Entscheidung | weiter zu Tier 2 |
| NO MATCH | keine ANP-Regel greift | weiter zu Tier 2 |
PASS und NO MATCH landen beide in Tier 2 – sind aber nicht dasselbe: PASS ist eine aktive Delegation („diese Verbindung sollen die NetworkPolicies der Tenants entscheiden“), NO MATCH heißt schlicht, dass sich keine ANP für das Paket interessiert hat. Ein ANP-Allow dagegen ist absolut: NetworkPolicies werden dann komplett ignoriert – kein Tenant kann sich z. B. selbst vom Monitoring abschotten.
Die Auswertungsreihenfolge unter mehreren ANPs steuert spec.priority: Werte 0–99, maximal 100 ANPs pro Cluster, je niedriger der Wert, desto höher der Vorrang.
namespaces: {} selektiert alle Namespaces – auch openshift-*, kube-system und default. ANP/BANP auf System-Namespaces anzuwenden ist unsupported und kann den Cluster in einen nicht funktionsfähigen Zustand versetzen. Immer explizite Labels statt Catch-all.YAML: Grundgerüst einer ANP
Subject wählt die betroffenen Pods (über Namespaces bzw. Namespace+Pod-Selektoren), Ingress- und Egress-Regeln tragen jeweils Name, Action und Peers. Actions: Allow, Deny, Pass.
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: sample-anp-deny-pass-rules
spec:
priority: 50 # 0-99, niedriger = mehr Vorrang
subject:
namespaces:
matchLabels:
kubernetes.io/metadata.name: example.name
ingress:
- name: "deny-all-ingress-tenant-1"
action: "Deny"
from:
- pods:
namespaceSelector:
matchLabels:
custom-anp: tenant-1
podSelector:
matchLabels:
custom-anp: tenant-1
egress:
- name: "pass-all-egress-to-tenant-1"
action: "Pass"
to:
- pods:
namespaceSelector:
matchLabels:
custom-anp: tenant-1
podSelector:
matchLabels:
custom-anp: tenant-1
Die drei Actions als Monitoring-Trio (Allow / Deny / Pass)
Drei ANPs zeigen die Abstufung: block-monitoring (Priority 5) schützt restriktive Tenants absolut vor Scraping, pass-monitoring (Priority 7) lässt interne Tenants per NetworkPolicy selbst entscheiden, allow-monitoring (Priority 9) garantiert Monitoring für den Rest. Die kleinste Zahl gewinnt bei Überlappung.
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: block-monitoring
spec:
priority: 5
subject:
namespaces:
matchLabels:
security: restricted
ingress:
- name: "deny-ingress-from-monitoring"
action: "Deny"
from:
- namespaces:
matchLabels:
kubernetes.io/metadata.name: monitoring
---
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: pass-monitoring
spec:
priority: 7
subject:
namespaces:
matchLabels:
security: internal
ingress:
- name: "pass-ingress-from-monitoring"
action: "Pass"
from:
- namespaces:
matchLabels:
kubernetes.io/metadata.name: monitoring
---
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: allow-monitoring
spec:
priority: 9
subject:
namespaces: {} # Vorsicht: selektiert auch OpenShift-Namespaces
ingress:
- name: "allow-ingress-from-monitoring"
action: "Allow"
from:
- namespaces:
matchLabels:
kubernetes.io/metadata.name: monitoring
Tier 2: NetworkPolicy (NP)
Namespace-Ebene, Werkzeug der Entwickler und Namespace-Owner. Die Engine prüft, ob eine NP den Ziel-Pod per podSelector selektiert – erst dann wird überhaupt entschieden.
Was in Tier 2 passieren kann
| Ergebnis | Aktion | Nächster Schritt |
|---|---|---|
| NP selektiert Pod + Traffic matcht Allow-Regel | Paket wird durchgelassen | Tier 3 wird übersprungen |
| NP selektiert Pod + kein Rule-Match | Implicit Deny – Paket wird verworfen | Tier 3 wird übersprungen |
| Keine NP selektiert den Pod | keine Entscheidung | weiter zu Tier 3 |
Anders als ANPs kennen NetworkPolicies keine expliziten Deny-Regeln: Das Deny entsteht implizit durch die Selektion. Und anders als ANPs entscheidet Tier 2 auch dann final, wenn nichts erlaubt wurde – ein selektierter Pod ohne passende Allow-Regel kommt nie bei der BANP an.
YAML: NP, die gepassten Monitoring-Traffic erlaubt
Passt zum Pass-Beispiel aus Abschnitt 1: Der Tenant entscheidet per NP selbst, ob Monitoring ihn scrapen darf.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring
namespace: tenant-1
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
Tier 3: BaselineAdminNetworkPolicy (BANP)
Das Auffangnetz: BANPs greifen nur, wenn weder ANP noch NP entschieden haben. Sie setzen eine überschreibbare Grundlinie – Namespace-Owner können sie per NetworkPolicy gezielt aushebeln, denn Tier 2 kommt immer vor Tier 3.
Was in Tier 3 passieren kann
| Ergebnis | Aktion |
|---|---|
| ALLOW | Paket wird durchgelassen |
| DENY | Paket wird verworfen (drop) |
| NO MATCH | Default Allow (Kubernetes-Standard) – Paket wird zugelassen |
Zwei Eigenheiten gegenüber der ANP: Es gibt kein Pass (unter Tier 3 kommt nichts mehr, an das man delegieren könnte) und keine Priority – denn pro Cluster existiert genau eine BANP. Typischer Einsatz: Default-Deny für Intra-Cluster-Traffic in User-Namespaces, sodass Entwickler bekannten Traffic explizit per NetworkPolicy freigeben müssen.
default heißen – sie ist ein Cluster-Singleton. Und wie bei der ANP gilt: nur auf User-Namespaces scopen. System-Namespaces haben keine NetworkPolicies, die eine zu strenge BANP übersteuern könnten – ein Deny trifft sie dort ungebremst.YAML: BANP mit Deny-Grundlinie
Actions in BANP-Regeln: nur Allow und Deny. Dieses Beispiel verweigert Monitoring-Ingress für interne Tenants als Grundzustand – Abschnitt 4 zeigt, wie Tenants das per NP übersteuern.
apiVersion: policy.networking.k8s.io/v1alpha1
kind: BaselineAdminNetworkPolicy
metadata:
name: default # Pflichtname, Cluster-Singleton
spec:
subject:
namespaces:
matchLabels:
security: internal
ingress:
- name: "deny-ingress-from-monitoring"
action: "Deny"
from:
- namespaces:
matchLabels:
kubernetes.io/metadata.name: monitoring
Zusammenspiel: Pass-Kette und Egress-Peers
Die Stärke des Modells zeigt sich erst in Kombination: ANP-Pass delegiert an die Tenants, die BANP fängt alle auf, die nichts entschieden haben. Und Richtung Norden (raus aus dem Cluster) kommen nodes- und networks-Peers dazu.
Das Multi-Tenant-Pattern: Pass → NP → BANP-Deny
- ANP
pass-monitoring(Priority 7)Delegiert Monitoring-Ingress fürsecurity: internalaktiv an Tier 2 – der Admin diktiert nicht, er lässt wählen. - Tenant-NP entscheidetTenant 1 legt die
allow-monitoring-NP an und wird gescrapt. Tenant 2 legt nichts an – für ihn fällt die Entscheidung eine Etage tiefer. - BANP
defaultverweigertDie Deny-Grundlinie fängt Tenant 2 ab: kein Monitoring ohne explizite Freigabe. Opt-in statt Opt-out.
Ergebnis: Der Admin hat nie einzelne Tenants konfiguriert – er hat nur den Rahmen gesetzt, in dem Tenants selbst entscheiden.
Nordverkehr: nodes- und networks-Peers
Neben Ost-West-Traffic steuern ANP und BANP auch Traffic, der den Cluster verlässt oder zu Nodes geht – mit zwei zusätzlichen Peer-Typen, die es nur in Egress-Regeln gibt:
nodes-Peer – Egress zu Cluster-Nodes per Node-Selektor, z. B. zum Kubernetes-API-Server über die Control-Plane-Nodes; Regeln überstehen Node-Zu- und -Abgänge ohne Policy-Änderungnetworks-Peer – Egress zu externen Zielen per CIDR-Range, z. B. Intranet erlauben, bestimmte externe DNS-Server sperren
0.0.0.0/0 sperrt auch die Lebensadern: Ein pauschales Egress-Deny ins Internet trifft ohne Gegenmaßnahme auch Kubernetes-API und DNS. Vor dem Deny braucht es höher priorisierte Allow-Regeln für die essenziellen Ziele – sonst steht der Cluster, und die Policy sieht dabei völlig korrekt aus.YAML: Egress-Kontrolle mit nodes- und networks-Peers
ANP erlaubt API-Server (Port 6443 auf Control-Plane-Nodes) und Intranet, verbietet externe DNS-Server, passt den Rest – die BANP macht daraus ein Default-Deny Richtung Internet.
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: network-as-egress-peer
spec:
priority: 70
subject:
namespaces:
matchLabels:
tenant-tier: standard # explizite Labels statt {} verwenden
egress:
- name: "allow-to-kubernetes-api-server"
action: "Allow"
ports:
- portNumber:
protocol: TCP
port: 6443
to:
- nodes:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
- name: "deny-egress-to-external-dns-servers"
action: "Deny"
to:
- networks:
- 8.8.8.8/32
- 8.8.4.4/32
- 208.67.222.222/32
ports:
- portNumber:
protocol: UDP
port: 53
- name: "allow-all-egress-to-intranet"
action: "Allow"
to:
- networks:
- 89.246.180.0/22
- 60.45.72.0/22
- name: "pass-all-egress-to-internet"
action: "Pass"
to:
- networks:
- 0.0.0.0/0
---
apiVersion: policy.networking.k8s.io/v1alpha1
kind: BaselineAdminNetworkPolicy
metadata:
name: default
spec:
subject:
namespaces:
matchLabels:
tenant-tier: standard
egress:
- name: "deny-all-egress-to-internet"
action: "Deny"
to:
- networks:
- 0.0.0.0/0
Praxis: Verfügbarkeit und Best Practices
ANP und BANP stammen aus der sig-network-policy-api Working Group und liegen als policy.networking.k8s.io/v1alpha1 vor. In OpenShift: Tech Preview ab 4.14, GA ab 4.16 mit OVN-Kubernetes als CNI.
Prioritäten planen
- Mittleren Bereich nutzen (z. B. 30–70) und Lücken lassen – so passen später neue ANPs dazwischen, ohne alles neu zu nummerieren
- Gleiche Priority vermeiden: Bei überlappenden Regeln auf derselben Priority ist nicht garantiert, welche greift
- Selektoren nicht überlappen lassen – dieselben IPs in mehreren Policies kosten Performance und Skalierung
Regeln entwerfen
- Allow = Verbindung gilt immer, NetworkPolicies werden ignoriert; Pass = Entscheidung liegt bei den Tenants
- Explizite Labels statt
{}– der Catch-all-Selektor erwischt auch Infrastruktur-Namespaces namedPortsnicht mitportNumber/portRangemischen – erzeugt 6 ACLs pro Regel und macht den Cluster ineffizient- ANP hat kein Implicit Deny: Anders als bei der NP muss jedes Allow und Deny explizit formuliert werden
Debuggen: Status, Metriken, nbdb
Ob eine Policy wirklich verdrahtet wurde, steht nicht im Apply-Output, sondern im Status der CR – und im Zweifel direkt in der OVN Northbound-Datenbank (nbdb) auf dem Node.
Erst der Status, dann die Datenbank
Jeder Zone-Controller (pro Node) meldet im Status, ob das „OVN DB plumbing“ geklappt hat. Erwartet: SetupSucceeded pro Zone.
oc describe anp cluster-control
oc describe banp default
# gut: Reason: SetupSucceeded / Message: Setting up OVN DB plumbing was successful
# bös: Reason: SetupFailed / z. B. "OVNK only supports priority ranges 0-99"
oc apply nimmt auch eine ANP mit Priority 600 klaglos an – die CRD-Validierung lässt sie durch, aber der OVN-Controller meldet erst im Status SetupFailed, weil nur 0–99 unterstützt wird. Wer nach dem Apply nicht oc describe anp prüft, wundert sich über eine Policy, die nie gegriffen hat.ACLs, Address Sets und Port Groups in der nbdb ansehen
Für den Blick in die nbdb per Remote-Shell in den nbdb-Container des ovnkube-node-Pods auf dem betreffenden Node wechseln. In den ACL-Objekten steht die übersetzte Logik: action (allow-related, drop, pass), match und tier: 1 für ANP-ACLs.
oc get pods -n openshift-ovn-kubernetes -owide
oc rsh -c nbdb -n openshift-ovn-kubernetes ovnkube-node-524dt
# alle ACLs einer Policy (Typ: AdminNetworkPolicy oder BaselineAdminNetworkPolicy)
ovn-nbctl find ACL 'external_ids{>=}{"k8s.ovn.org/owner-type"=AdminNetworkPolicy,"k8s.ovn.org/name"=cluster-control}'
# eine einzelne Regel (gress-index = Position in ingress/egress, ab 0)
ovn-nbctl find ACL 'external_ids{>=}{"k8s.ovn.org/owner-type"=AdminNetworkPolicy,direction=Ingress,"k8s.ovn.org/name"=cluster-control,gress-index="1"}'
# zugehörige Address Sets (aufgelöste Peer-IPs) und Port Groups (Subject-Ports)
ovn-nbctl find Address_Set 'external_ids{>=}{"k8s.ovn.org/owner-type"=AdminNetworkPolicy,"k8s.ovn.org/name"=cluster-control}'
ovn-nbctl find Port_Group 'external_ids{>=}{"k8s.ovn.org/owner-type"=AdminNetworkPolicy,"k8s.ovn.org/name"=cluster-control}'
Metriken für ANP und BANP
ovnkube_controller_admin_network_policies– Anzahl ANPs im Clusterovnkube_controller_baseline_admin_network_policies– Anzahl BANPs; muss 0 oder 1 seinovnkube_controller_admin_network_policies_rules– Regeln je Direction (Ingress/Egress) und Action (Pass/Allow/Deny)ovnkube_controller_baseline_admin_network_policies_rules– dito für BANP (nur Allow/Deny)ovnkube_controller_admin_network_policies_db_objects– erzeugte nbdb-Objekte jetable_name(ACL, Address_Set)