Skip to main content

Command Palette

Search for a command to run...

Kubernetes NetworkPolicy Explained: Ingress, Egress, Default Deny, Selectors, and IP-Based Rules

Updated
21 min readView as Markdown
Kubernetes NetworkPolicy Explained: Ingress, Egress, Default Deny, Selectors, and IP-Based Rules
A

Devops | 3x AWS Certified | CKA

A practical guide to standard Kubernetes NetworkPolicy using only the Kubernetes NetworkPolicy API.

This article intentionally does not cover Cilium, Calico-specific policy features, or other extended policy engines. Those are separate topics.


Why NetworkPolicy feels confusing

NetworkPolicy looks straightforward:

kind: NetworkPolicy
spec:
  podSelector:
  policyTypes:
  ingress:
  egress:

But several concepts interact:

  • Is the Pod isolated for ingress?

  • Is it isolated for egress?

  • Does an empty rule mean allow everything or deny everything?

  • What happens when multiple policies select the same Pod?

  • Does from mean the source or destination?

  • Does to mean the source or destination?

  • Can I select a Pod?

  • Can I select a namespace?

  • Can I select an external IP?

  • What happens when I specify a port?

  • Can standard NetworkPolicy explicitly deny one IP/port?

  • What happens to return traffic?

The easiest way to understand all of this is to build the mental model first.


1. The two directions: Ingress and Egress

Think of every Pod as having two doors:

                         POD
                  ┌──────────────┐
                  │              │
       INGRESS ──>│              │<── EGRESS
                  │              │
                  └──────────────┘

Ingress

Ingress is traffic coming into the Pod.

frontend ───────────────> backend
                         INGRESS

From the backend's point of view, this is ingress traffic.

Egress

Egress is traffic leaving the Pod.

frontend ───────────────> backend
   EGRESS

From the frontend's point of view, this is egress traffic.

The same connection can therefore be:

frontend                         backend
   │                               │
   │ ─────── TCP connection ─────> │
   │                               │
 EGRESS                           INGRESS

This distinction is fundamental.


2. The default behavior: everything is open

If there is no NetworkPolicy selecting a Pod, the Pod is non-isolated.

In the normal Kubernetes NetworkPolicy model:

Ingress = allowed
Egress  = allowed

So without applicable policies:

Pod A ───────────────> Pod B       ✓

Pod B ───────────────> Pod A       ✓

Pod A ───────────────> Internet    ✓

NetworkPolicy is not a firewall that automatically blocks traffic just because the API object exists somewhere in the cluster.

The important question is:

Does a NetworkPolicy select this Pod for this direction?


3. A NetworkPolicy has a target: podSelector

Every NetworkPolicy has a podSelector.

Example:

spec:
  podSelector:
    matchLabels:
      app: backend

This means:

Apply this policy to Pods with the label app=backend in the policy's namespace.

For example:

metadata:
  labels:
    app: backend

matches:

Pod A: app=backend       ← selected
Pod B: app=frontend      ← not selected
Pod C: app=database      ← not selected

Empty podSelector

This:

podSelector: {}

means:

Select all Pods in the policy's namespace.

That is why default-deny policies commonly use:

podSelector: {}

4. policyTypes: which direction are we controlling?

policyTypes tells Kubernetes whether the policy applies to:

  • Ingress

  • Egress

  • or both

Example:

policyTypes:
- Ingress

means:

This policy isolates the selected Pods for incoming traffic.

Example:

policyTypes:
- Egress

means:

This policy isolates the selected Pods for outgoing traffic.

Example:

policyTypes:
- Ingress
- Egress

means:

Isolate the selected Pods in both directions.

A useful mental model is:

policyTypes
     │
     ├── Ingress → control incoming traffic
     │
     └── Egress  → control outgoing traffic

For clarity, it is a good practice to explicitly specify policyTypes, especially for an egress-only policy.


5. Standard NetworkPolicy is an ALLOW-list

This is the single most important concept.

Standard Kubernetes NetworkPolicy does not provide an explicit deny: rule.

You cannot write:

egress:
- deny:
  - ipBlock:
      cidr: 192.168.121.17/32

There is no standard deny field in the Kubernetes NetworkPolicy API.

Instead, NetworkPolicy answers:

