Skip to content
Back to Blog
Security11 min read

Kubernetes Security Hardening: 8 Critical Fixes for Beginners

Lock down your first Kubernetes cluster with eight practical fixes that protect against common attacks—no prior container experience required.

Written by Abdul AbrorTechnical Hosting Support Engineer
Kubernetes Security Hardening: 8 Critical Fixes for Beginners
On this page

Kubernetes is the orchestration layer that runs containerized applications across many machines. If you're hosting apps in containers—whether for clients or your own infrastructure—you need to lock down the cluster before anything goes to production. Most default Kubernetes installs leave the front door open.

This guide walks you through eight security fixes that close the most dangerous gaps. We define every term as we go and show working commands you can run today.

What is Kubernetes and why does it need hardening?

Kubernetes (often shortened to K8s) schedules Docker or containerd containers across worker nodes, manages networking between them, and restarts failed pods automatically. A pod is the smallest unit—one or more containers that share storage and network. A node is a physical or virtual machine running the Kubernetes agent.

Out of the box, Kubernetes trusts everything inside the cluster. Any pod can talk to any other pod. The API server often allows anonymous requests. Container images run as root. That trust model works in a lab but becomes a liability the moment you expose a service to the internet or run untrusted workloads.

In support tickets I handled, the usual entry point was either an exposed API server with weak authentication or a container breakout through a privileged pod. Both are preventable.

Fix 1: Disable anonymous API access

The Kubernetes API server is the control plane. Every kubectl command, every pod creation, every service update flows through it. By default, many distributions enable anonymous authentication so you can bootstrap the cluster without certificates.

Check the current setting:

kubectl cluster-info dump | grep anonymous-auth

If you see --anonymous-auth=true, anyone who can reach the API port (usually 6443) can query cluster metadata. Disable it by editing the API server manifest. On most installs that file lives at /etc/kubernetes/manifests/kube-apiserver.yaml.

Add or change this line under spec.containers[0].command:

- --anonymous-auth=false

The kubelet will restart the API server pod automatically. Verify:

curl -k https://your-api-server:6443/version

You should see Unauthorized instead of version JSON. Good.

Fix 2: Enforce role-based access control (RBAC)

RBAC is Kubernetes' permission system. A Role defines what actions (get, list, create, delete) are allowed on which resources (pods, secrets, services). A RoleBinding ties that Role to a user or service account.

Without RBAC, any authenticated entity can do anything. With RBAC, you grant the minimum permission needed.

First confirm RBAC is enabled:

kubectl api-versions | grep rbac

You should see rbac.authorization.k8s.io/v1. If not, add --authorization-mode=RBAC to your API server manifest and restart.

Create a read-only role for developers who need to view logs but not modify deployments:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: log-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]

Bind it to a user:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-logs
  namespace: production
subjects:
- kind: User
  name: alice
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: log-reader
  apiGroup: rbac.authorization.k8s.io

Apply both:

kubectl apply -f role.yaml -f binding.yaml

Now alice can read logs but cannot delete pods or access secrets. Every service account and human user should have an explicit RBAC policy. Never hand out cluster-admin unless someone truly needs full control.

Fix 3: Drop root privileges in containers

Most container images run as UID 0 (root) by default. If an attacker escapes the container namespace, they land on the host as root. Prevent that by forcing a non-root user.

In your pod spec, add a security context:

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  containers:
  - name: app
    image: myapp:latest
    securityContext:
      allowPrivilegeEscalation: false
      runAsNonRoot: true

runAsNonRoot: true tells Kubernetes to reject the pod if the image would run as UID 0. allowPrivilegeEscalation: false blocks the container from gaining more privileges than its parent process.

If your application legitimately needs to bind to port 80 or 443, use a capability instead of running as root:

    securityContext:
      capabilities:
        add:
        - NET_BIND_SERVICE
        drop:
        - ALL

That grants only the network binding capability and drops everything else. Much safer.

Fix 4: Enable pod security standards

Pod Security Standards (PSS) replaced the older Pod Security Policies in Kubernetes 1.25. PSS defines three levels: Privileged (unrestricted), Baseline (blocks the worst practices), and Restricted (defense in depth).

Apply the Restricted standard to your namespace:

kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

Now any pod that tries to run as root, mount the host filesystem, or use host networking will be rejected. Existing pods are not evicted, but new ones must comply.

Check what would be blocked without enforcing:

kubectl label namespace staging \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

You'll see warnings in the API response but pods will still deploy. Use audit and warn first to find violations, then switch to enforce.

So what if your app needs host access?

Some workloads—log collectors, monitoring agents, CNI plugins—must interact with the host. Put those in a separate namespace with Privileged or Baseline enforcement and lock down everything else.

