Master Kubernetes security by implementing a Zero-Trust architecture. Learn to use Kyverno and Network Policies to enforce strict, automated security at scale.
In the early days of Kubernetes, we treated the cluster like a trusted internal network. If a pod could reach the API server or another service, it had permission to do so. That’s a dangerous assumption. As a DevOps engineer, I’ve seen enough lateral movement attacks to know that the "castle and moat" strategy is dead.
To secure our clusters, we need Zero-Trust architecture. We stop trusting traffic by default and start verifying every connection. In this post, I’ll show you how to combine Kubernetes Network Policies with Kyverno to turn your security requirements into executable code.
Network Policies are your first line of defense. They function as a distributed firewall at the pod level. By default, pods are non-isolated, meaning they accept traffic from any source. We need to flip that.
First, implement a "Default Deny" policy for every namespace. This ensures that if you forget to whitelist a service, it stays isolated.
YAMLapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all spec: podSelector: {} policyTypes: - Ingress - Egress
Once you apply this, your cluster is locked down. Now, you only open holes for traffic you explicitly trust.
Writing Network Policies manually is a recipe for drift. Developers will forget labels, or someone will accidentally create a policy that’s too permissive. This is where Kyverno shines. As a Policy-as-Code engine, Kyverno lets us enforce best practices automatically.
If you’re running Kyverno v1.11+, you can use it to mutate resources or validate that every new namespace comes pre-configured with a default Network Policy.
Instead of relying on human discipline, let's use a Kyverno ClusterPolicy to ensure every namespace has a network-restricted posture. This policy automatically generates a NetworkPolicy object whenever a new namespace is created:
YAMLapiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: add-default-deny-policy spec: generateExisting: true rules: - name: create-default-deny match: resources: kinds: - Namespace generate: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy name: default-deny namespace: "{{request.object.metadata.name}}" data: spec: podSelector: {} policyTypes: - Ingress - Egress
By deploying this, you’ve effectively automated your Kubernetes security baseline. No namespace enters the cluster without being secured.
Zero-Trust isn't just about blocking traffic; it’s about identity and least privilege. Here’s how I structure my production clusters:
app: frontend, app: backend). Write policies that only allow frontend to talk to backend on specific ports.audit mode before switching to enforce. This lets you see which pods would break without actually killing your production traffic.I’ve learned the hard way that aggressive security can break legitimate traffic. Here are three rules I follow:
enforce mode immediately. Use Kyverno’s reporting features to check for violations for at least 24 hours.Implementing a Zero-Trust architecture in Kubernetes isn't a one-time project; it’s a continuous process of narrowing the blast radius. By combining the granular control of Network Policies with the automation power of Kyverno, you turn security from a bottleneck into a scalable feature.
Start small. Apply the default deny policy today, observe the logs, and build your whitelist from there. Your future self—and your security team—will thank you.
Master Kubernetes secret management by integrating HashiCorp Vault and the External Secrets Operator. Secure your cloud-native apps and streamline GitOps workflows.
Read moreMaster Kubernetes compliance using Policy-as-Code. Compare Kyverno and OPA Gatekeeper to secure your clusters with actionable code examples and best practices.