Cybersecurity & Compliance

Kubernetes Security Best Practices

MatterAI
MatterAI
14 min read·

Kubernetes Security Best Practices

Kubernetes security fails in layers, and it fails in predictable ways: over-permissioned service accounts, flat networks, secrets in plaintext, and images pulled from anywhere. This guide covers the defensive layers in the order attackers exploit them, with concrete YAML for each.

Layer 1: Authentication and Authorization (RBAC)

The default cluster-admin service account is the most common security hole. Grant the least privilege per workload:

# rbac.yaml — a service account that can only read its own namespace
apiVersion: v1
kind: ServiceAccount
metadata:
  name: payments-sa
  namespace: payments
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: payments-reader
  namespace: payments
rules:
  - apiGroups: [""]
    resources: ["pods", "services", "configmaps"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: payments-reader-binding
  namespace: payments
subjects:
  - kind: ServiceAccount
    name: payments-sa
    namespace: payments
roleRef:
  kind: Role
  name: payments-reader
  apiGroup: rbac.authorization.k8s.io

Rules:

  • Never use cluster-admin for workloads. It is for cluster operators only.
  • Use Roles (namespace-scoped) over ClusterRoles unless the workload genuinely needs cluster scope.
  • Audit bindings regularly: kubectl get rolebindings -A and review who can do what.
  • Disable the default service account for pods that do not need API access:
spec:
  automountServiceAccountToken: false

Layer 2: Network Policies

By default, Kubernetes networks are flat: any pod can talk to any pod. Network policies are the firewall:

# networkpolicy.yaml — payments can only talk to the database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: payments-allow-db
  namespace: payments
spec:
  podSelector:
    matchLabels:
      app: payments
  policyTypes: [Ingress, Egress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api-gateway
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432

Rules:

  • Default-deny is the only safe default: create a policy that denies all traffic, then add allow rules.
  • The CNI must support policies: Calico, Cilium, or Weave. Flannel does not enforce them.
  • Block egress to the internet for workloads that do not need it.

Layer 3: Pod Security

Pod Security Standards (replacing PodSecurityPolicies) enforce three levels: privileged, baseline, restricted.

# pod-security.yaml — enforce restricted in the payments namespace
apiVersion: v1
kind: Namespace
metadata:
  name: payments
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

A restricted pod must run as non-root, drop all capabilities, and avoid privileged features:

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      securityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop: ["ALL"]
        readOnlyRootFilesystem: true

Layer 4: Secrets Management

Secrets in kind: Secret are base64, not encrypted. Treat them as plaintext:

  • Use an external secrets manager: Vault, AWS Secrets Manager, or GCP Secret Manager, synced via the External Secrets Operator or CSI driver.
  • Enable encryption at rest for etcd: --encryption-provider-config with a KMS provider.
  • Never commit secrets to git: scan with tools like gitleaks in CI.
  • Rotate automatically: external secrets with short TTLs rotate without redeploys.
# ExternalSecret — pull from AWS Secrets Manager
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: payments-db
  namespace: payments
spec:
  secretStoreRef:
    name: aws-secrets
    kind: SecretStore
  target:
    name: payments-db-secret
  data:
    - secretKey: password
      remoteRef:
        key: payments/prod/db
        property: password

Layer 5: Supply Chain Security

The images you run are the code you deploy. Secure the pipeline:

  1. Use signed images: cosign sign and verify with policy controllers (Kyverno, OPA Gatekeeper).
  2. Pin image digests, not tags: image: myapp@sha256:abc123... prevents tag mutation.
  3. Scan images in CI: Trivy, Grype, or Snyk before they reach the registry.
  4. Restrict registries: an admission policy that only allows images from your registry.
# Kyverno policy — only allow images from the trusted registry
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-trusted-registry
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-registry
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "Images must come from registry.acme.io"
        pattern:
          spec:
            containers:
              - image: "registry.acme.io/*"

Layer 6: Admission Control and Policy

Admission controllers are the last gate before anything runs. Use policy engines to enforce your security rules:

  • Kyverno: Kubernetes-native policies, easy to write.
  • OPA Gatekeeper: Rego policies, more powerful, steeper learning curve.
  • ValidatingAdmissionPolicies: built-in, no extra components.

Enforce: no privileged containers, no hostPath mounts, no latest tags, no cluster-admin bindings.

Layer 7: Runtime Security

Defense in depth at runtime:

  • Falco: detects anomalous behavior (shell in a container, unexpected file access).
  • Seccomp/AppArmor: restrict syscalls per workload.
  • Read-only root filesystems: prevents writes to the container layer.
  • Resource limits: a runaway container cannot starve the node.

The Audit Checklist

Run this against every cluster:

  • No workload uses cluster-admin
  • Default service accounts disabled where unused
  • Network policies default-deny in place
  • Pod Security restricted enforced
  • Secrets externalized, etcd encrypted
  • Images signed, digests pinned, scanned in CI
  • Admission policies enforce registry and security rules
  • Runtime monitoring (Falco) active
  • RBAC bindings audited regularly
  • kube-bench run against the control plane

Implementation Checklist

  • Start with RBAC least privilege
  • Add default-deny network policies
  • Enforce restricted pod security
  • Move secrets to an external manager
  • Sign, pin, and scan images
  • Add admission policies
  • Deploy runtime monitoring
  • Run kube-bench and fix findings

MatterAI builds frontier AI infrastructure for engineering teams — from inference-optimized models to autonomous coding agents and agentic code reviews.

Explore what we're building:

  • Orbital IDE — Autonomous AI coding agent with background agents and deep codebase memory
  • AI Code Reviews — Agentic pre-commit reviews across GitHub, GitLab, and Bitbucket
  • Axon Models — Frontier-grade reasoning models at 70% lower inference cost

Get started free - https://app.matterai.so


Follow us on X · LinkedIn · GitHub

Share this Guide:

Ship Faster. Ship Safer.

Join thousands of engineering teams using MatterAI to autonomously build, review, and deploy code with enterprise-grade precision.

No credit card requiredSOC 2 Type IISetup in 2 min