Fix 5: Isolate pods with network policies

By default, every pod can reach every other pod in the cluster, even across namespaces. An attacker who compromises one pod can pivot to your database, your secret store, your management tools.

Network policies act as firewall rules inside Kubernetes. They require a CNI plugin that supports them—Calico, Cilium, and Weave all do. The default kubenet does not.

Check if your CNI supports network policies by creating a test policy and seeing if it takes effect. Here's a policy that blocks all ingress by default:

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

Apply it:

kubectl apply -f deny-all.yaml

Now nothing can reach pods in the production namespace. Add exceptions for legitimate traffic:

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

This allows only pods labeled app=frontend to reach app=api on port 8080. Everything else is dropped.

Start with deny-all policies in each namespace, then add explicit allow rules for each service dependency. It's tedious but blocks lateral movement cold.

Fix 6: Scan and sign container images

Your cluster is only as secure as the images you run. A compromised base image or a dependency with a known vulnerability gives attackers a foothold.

Scan images before deployment with a tool like Trivy:

trivy image myapp:latest

Trivy checks for known CVEs in OS packages and application dependencies. Fix or replace images with HIGH or CRITICAL findings before pushing them to production.

Enforce signed images with an admission controller. Sigstore's policy-controller or Kyverno can reject unsigned images at admission time:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-image-signature
spec:
  validationFailureAction: enforce
  rules:
  - name: check-signature
    match:
      resources:
        kinds:
        - Pod
    verifyImages:
    - image: "myregistry.example.com/*"
      key: |-
        -----BEGIN PUBLIC KEY-----
        MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
        -----END PUBLIC KEY-----

Now only images signed with your private key will deploy. An attacker who compromises your registry can't inject a backdoored image without the signing key.

Fix 7: Restrict the Kubernetes dashboard

The web-based Kubernetes Dashboard is convenient for browsing resources but dangerous if exposed. Many clusters ship it with a service account that has cluster-admin privileges.

Check if it's installed:

kubectl get pods -n kubernetes-dashboard

If you see a dashboard pod, review its service account permissions:

kubectl describe sa kubernetes-dashboard -n kubernetes-dashboard
kubectl get clusterrolebinding | grep kubernetes-dashboard

If you find a binding to cluster-admin, delete it and create a narrower role. Better yet, expose the dashboard only through kubectl proxy on your local machine, never over the internet:

kubectl proxy

Then access it at http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/. No public IP, no TLS certificate hassles, no risk of credential stuffing.

Fix 8: Audit and monitor API activity

Enable audit logging on the API server so you have a record of every action: who created that pod, who deleted that secret, who tried to escalate privileges.

Create an audit policy file, /etc/kubernetes/audit-policy.yaml:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
  verbs: ["create", "update", "patch", "delete"]
  resources:
  - group: ""
    resources: ["secrets", "configmaps"]
- level: Metadata
  omitStages:
  - RequestReceived

Tell the API server to use it by adding these flags in /etc/kubernetes/manifests/kube-apiserver.yaml:

- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-log-maxage=30
- --audit-log-maxbackup=10
- --audit-log-maxsize=100

Restart the API server. Logs land in /var/log/kubernetes/audit.log in JSON format. Ship them to a SIEM or log aggregator for alerting. Watch for repeated authentication failures, privilege escalation attempts, and secret access by unexpected service accounts.

What to check first

If you walk away with one task, disable anonymous authentication and enable RBAC. Those two changes force every request to prove identity and permission, blocking the most common cluster compromises.

From there, layer on the other fixes as your workloads and team grow. Security is a ratchet—once you enforce a control, leaving it in place costs nothing and every new app benefits.

Kubernetes gives you the primitives to build a secure platform. You just have to turn them on.

FAQ

Do I need all eight fixes or can I pick a few?

Start with anonymous auth disabled, RBAC enabled, and pods running as non-root. Those three stop the easiest attacks. Add network policies and image scanning as you gain confidence.

Can I apply these fixes to a cluster that's already running workloads?

Yes, but test in a staging namespace first. Pod security standards and network policies can break apps that assume unrestricted access. Rolling out RBAC requires mapping every service account and user to a role, which takes time.

What if my CNI doesn't support network policies?

Switch to Calico or Cilium. Both are drop-in replacements for most environments and add minimal overhead. If you're locked into a cloud provider's CNI, check their documentation—most now support policies.

How do I know if an image is safe to run?

Scan it with Trivy or Grype before deployment. Check that the base image is actively maintained and recent. Avoid images from unknown publishers. Sign your own images and enforce signature verification in production.