What traffic should be allowed?

Everything else is implicitly denied once the Pod is isolated for that direction.

Think:

No policy selecting Pod
        ↓
     ALLOW ALL

Policy selects Pod for Egress
        ↓
     ALLOW only
     what matches rules

6. An Egress rule automatically creates egress isolation

This is a very common point of confusion.

Suppose there is no default-deny policy.

You create:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-database
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend

  policyTypes:
  - Egress

  egress:
  - to:
    - ipBlock:
        cidr: 192.168.121.17/32
    ports:
    - protocol: TCP
      port: 9999

You do not need another empty egress policy first.

The selected Pods become egress-isolated.

The result is:

backend Pod
    │
    ├──> 192.168.121.17:9999/TCP     ✓ ALLOW
    │
    ├──> 192.168.121.17:80           ✗ DENY
    │
    ├──> 8.8.8.8:443                 ✗ DENY
    │
    └──> another Pod                 ✗ DENY

Why?

Because the Pod is now egress-isolated and the policy only allows traffic matching its egress rule.


7. Compare that with having no Egress policy

Scenario A: no egress policy

Pod
 │
 ├──> 192.168.121.17:9999     ✓
 ├──> 192.168.121.17:80       ✓
 ├──> 8.8.8.8:443             ✓
 └──> anywhere else           ✓

Egress is open.

Scenario B: an Egress policy allows one destination

policyTypes:
- Egress

egress:
- to:
  - ipBlock:
      cidr: 192.168.121.17/32
  ports:
  - protocol: TCP
    port: 9999

Now:

192.168.121.17:9999     ✓
Everything else         ✗

This distinction is critical:

The existence of an applicable Egress policy changes the selected Pod from non-isolated to egress-isolated.


8. Default-deny Ingress

A classic default-deny ingress policy is:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Notice there is no ingress: rule.

This means:

All Pods in namespace
        │
        ↓
Ingress isolation enabled
        │
        ↓
No ingress rules
        │
        ↓
DENY ALL INGRESS

So:

frontend ───────X──────> backend
random   ───────X──────> backend
external ───────X──────> backend

The empty rule set is not "allow everything."

It means:

The selected Pods are isolated, and this policy allows no ingress traffic.


9. Default-deny Egress

Same concept:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress

Result:

All Pods
    │
    ↓
Egress isolation
    │
    ↓
No egress rules
    │
    ↓
DENY ALL EGRESS

So:

Pod ─────X────> Internet
Pod ─────X────> database
Pod ─────X────> another Pod

All are blocked unless another applicable NetworkPolicy allows them.

Important: DNS

A default-deny egress policy also blocks DNS traffic unless DNS is explicitly allowed by another applicable policy.

That is a common reason applications suddenly stop resolving service names after egress lockdown.


10. Default-deny both directions

You can isolate both directions with one policy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

No ingress rules.

No egress rules.

Therefore:

                  POD
                   │
          ┌────────┴────────┐
          │                 │
       INGRESS           EGRESS
          │                 │
        DENY              DENY

This is the strongest baseline:

DEFAULT DENY
      +
EXPLICIT ALLOW

11. ingress.from: Who can connect to me?

Suppose the backend has:

podSelector:
  matchLabels:
    app: backend

policyTypes:
- Ingress

ingress:
- from:
  - podSelector:
      matchLabels:
        app: frontend

Read this as:

Allow traffic from frontend Pods into backend Pods.

So:

frontend ─────────> backend
          ✓

but:

random-pod ───────> backend
          ✗

Remember:

INGRESS
   │
   └── from = SOURCE

12. egress.to: Where can I connect?

Now reverse the direction.

podSelector:
  matchLabels:
    app: frontend

policyTypes:
- Egress

egress:
- to:
  - podSelector:
      matchLabels:
        app: backend

Read this as:

Allow frontend Pods to connect to backend Pods.

So:

frontend ─────────> backend
          ✓

Remember:

EGRESS
   │
   └── to = DESTINATION

A simple memory trick:

Ingress  → from = who is coming TO me?
Egress   → to   = where am I going?

13. What can from and to target?

Standard Kubernetes NetworkPolicy provides three main peer selector mechanisms:

  1. podSelector

  2. namespaceSelector

  3. ipBlock

