k8s-security.pro
kubernetes security zero-trust network-policy rbac

Implementing Zero Trust Architecture in Kubernetes

A practical guide to implementing zero trust security in Kubernetes with network policies, RBAC, service mesh, and pod security standards.

K8s Security Pro Team | | 14 min read

Implementing Zero Trust Architecture in Kubernetes

The traditional perimeter-based security model assumes that everything inside your network is trusted. In Kubernetes, this assumption is catastrophic. With pods spinning up and down, developers deploying code multiple times per day, and workloads sharing the same cluster, the only safe assumption is that nothing is trusted — not the network, not the identity, not the workload.

Zero trust in Kubernetes means: verify everything, trust nothing, and assume breach. This guide walks you through implementing each pillar of zero trust in a production Kubernetes environment.

The Three Pillars of Kubernetes Zero Trust

Zero trust in Kubernetes rests on three interconnected pillars:

  1. Network Zero Trust — No pod can communicate with any other pod unless explicitly allowed
  2. Identity Zero Trust — Every request to the Kubernetes API is authenticated and authorized with minimal permissions
  3. Workload Zero Trust — Every container runs with the least privileges needed, in a hardened security context

Remove any one pillar and your zero trust architecture has a gap an attacker can exploit. Let’s implement each one.

Pillar 1: Network Zero Trust with Network Policies

By default, Kubernetes networking is completely flat. Every pod can reach every other pod, across every namespace, on every port. This is the single biggest security gap in a default Kubernetes installation.

Step 1: Default Deny All Traffic

The foundation of network zero trust is a default deny policy in every namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

This policy selects all pods (podSelector: {}) and blocks both incoming and outgoing traffic. Once applied, no pod in the namespace can communicate unless another policy explicitly allows it.

Important: Apply this to every namespace, including default, staging, and any custom namespaces. The only exception is kube-system, which needs internal communication for cluster operations.

Step 2: Explicitly Allow Required Traffic

After default deny, layer on specific allow rules for each application:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

This explicitly allows only the frontend pods to reach api-server on port 8080. Every other traffic path remains blocked.

Step 3: Namespace Isolation

Prevent cross-namespace traffic by default. A breach in your dev namespace should never reach production:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-cross-namespace
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}

This allows intra-namespace traffic while blocking all cross-namespace connections.

Step 4: Block Cloud Metadata

In cloud environments, the metadata endpoint (169.254.169.254) is a goldmine for attackers. An SSRF vulnerability in any pod can be used to steal IAM credentials:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: block-cloud-metadata
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32

Step 5: Encrypt with mTLS

Network policies control which pods can communicate, but traffic between them is still unencrypted. Deploy a service mesh (Istio, Linkerd) to add mutual TLS:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: strict-mtls
  namespace: production
spec:
  mtls:
    mode: STRICT

With mTLS, every service-to-service connection is encrypted and both sides verify each other’s identity using X.509 certificates.

For standard Kubernetes NetworkPolicy templates, see Template 01: Default Deny, Template 14: Namespace Isolation, and Template 20: Complete 3-Tier NetworkPolicy.

Pillar 2: Identity Zero Trust with RBAC

Kubernetes RBAC (Role-Based Access Control) is the identity layer of your zero trust architecture. The goal: every human user, service account, and CI/CD pipeline has the absolute minimum permissions needed.

Principle of Least Privilege

Start by auditing existing ClusterRoleBindings. The cluster-admin role is “game over” — it grants full control over the entire cluster:

# Find all cluster-admin bindings
kubectl get clusterrolebindings -o json | \
  jq '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name'

Replace broad roles with namespace-scoped Roles:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-developer
  namespace: development
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "create", "update"]
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]

Service Account Segregation

Never share service accounts between applications. Each workload should have its own service account with only the permissions it needs:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: payment-service
  namespace: production
automountServiceAccountToken: false

Setting automountServiceAccountToken: false prevents the token from being mounted unless the pod explicitly requires it. Most pods don’t need Kubernetes API access at all.

Eliminate Wildcards

Wildcard permissions (*) in RBAC rules are the equivalent of leaving your front door open:

# Find roles with wildcard permissions
kubectl get clusterroles -o json | \
  jq '.items[] | select(.rules[]?.verbs[]? == "*") | .metadata.name'

Replace wildcards with explicit verbs: ["get", "list", "watch"] instead of ["*"].

