Understanding OpenShift NetworkPolicies for Enhanced Security

In Red Hat OpenShift Container Platform (OCP), NetworkPolicies govern how pods are allowed to communicate with each other, with services in other namespaces, and with external network endpoints.

By default, OpenShift follows a non-isolated network model: all pods within a cluster can send and receive traffic from any other pod or service across all namespaces. NetworkPolicies allow you to implement a Zero-Trust network architecture by restricting ingress (incoming) and egress (outgoing) traffic.

1. Underlying Engine: OVN-Kubernetes

OpenShift uses OVN-Kubernetes (Open Virtual Network) as its default Container Network Interface (CNI).

When you apply a NetworkPolicy object, the OVN-Kubernetes controller translates your high-level declarative Kubernetes manifest into low-level OpenFlow rules directly on the Open vSwitch (br-int) bridges across every host node.

  • Default State: Allow all traffic.
  • Policy Active State: Once a NetworkPolicy selects a pod, that pod enters an implicit default-deny state for the traffic directions specified in the policy (Ingress, Egress, or both).
  • Evaluation Model: NetworkPolicies are additive (allow-lists). You cannot write explicit “deny” rules—traffic is denied unless an explicit rule allows it.

2. The Core NetworkPolicy Manifest Anatomy

A standard NetworkPolicy targets a set of pods using podSelector and defines rules based on three match types:

  1. podSelector: Matches pods within the same namespace.
  2. namespaceSelector: Matches pods inside other namespaces based on namespace labels.
  3. ipBlock: Matches CIDR IP ranges (for external or non-pod traffic).

YAML

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: my-app-prod
spec:
# 1. Target Pods: This policy applies to pods with the 'app: backend' label
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
- Egress
# 2. Ingress Rules: Allow traffic ON TO port 8080 ONLY IF...
ingress:
- from:
# ...it comes from pods labeled 'app: frontend' in the SAME namespace
- podSelector:
matchLabels:
app: frontend
# ...OR from pods inside namespaces labeled 'environment: prod'
- namespaceSelector:
matchLabels:
environment: prod
ports:
- protocol: TCP
port: 8080
# 3. Egress Rules: Allow backend pods to communicate OUT TO...
egress:
- to:
# ...a specific external database IP range
- ipBlock:
cidr: 10.0.100.0/24
ports:
- protocol: TCP
port: 5432

3. Essential Production NetworkPolicy Patterns

Pattern A: Global “Default Deny All” Ingress & Egress

Place this in every production namespace to enforce a Zero-Trust baseline. All traffic is blocked until explicit allow rules are created.

YAML

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: my-app-prod
spec:
podSelector: {} # Empty selector selects ALL pods in the namespace
policyTypes:
- Ingress
- Egress

Pattern B: Allow Traffic from OpenShift Ingress Routers

If you enforce a default-deny policy, external users won’t be able to reach your application via an OpenShift Route. You must explicitly allow ingress from the OpenShift router pods:

YAML

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-openshift-ingress
namespace: my-app-prod
spec:
podSelector:
matchLabels:
app: web-frontend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
network.openshift.io/policy-group: ingress

Pattern C: Allow CoreDNS Resolution for Egress

When egress is locked down via a default-deny policy, pods cannot resolve internal or external domain names because DNS requests to openshift-dns are blocked. You must allow UDP/TCP port 53:

YAML

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-access
namespace: my-app-prod
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53

4. OpenShift-Specific Extensions: AdminNetworkPolicy

Standard Kubernetes NetworkPolicy objects are namespaced—meaning cluster administrators cannot easily enforce global security rules across all namespaces without developers overriding them.

In newer OpenShift releases, OVN-Kubernetes supports the AdminNetworkPolicy (ANP) and BaselineAdminNetworkPolicy (BANP) APIs (from the Kubernetes Network Policy Working Group):

  • Cluster-Scoped: Defined at the cluster level by admins, not developers.
  • Precedence: Evaluated before namespaced NetworkPolicy objects.
  • Explicit Deny Rules: Unlike standard NetworkPolicies, AdminNetworkPolicy supports explicit Pass, Allow, and Deny actions.

Example Admin Policy to globally block developer pods from hitting host metadata endpoints:

YAML

apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: block-cloud-metadata
spec:
priority: 10
subject:
namespaces: {}
egress:
- action: Deny
to:
- ipBlock: 169.254.169.254/32 # AWS/GCP/Azure Metadata IP

5. Debugging NetworkPolicies

  1. Verify Applied Policies in a Namespace:
    Bashoc get networkpolicy -n <namespace>
  2. Check for Dropped Packets in OVN Trace:Use the ovs-appctl trace command on the host node (via oc debug node/<node-name>) to verify if OVN is dropping packets due to an ACL block:Bashovs-appctl ofproto/trace br-int in_port=<OVS_PORT>,tcp,nw_src=10.128.2.15,nw_dst=10.128.4.20,tp_dst=80

Leave a Reply