These can be used under:

ingress:
- from:

and:

egress:
- to:

Let's look at each.


14. Target type #1: podSelector

Example:

ingress:
- from:
  - podSelector:
      matchLabels:
        app: frontend

This selects Pods with:

app=frontend

in the same namespace as the NetworkPolicy when podSelector is used by itself.

Example:

Namespace: default

frontend Pod
  app=frontend

backend Pod
  app=backend

Policy attached to backend:

frontend ─────────> backend
          ✓

A frontend Pod in another namespace is not selected by this standalone podSelector.


15. Target type #2: namespaceSelector

You can select namespaces by their labels.

Example:

ingress:
- from:
  - namespaceSelector:
      matchLabels:
        team: platform

Read this as:

Allow traffic from Pods in namespaces labeled team=platform.

This can allow Pods from multiple namespaces.

Think:

namespace-a   team=platform
namespace-b   team=platform
namespace-c   team=payments

Then:

namespace-a Pods ──┐
                   ├──> backend ✓
namespace-b Pods ──┘

namespace-c Pods ─────> backend ✗

16. Target type #3: ipBlock

ipBlock lets you select an IP range using CIDR.

Example:

egress:
- to:
  - ipBlock:
      cidr: 192.168.121.17/32

/32 represents exactly one IPv4 address:

192.168.121.17

You can also specify a range:

ipBlock:
  cidr: 192.168.121.0/24

which represents the CIDR range.

You can exclude a smaller CIDR from the range:

ipBlock:
  cidr: 192.168.121.0/24
  except:
  - 192.168.121.17/32

Conceptually:

192.168.121.0/24
        │
        ├── most addresses   ✓
        │
        └── .17              ✗ excluded

Important limitation

ipBlock.except excludes an IP/CIDR range. It is not a port-specific deny mechanism.

So it can express:

ALLOW 192.168.121.0/24
EXCEPT 192.168.121.17

but standard NetworkPolicy cannot express:

ALLOW 192.168.121.17:80
DENY  192.168.121.17:9999
ALLOW 192.168.121.17:443

using an explicit deny rule.


17. Can ipBlock target external IPs?

Yes. ipBlock is intended for IP/CIDR-based policy, including traffic between Pods and the outside world.

For example:

egress:
- to:
  - ipBlock:
      cidr: 8.8.8.8/32

can express an allow rule for traffic to that IP.

But there is an important Kubernetes caveat:

The exact source/destination IP seen by NetworkPolicy can depend on address rewriting performed by the network implementation, cloud provider, Services, and other networking components.

For example, traffic involving a Service or load balancer may undergo source/destination NAT, so the IP you expect may not be the IP the NetworkPolicy implementation evaluates.

This is one reason ipBlock behavior should be tested in the actual cluster/network implementation.


18. podSelector + namespaceSelector: the AND case

You can combine them in the same peer entry:

ingress:
- from:
  - namespaceSelector:
      matchLabels:
        team: platform
    podSelector:
      matchLabels:
        app: frontend

This means:

Allow Pods labeled app=frontend AND located in namespaces labeled team=platform.

Conceptually:

namespace must match
        AND
Pod must match

Example:

namespace-a
team=platform
  └── frontend
       ✓

namespace-b
team=payments
  └── frontend
       ✗

namespace-c
team=platform
  └── database
       ✗

19. A very common YAML mistake: AND vs OR

Compare these two.

Case A: same peer entry

from:
- namespaceSelector:
    matchLabels:
      team: platform
  podSelector:
    matchLabels:
      app: frontend

This means:

namespace = platform
AND
pod = frontend

Case B: two peer entries

from:
- namespaceSelector:
    matchLabels:
      team: platform

- podSelector:
    matchLabels:
      app: frontend

This means:

namespace = platform
OR
Pod = frontend in the policy's namespace

The indentation changes the meaning.

This is a very important NetworkPolicy YAML detail.


20. Ports: another important concept

Suppose you have:

egress:
- to:
  - ipBlock:
      cidr: 192.168.121.17/32
  ports:
  - protocol: TCP
    port: 9999

The destination and port both need to match.

Think:

destination MATCH
        AND
port MATCH
        ↓
      ALLOW

