Kubernetes networking behavior allows traffic between pods in the cluster as a default behavior. Attackers who gain access to a single container may use it for network reachability to another container in the cluster.
First we need to create an appropriate demo setup to explain.
# A namespace called "secret"
apiVersion: v1
kind: Namespace
metadata:
name: secret
---
# A web application in the form of a Pod called "web" in the "secret" namespace
apiVersion: v1
kind: Pod
metadata:
labels:
app: web
name: web
namespace: secret
spec:
containers:
- image: nginx
name: web
ports:
- containerPort: 80
---
# A service which exposes the "web" Pod in the "secret" namespace
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
namespace: secret
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
---
# A web application in the form of a Pod called "web-secret-only" in the "secret" namespace
apiVersion: v1
kind: Pod
metadata:
labels:
app: web-secret-only
name: web-secret-only
namespace: secret
spec:
containers:
- image: nginx
name: web
ports:
- containerPort: 80
---
# A service which exposes the "web-secret-only" Pod in the "secret" namespace
apiVersion: v1
kind: Service
metadata:
labels:
app: web-secret-only
name: web-secret-only
namespace: secret
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web-secret-only
---
# A second namespace which is called "test-namespace"
apiVersion: v1
kind: Namespace
metadata:
name: test-namespace
---
# A Pod called "test-pod" in the "test-namespacecret" namespace (it doesn't matter that it's also a web application)
apiVersion: v1
kind: Pod
metadata:
name: test-pod
namespace: test-namespace
spec:
containers:
- image: nginx
name: web
$ kubectl exec -it test-pod -n test-namespace -- curl http://web.secret
# Gives a proper HTTP 200 response
$ kubectl exec -it test-pod -n test-namespace -- curl http://web-secret-only.secret
# Gives a proper HTTP 200 response
$ kubectl exec -it web -n secret -- curl http://web-secret-only.secret
# Gives a proper HTTP 200 response
Now we add NetworkPolicy objects which will make sure the web
Pod/Service is the only one in the secret
namespace that can be reached from containers running in other namespaces. Within the secret
namespace Pods can communicate with each other without any restrictions.
Make sure your Kubernetes cluster uses a CNI that supports NetworkPolicy objects and enforces them. Many Kubernetes distributions that are used mainly for development and testing like Minikube and k3d may require additional configuration steps.
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
namespace: secret
name: deny-from-other-namespaces
spec:
podSelector:
matchLabels:
ingress:
- from:
- podSelector: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: web-allow-all-namespaces
namespace: secret
spec:
podSelector:
matchLabels:
app: web
ingress:
- from:
- namespaceSelector: {}
$ kubectl exec -it test-pod -n test-namespace -- curl http://web.secret
# Gives a proper HTTP 200 response
$ kubectl exec -it test-pod -n test-namespace -- curl http://web-secret-only.secret
# Timeout - no connection possible
$ kubectl exec -it web -n secret -- curl http://web-secret-only.secret
# Gives a proper HTTP 200 response
As we can see, the test-pod
can no longer reach the web-secret-only
application in the secret
namespace as the test-pod
is located in the test-namespace
namespace. An attacker might therefore target the web
Pod as e.g. in the case of it containing a software vulnerability which can then be exploited by an attacker as described in Application exploit (RCE) to use it as a pivot point to target web-secret-only
once web
is under the attacker’s control.