Securing Microservices in Kubernetes
IntroductionStarting with version 1.3, Kubernetes includes beta support for network policies that allow you to exert control over connections to your containers. For those unfamiliar with Kubernetes network policies they have the following...

Multi-cluster Application Deployment Made Easy with GitOpsSets
KubeCon EU 2023 Recap – GitOps Sessions on Flux with OCI, Liquid Metal CI/CD Platforms & Telco Cloud Platforms
Close the Cloud-Native Skills Gap and Use Automation to Boost Developer Productivity with Weave GitOps Release 2023.04
Introduction
Starting with version 1.3, Kubernetes includes beta support for network policies that allow you to exert control over connections to your containers. For those unfamiliar with Kubernetes network policies they have the following characteristics:
- Control over ingress only
- Connection oriented, stateful
- Disabled by default; enabled on a per-namespace basis
- Label selectors used to select source and destination pods
- Filter by protocol (TCP/UDP) and port
If you’re used to working with standard firewalls, there are also a few notable simplifying omissions:
- No ability to filter by CIDR
- No ability to specify deny rules
Finally, it is important to understand that although the Kubernetes API server understands network policy objects, it does not ship with a controller that implements them. Fortunately Weave Net 1.8.0 includes just such an implementation, and is readily installed on your cluster with a single command.
If you would like to experiment with network policies but don’t have a cluster already, you can create one easily using the kubeadm tool – be sure to include the Weave pod network addon!
Policy Design Considerations
There are many reasons why you may chose to employ Kubernetes network policies:
- Ensure containers assigned to different environments (e.g. dev/staging/prod) cannot interfere with one another
- Isolate multi-tenant deployments
- Regulatory compliance
- Segregate teams
- Enforce best practices
In this post we will explore the final category, and enforce microservices best practices at the network level:
- By ensuring that backing data stores/message queues are accessible only by the microservice that owns them
- That microservices are only accessible to the front end and to the other microservices
- And that only the front end services are accessible from the internet (or more usually an external load balancer)
- And finally, that the monitoring system can gather metrics from all services
Implementation
This section uses the Weaveworks Sock-shop microservices demo as a real-world example. You can see the full set of policy specifications for the sock-shop here.
Enabling Ingress Isolation
First of all, we must enable ingress isolation for the sock-shop namespace. As network policy is still a beta feature, it is enabled by adding an annotation:
kubectl annotate ns sock-shop net.beta.kubernetes.io/network-policy='{"ingress":{"isolation":"DefaultDeny"}}'
Alternatively, in YAML form:
kind: Namespace apiVersion: v1 metadata: name: sock-shop annotations: net.beta.kubernetes.io/network-policy: | { "ingress": { "isolation": "DefaultDeny" } }
At this point, no pods in the sock-shop namespace can receive connections – everything is blocked. We must now add policies that selectively allow legitimate traffic.
If you wish to later remove the annotation you can do so with the following command (taking careful note of the trailing minus sign):
kubectl annotate ns sock-shop net.beta.kubernetes.io/network-policy-
NB do not attempt to
kubectl delete -f
the above YAML – you’ll delete the sock-shop namespace entirely!
Allowing External Access
As mentioned in the introduction, Kubernetes network policies identify traffic sources and destinations by label selector only – there is no provision (as yet) to specify IP addresses or masks. How then does one allow access into the cluster from external sources, once ingress isolation is enabled? The solution is straightforward, if slightly obscure; the from
label selector can be omitted entirely, in which case traffic is not filtered by source at all:
apiVersion: extensions/v1beta1 kind: NetworkPolicy metadata: name: front-end-access namespace: sock-shop spec: podSelector: matchLabels: name: front-end ingress: - ports: - protocol: TCP port: 8079
This policy applies to any pods labelled name: front-end
in the sock-shop namespace, and it allows TCP connections to port 8079. There are a few points of particular interest here:
- Matching on
name: front-end
means that this policy will apply automatically to all replicas of the front end (assuming we have arranged for them to be so labelled) - Port filtering is applied after traffic has passed through the kubeproxy DNAT – consequently we must specify the pod container port, not the service or node port!
Now that our external loadbalancer can access our front end, we must add policies that allow access to the internal microservices and their underpinning databases and message queues.
Allowing Internal Access
The full Sock-shop demo includes multiple microservices – we will consider only one, the catalogue, as an example. You can see the full set of policies for the sock-shop here. First of all we need a policy that allows the front end to access the catalogue REST API:
apiVersion: extensions/v1beta1 kind: NetworkPolicy metadata: name: catalogue-access namespace: sock-shop spec: podSelector: matchLabels: name: catalogue ingress: - from: - podSelector: matchLabels: name: front-end ports: - protocol: TCP port: 80
With that in place, we need a policy that grants exclusive catalogue database access to the catalogue microservice:
apiVersion: extensions/v1beta1 kind: NetworkPolicy metadata: name: catalogue-db-access namespace: sock-shop spec: podSelector: matchLabels: name: catalogue-db ingress: - from: - podSelector: matchLabels: name: catalogue ports: - protocol: TCP port: 3306
That’s it for the catalogue microservice – equivalent policies for the other services can be found in the repo linked above. Finally, we need a cross-cutting policy that allows our local Prometheus agent to scrape metrics for upload to Weave Cloud:
apiVersion: extensions/v1beta1 kind: NetworkPolicy metadata: name: cortex-access namespace: sock-shop spec: podSelector: matchLabels: ingress: - from: - podSelector: matchLabels: name: cortex
Testing & Debugging
When drafting policies for an existing application, it is common for initial revisions to be incomplete or wrong – they need to be tested and debugged like anything else. It is very important that you exercise all aspects of your application, including:
- Handling of exceptional conditions
- Scheduled/batch jobs that run infrequently
- Access provisions for backups, maintenance and debugging
since any of these may need to make or receive connections to operate correctly.
Future versions of the Weave Net policy controller will feature improved logging of blocked connections for diagnostic purposes – see weaveworks/weave#2629 for more details. In the meantime, you can use the metrics endpoints covered in the next section to get a summary of what is being blocked.
Monitoring
Weave Net exposes metrics endpoints which can be used to monitor the policy controller – see the documentation on configuring Prometheus for more information. Of particular interest is the weavenpc_blocked_connections_total
counter – we recommend configuring an alarm to draw your attention if this value is increasing rapidly, as that is a sign of misconfiguration or potentially even an attack on your infrastructure. The counter has protocol and dport labels if you wish to be more selective.
External Resources