Therefore:

192.168.121.17:9999/TCP     ✓
192.168.121.17:80/TCP       ✗
8.8.8.8:9999/TCP             ✗

The rule is not saying "allow the IP OR the port."

It is saying:

Allow traffic that matches the destination and the port.


21. Multiple ports in one rule are OR

Example:

ports:
- protocol: TCP
  port: 80
- protocol: TCP
  port: 443

means:

TCP/80   ✓
TCP/443  ✓

The ports inside that list are logically ORed.


22. Multiple destinations in one rule are OR

Example:

to:
- ipBlock:
    cidr: 10.0.0.0/24
- ipBlock:
    cidr: 192.168.1.0/24

means:

10.0.0.0/24      ✓
192.168.1.0/24   ✓

The destination peers are logically ORed.


23. Multiple rules are also additive

Suppose:

egress:
- to:
  - podSelector:
      matchLabels:
        app: database

- to:
  - podSelector:
      matchLabels:
        app: redis

Then:

backend ─────> database     ✓
backend ─────> redis        ✓
backend ─────> frontend     ✗

Think:

Rule 1 OR Rule 2 OR Rule 3 ...

not:

Rule 1 AND Rule 2

24. Multiple NetworkPolicies are additive

This is one of the most important concepts.

Suppose Policy A allows:

frontend → backend:8080

and Policy B allows:

monitoring → backend:9090

If both policies select the same backend Pods:

frontend   ───> backend:8080     ✓
monitoring ───> backend:9090     ✓

The policies do not override each other.

Their allowed traffic is combined.

Think:

Policy A
   │
   ├── allow X
   │
Policy B
   │
   ├── allow Y
   │
Policy C
   │
   ├── allow Z
   │
   ↓
X + Y + Z are allowed

This also means there is no standard policy ordering such as:

Policy 1
   ↓
Policy 2
   ↓
Policy 3

The policies are combined additively.


25. There is no "deny wins" in standard NetworkPolicy

Because standard NetworkPolicy does not have explicit deny rules, you cannot normally create:

Policy A:
ALLOW 10.0.0.0/24

Policy B:
DENY 10.0.0.5

and expect the second policy to override the first.

There is no standard deny rule.

Instead, the design is:

DEFAULT DENY
       +
EXPLICIT ALLOW

This is why NetworkPolicy is best understood as an allow-list.


26. Pod-to-Pod traffic: both directions matter

Suppose:

frontend Pod ───────────────> backend Pod

There are potentially two policy checks:

frontend                       backend
   │                              │
   │ EGRESS                       │ INGRESS
   │                              │
   └──────── connection ─────────>│

For a Pod-to-Pod connection to work when both Pods are isolated:

SOURCE EGRESS = ALLOW
        AND
DESTINATION INGRESS = ALLOW
        ↓
CONNECTION = ALLOW

If either side blocks it:

SOURCE EGRESS = DENY
        OR
DESTINATION INGRESS = DENY
        ↓
CONNECTION = BLOCKED

27. Scenario: both sides are default-deny

Suppose we start with:

Frontend:
  Egress = DENY ALL

Backend:
  Ingress = DENY ALL

Then:

frontend ─────────X────────> backend

Blocked.


28. Scenario: only frontend Egress is allowed

Now we add:

Frontend:
  Egress → ALLOW backend:8080

Backend:
  Ingress → still DENY ALL

Result:

frontend ─────────X────────> backend

Still blocked.

Why?

Because:

Frontend Egress = ✓
Backend Ingress = ✗

Both sides are not allowed.


29. Scenario: only backend Ingress is allowed

Now instead:

Frontend:
  Egress → still DENY ALL

Backend:
  Ingress → ALLOW frontend:8080

Result:

frontend ─────────X────────> backend

Still blocked.

Why?

Frontend Egress = ✗
Backend Ingress = ✓

Again, both sides are not allowed.


30. Scenario: both sides are allowed

Now:

Frontend:
  Egress → ALLOW backend:8080

Backend:
  Ingress → ALLOW frontend:8080

Result:

frontend ──────────────────> backend
             ALLOWED ✓

Now:

Frontend Egress = ✓
Backend Ingress = ✓

The connection works.


31. But do you always need both policies?

No.

