Trying out NetworkPolicy on Kubernetes running on Docker for macOS


I was tempting to try out NetworkPolicy1 on Kubernetes as a secure way to protect traffic in and out Pods. Today a friend of mine who was pursuing “Certified Kubernetes Application Developer” asked me a problem related to it.

He was using a small set of exercises 2 to practice Kubernetes. The problem statement was:

### Create an nginx deployment of 2 replicas, expose it via a ClusterIP service on port 80. Create a NetworkPolicy so that only pods with labels 'access: granted' can access the deployment and apply it

The guide also included the solution and he tried it on his test environment and it didn’t work. The deployed network policy did not take effect at all.

At first, I thought it might be because he did not deploy a “deny-all” policy as described in the page 1. This practice seemed like a good practice that almost all serious production-ready solution used (see CouchBase 3).

apiVersion: v1
kind: Namespace
  name: $NAMESPACE
kind: NetworkPolicy
  name: default-deny-all-except-dns
  namespace: $NAMESPACE
  # Prevent any traffic for all pods apart from that we specifically allow.
  # This is taken from the Kubernetes documentation with a tweak to allow DNS.
  podSelector: {}
  - Ingress
  - Egress
  # Allow DNS resolution, primarily for Couchbase pods but it triggers other
  # hard to debug connection issues sometimes too so be aware if this is moved to
  # the later rules.
  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP

However, my friend tried that as well and it still DIDN’T work. Hmm! So I thought “Let’s try!”


I was using a MacBook Pro and installed Docker for macOS. I didn’t want to use any managed Kubernetes cluster available online because I didn’t want to waste time on them.

So I started to use Kind 4 to set up a Kubernetes cluster on the existing Docker Engine.

kind is a tool for running local Kubernetes clusters using Docker container “nodes”.
kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI.

$> brew install kind
$> kind create cluster
$> kubectl cluster-info --context kind-kind

Now, I ran the same set of commands suggested by the exercise 2 and, interestingly, reproduced the issue.

Grokking it a little harder

I re-read the page 1, until now, very carefully again and found out that:

Make sure you’ve configured a network provider with network policy support. There are a number of network providers that support NetworkPolicy, including:

Okay. So NetworkPolicy did not come out-of-the-box in Kubernetes. And to top it off, the exercise DID NOTICE THAT as well:

Note that network policies may not be enforced by default, depending on your k8s implementation. E.g. Azure AKS by default won’t have policy enforcement, the cluster must be created with an explicit support for netpol

Shame on me!

In order to test the NetworkPolicy, I have to see if the cluster created by Kind did support network policy? Turned out that it was supported…eventually.

According to the GitHub issue “#842 NetworkPolicy support” (which was still open as of this writing btw), Kind could provide support for network policies by installing Calico. The most voted comment 5 showed how to do it.

To sum it up:

  • The cluster created by Kind MUST have the default CNI plugin disabled 6.
  • The network provider Calico MUST be installed.
# IMPORTANT: This guide worked on 2023-01-16

# [1]: First create a Kind cluster with default CNI disabled.
$> cat <<'_YAML_' |  kind create cluster --name test --config -
# this config file contains all config fields with comments
# NOTE: this is not a particularly useful config file
kind: Cluster
  disableDefaultCNI: true
  podSubnet: ""

# [2]: Install Calico v3.25
$> kubectl apply -f

# [3]: It may take a while for Calico and Kubernetes to settle.
# Use the following command to watch until all Pods reach "Running" state.
$> kubectl get pods -n kube-system

Once all the Pods reached the state “Running”, it was time to test.

$> kubectl create deployment nginx --image=nginx --replicas=2
$> kubectl expose deployment nginx --port=80
$> cat <<_YAML_ | kubectl apply -f-
kind: NetworkPolicy
  name: access-nginx # pick a name
      app: nginx # selector for the pods
  ingress: # allow ingress traffic
  - from:
    - podSelector: # from pods
        matchLabels: # with this label
          access: granted
$> kubectl run busybox \
  --image=busybox --rm -it --restart=Never -- wget -O- http://nginx:80 --timeout 2
  # This should not work. --timeout is optional here. But it helps to get answer more quickly (in seconds vs minutes)
$> kubectl run busybox --image=busybox --rm -it --restart=Never --labels=access=granted -- wget -O- http://nginx:80 --timeout 2 # This should be fine

Key Takeaways

  • As always, Read The Documents CAREFULLY AGAIN, once you hit a trouble that it should not be there.
  • Kind was only used for local-testing/learning.
  • NetworkPolicy is not out-of-the-box. Check the network provider installed for Kubernetes cluster.