For RBAC templates, see Template 04: Least Privilege RBAC and Template 05: Secure Service Account.

Pillar 3: Workload Zero Trust with Pod Security

Even with network isolation and RBAC, a container running as root with full capabilities is a ticking time bomb. Workload zero trust means every container runs in a hardened security context.

Pod Security Standards (PSS)

Kubernetes 1.25+ includes built-in Pod Security Standards at three levels:

  • Privileged — Unrestricted (default, dangerous)
  • Baseline — Prevents known privilege escalations
  • Restricted — Hardened for security-critical workloads

Apply the restricted standard at the namespace level:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Container Security Context

Every container should specify a complete security context:

securityContext:
  readOnlyRootFilesystem: true
  runAsNonRoot: true
  runAsUser: 65534
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]
  seccompProfile:
    type: RuntimeDefault

This configuration:

  • readOnlyRootFilesystem — Prevents attackers from writing malware to the container
  • runAsNonRoot — Ensures the container doesn’t run as root (UID 0)
  • allowPrivilegeEscalation: false — Blocks setuid binaries from escalating to root
  • drop ALL capabilities — Removes all Linux capabilities
  • seccompProfile: RuntimeDefault — Restricts available system calls

Admission Control Enforcement

Use Kyverno or OPA Gatekeeper to enforce these standards as admission policies. This prevents anyone from deploying a pod that violates your security requirements, even if they have RBAC permission to create pods:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-security-context
spec:
  validationFailureAction: Enforce
  rules:
  - name: require-run-as-non-root
    match:
      any:
      - resources:
          kinds: ["Pod"]
    validate:
      message: "Containers must run as non-root"
      pattern:
        spec:
          containers:
          - securityContext:
              runAsNonRoot: true

For pod security templates, see Template 03: Hardened Pod Security Context and Template 09: Seccomp Profile.

Putting It All Together: A Zero Trust Audit

Here’s a quick checklist to assess your cluster’s zero trust posture:

Network

  • Default deny NetworkPolicy in every namespace
  • Cross-namespace traffic blocked unless explicitly allowed
  • Cloud metadata endpoint (169.254.169.254) blocked
  • Egress restricted to known-good destinations
  • mTLS enabled between all services

Identity

  • No unnecessary cluster-admin bindings
  • No wildcard permissions in roles
  • Each application has its own ServiceAccount
  • automountServiceAccountToken: false by default
  • Short-lived credentials for humans and CI/CD

Workload

  • Pod Security Standards “restricted” enforced
  • All containers run as non-root
  • All capabilities dropped
  • Read-only root filesystem
  • Seccomp profiles enabled
  • Admission controllers enforce security policies

Common Pitfalls

  1. Starting too strict. Don’t enable enforce mode everywhere on day one. Start with audit and warn modes to understand what would break, then gradually enforce.

  2. Forgetting DNS. Default deny blocks DNS (port 53 to kube-dns). You need an explicit egress rule to allow DNS resolution, or nothing works.

  3. Ignoring system namespaces. kube-system, istio-system, and other infrastructure namespaces need their own policies that allow their internal communication patterns.

  4. Service mesh vs NetworkPolicy. They’re complementary, not competing. NetworkPolicy operates at L3/L4 (IP and port), while a service mesh adds L7 (HTTP) control and mTLS encryption. Use both.

  5. Not testing restores. Zero trust protects against attacks, but you still need backups. Test that you can restore your cluster after a catastrophic event.

Next Steps

Zero trust is not a checkbox — it’s a continuous process. Start with the highest-impact items:

  1. Deploy default deny NetworkPolicy in production namespaces today
  2. Audit and remove cluster-admin bindings this week
  3. Enable PSS “restricted” in audit mode across all namespaces
  4. Plan service mesh deployment for mTLS within the next quarter

The complete 50-point Kubernetes security checklist covers all of these controls with kubectl verification commands, YAML fixes, and compliance mappings.


Get the Complete 50-Point Security Checklist

5 production-ready templates + audit checklist highlights, free for K8s engineers.

Get Free Kit

Get the Free K8s Security Quick-Start Kit

Get 5 essential templates + audit checklist highlights delivered to your inbox.

No spam. Unsubscribe anytime.

Secure Your Kubernetes Clusters

Get the complete 50-point audit checklist and 20+ production-ready YAML templates.

View Pricing Plans