This is an important nuance.

Suppose:

Frontend:
  Egress = NOT isolated

Backend:
  Ingress = ALLOW frontend:8080

Then the connection can work.

Why?

Because the frontend has no applicable Egress isolation, so its egress is allowed by default.

Likewise:

Frontend:
  Egress = ALLOW backend:8080

Backend:
  Ingress = NOT isolated

can also work.

The actual rule is:

If the source is egress-isolated, its egress must allow the connection.

If the destination is ingress-isolated, its ingress must allow the connection.

If neither side is isolated, traffic is allowed by default.


32. Return traffic

Suppose:

frontend ─────────> backend
       request

is allowed.

The backend's response traffic for that connection is permitted as reply traffic.

You do not normally need to create a separate NetworkPolicy rule just to permit the response to an already allowed connection.

Think:

frontend                    backend

   ─────── request ────────>
   <────── response ────────

        ONE CONNECTION

NetworkPolicy is concerned with whether the connection is allowed; it is not normally necessary to model the return packet as an independent application connection.


33. A complete example

Suppose we have:

frontend Pod
app=frontend

backend Pod
app=backend

database Pod
app=database

We want:

frontend → backend:8080
backend  → database:5432

and we want everything else denied.

A common design is:

Default deny
      +
Allow frontend → backend
      +
Allow backend → database

Default deny

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Allow frontend to backend

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

Allow backend to database

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-to-database
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432

If backend egress is still denied by the default-deny policy, you would also need an egress allow for backend → database.

For example:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-egress-to-database
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432

Now the flow is:

frontend
   │
   │ Egress must be allowed
   ↓
backend
   │
   │ Egress must be allowed
   ↓
database

And the database must allow the corresponding ingress.


34. A practical way to read any NetworkPolicy

Whenever you see a NetworkPolicy, read it in this order:

Step 1 — Who is selected?

Look at:

podSelector:

Ask:

Which Pods does this policy apply to?


Step 2 — Which direction?

Look at:

policyTypes:

Ask:

Is this controlling ingress, egress, or both?


Step 3 — Who/where is allowed?

For ingress:

from:

Ask:

Who can connect to these Pods?

For egress:

to:

Ask:

Where can these Pods connect?


Step 4 — Which ports?

Look at:

ports:

Ask:

Which protocol and destination port are allowed?


Step 5 — Remember the implicit deny

If the Pod is isolated for that direction:

matches a rule → ALLOW
doesn't match   → DENY

35. Your original policy, translated

Your original policy was:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-metadata
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: app
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 192.168.121.17/32
    ports:
    - protocol: TCP
      port: 9999

Read it in plain English:

Select Pods with app=app.

Then:

Isolate them for Egress.

Then:

Allow TCP traffic to 192.168.121.17 on port 9999.

Therefore:

app=app Pod

192.168.121.17:9999/TCP     ✓ ALLOW
192.168.121.17:80           ✗ DENY
192.168.121.17:443          ✗ DENY
8.8.8.8:443                 ✗ DENY
another Pod                 ✗ DENY

So despite its name:

name: deny-metadata

the policy is actually allowing the metadata destination.

The name does not change policy behavior.


36. If I want to block one specific IP/port, what should I remember?

Suppose your requirement is:

ALLOW everything
EXCEPT
192.168.121.17:9999

Standard Kubernetes NetworkPolicy does not provide an explicit deny rule for this.

You cannot simply write:

deny:
- ipBlock:
    cidr: 192.168.121.17/32
  ports:
  - port: 9999

That field does not exist in the standard NetworkPolicy API.

Instead, standard NetworkPolicy works by defining the traffic that is allowed.

This is why a precise "deny one IP + port while allowing everything else" requirement can require careful allow-list design, or a policy engine with capabilities beyond the standard Kubernetes NetworkPolicy API.

We will cover those extended policy engines separately.


37. What NetworkPolicy can target

For standard Kubernetes NetworkPolicy, keep these three peer mechanisms in your mental model:

Selector What it targets Typical use
podSelector Pods frontend → backend
namespaceSelector Namespaces, and therefore Pods in them allow traffic from another team/namespace
ipBlock IP/CIDR ranges external networks, specific IPs, CIDRs

