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:

  1. Identity-based access for anything entering the cluster (North-South traffic).
  2. 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.