The term “Zero Trust” has been buzzed to death by marketing teams, but it’s a simple premise: assume breach. Don’t trust a packet just because it originated from inside your VPC.
In a Kubernetes context, this means two things:
- Identity-based access for anything entering the cluster (North-South traffic).
- Strict traffic rules for services talking to each other (East-West traffic).
Here is how I implemented a zero-trust network for my personal cluster using Tailscale and Kubernetes Network Policies.
The Gateway: Tailscale
Exposing services to the public internet is scary. VPNs are annoying. Tailscale (built on WireGuard) is the perfect middle ground. It creates a mesh network where every device is authenticated via your SSO provider.
By running the Tailscale Kubernetes Operator, I can expose internal cluster services directly to my tailnet without opening a single port on the firewall.
# Example: Exposing the Grafana service to the Tailnet
apiVersion: v1
kind: Service
metadata:
name: grafana
annotations:
tailscale.com/expose: "true"
tailscale.com/hostname: "k8s-grafana"
spec:
ports:
- port: 80
targetPort: 3000
selector:
app: grafana
With this annotation, the operator spins up a sidecar/proxy, authenticates with Tailscale, and makes http://k8s-grafana accessible only to devices in my Tailscale network.
The Firewall: Network Policies
Once inside the cluster, reliance on the “flat network” model is a security risk. If one pod is compromised, it can scan and attack others. Network Policies act as a firewall at the pod level.
I start with a Default Deny policy for every namespace. This ensures that no traffic is allowed unless explicitly whitelisted.
# 1. Block EVERYTHING by default
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Then, I strictly layer on allow rules. For example, my frontend needs to talk to the backend api, but nothing else.
# 2. Allow Frontend -> Backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
Conclusion
By combining Tailscale for secure, identity-aware ingress and Network Policies for strict east-west traffic control, you effectively minimize the blast radius of any potential intrusion. It adds a bit of YAML overhead, but the peace of mind is worth it.