You can also combine namespaceSelector and podSelector in the same peer entry to select specific Pods in selected namespaces.


38. What about Services?

NetworkPolicy fundamentally operates at the network traffic level, not at the Kubernetes Service object level.

For example, an application may connect to:

my-backend.default.svc.cluster.local:8080

The traffic ultimately reaches a Pod endpoint.

How the Service IP, endpoint IP, NAT, routing, and NetworkPolicy implementation interact can depend on the cluster's networking implementation.

Therefore, don't assume that writing a policy around a Service's virtual IP is always equivalent to writing a policy around the actual Pod endpoints.

For exact behavior involving Services and IP rewriting, test with your actual network plugin.


39. NetworkPolicy requires enforcement support

Creating a NetworkPolicy object does not magically enforce traffic filtering.

Your cluster must use a network plugin that supports NetworkPolicy enforcement.

For example, the Kubernetes API can accept:

kubectl apply -f network-policy.yaml

but actual traffic enforcement depends on the networking implementation.

This is why NetworkPolicy behavior can sometimes differ between clusters.


40. The mental model to remember

If you remember only these rules, you can understand most standard NetworkPolicies.

Rule 1 — No applicable policy means open

No policy selecting Pod
        ↓
Ingress = allowed
Egress  = allowed

Rule 2 — An applicable policy isolates that direction

Ingress policy selects Pod
        ↓
Ingress becomes allow-list
Egress policy selects Pod
        ↓
Egress becomes allow-list

Rule 3 — Empty rules mean deny everything for that isolated direction

Ingress isolation
+
no ingress rules
        ↓
DENY ALL INGRESS
Egress isolation
+
no egress rules
        ↓
DENY ALL EGRESS

Rule 4 — NetworkPolicy is allow-list based

MATCHES an allowed rule → ALLOW
DOES NOT MATCH          → DENY

for an isolated direction.

Rule 5 — Multiple policies are additive

Policy A allows X
Policy B allows Y

Result:
X + Y are allowed

Rule 6 — Pod-to-Pod traffic can involve both sides

SOURCE EGRESS ✓
       +
DESTINATION INGRESS ✓
       =
CONNECTION ✓

when both directions are isolated.


41. The simplest possible picture

Keep this picture in your head:

                         Kubernetes Pod
                              │
                    ┌─────────┴─────────┐
                    │                   │
                 INGRESS              EGRESS
                    │                   │
                 "from"               "to"
                    │                   │
                    ↓                   ↓
             Who can reach me?   Where can I reach?
                    │                   │
                    └─────────┬─────────┘
                              │
                        ALLOW-LIST
                              │
                     Everything else
                         is denied
                    when isolated

And for peer selection:

             from / to
                 │
       ┌─────────┼─────────┐
       │         │         │
       ↓         ↓         ↓
      Pod     Namespace    IP/CIDR
 selector    selector     ipBlock

That's the standard Kubernetes NetworkPolicy model.


42. Final cheat sheet

podSelector
    ↓
Which Pods does this policy apply to?

policyTypes
    ↓
Which direction becomes isolated?

Ingress
    ↓
Traffic coming INTO selected Pods

Egress
    ↓
Traffic going OUT OF selected Pods

from
    ↓
Ingress source

to
    ↓
Egress destination

podSelector
    ↓
Select Pods

namespaceSelector
    ↓
Select namespaces

ipBlock
    ↓
Select IP/CIDR ranges

ports
    ↓
Restrict protocol + destination port

No applicable policy
    ↓
Traffic allowed by default

Applicable policy + no matching rule
    ↓
Traffic denied for that isolated direction

Multiple policies
    ↓
Allowed traffic is combined additively

Explicit deny
    ↓
Not part of the standard Kubernetes NetworkPolicy API

Official Kubernetes sources

This article intentionally uses the standard Kubernetes NetworkPolicy model and official Kubernetes documentation as the source of truth.

The official API reference defines podSelector, policyTypes, ingress, egress, podSelector, namespaceSelector, ipBlock, ports, and the additive behavior of applicable policies.

Note: NetworkPolicy enforcement requires a network plugin that supports NetworkPolicy. Exact behavior around source/destination IP rewriting, Services, load balancers, and other networking features can depend on the cluster's networking implementation.