Tutorial

Kubernetes Security Compliance Best Practices

Ethan Troy
by  Ethan Troy · on
KubernetesSecurity
Learn essential Kubernetes security compliance standards, use tools to scan your cluster for vulnerabilities, and implement practical security measures to protect your containerized workloads.

Kubernetes Security Compliance Best Practices

Kubernetes has become the de-facto standard for container orchestration, but its complex nature creates a wide attack surface. This tutorial will guide you through essential security compliance standards and teach you how to implement practical security measures to protect your containerized workloads.

Understanding Kubernetes Security Compliance Standards

Kubernetes security compliance involves adhering to industry standards and best practices to ensure your clusters are protected against threats. Several key frameworks provide guidance:

Kubernetes security compliance framework overview

Major security compliance frameworks for Kubernetes environments

Key Security Frameworks for Kubernetes

  • CIS Kubernetes Benchmark - Security configuration best practices developed by the Center for Internet Security
  • NIST SP 800-190 - Application Container Security Guide from the National Institute of Standards and Technology
  • MITRE ATT&CK for Containers - Tactics and techniques used by adversaries targeting containerized environments
  • Kubernetes Pod Security Standards - Built-in Kubernetes security controls (replacing Pod Security Policies)

CIS Kubernetes Benchmark Scanning

The CIS Kubernetes Benchmark provides configuration guidelines for securing Kubernetes components. Let's use kube-bench to scan our cluster against these standards.

Running a CIS Benchmark Scan with kube-bench

Run the following command to scan the master node components:

kube-bench run --targets=master --benchmark cis-1.23

You'll see results similar to:

[INFO] 1 Control Plane Security Configuration
[PASS] 1.1.1 Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)
[FAIL] 1.1.2 Ensure that the API server pod specification file ownership is set to root:root (Automated)
...
Note

kube-bench automatically detects your Kubernetes version and applies the appropriate CIS benchmark tests. The scan results indicate which configurations pass or fail the security recommendations.

Understanding and Remediating Findings

Let's review the major categories of CIS Benchmark findings:

  1. Control Plane Security - Configurations for API server, controller manager, scheduler
  2. Worker Node Security - Kubelet and container runtime configurations
  3. Policies - Network policies, RBAC, and service accounts
  4. Authentication and Authorization - Secure access to the API server
Common remediation steps for CIS findings
  • API Server Security:
    --anonymous-auth=false
    --authorization-mode=RBAC
    --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
    
  • Kubelet Security:
    --anonymous-auth=false
    --authorization-mode=Webhook
    --protect-kernel-defaults=true
    
  • ETCD Security:
    --client-cert-auth=true
    --peer-client-cert-auth=true
    --auto-tls=false
    

Image Vulnerability Scanning

Container images may contain vulnerable packages that attackers can exploit. Let's use Trivy to scan images for vulnerabilities.

Scanning the Container Image

Run a scan on the vulnerable deployment we created:

trivy image nginx:1.14.2

The output shows detected vulnerabilities categorized by severity:

2025-03-30T12:34:56.789Z        INFO    Number of language-specific files: 0
2025-03-30T12:34:56.789Z        INFO    Detecting OS vulnerabilities...
2025-03-30T12:34:56.789Z        INFO    Detected OS: debian
2025-03-30T12:34:56.789Z        WARN    This OS version is no longer supported by the distribution: debian 9.6
2025-03-30T12:34:56.789Z        WARN    The vulnerability detection may be insufficient because security updates are not provided

nginx:1.14.2 (debian 9.6)

Total: 152 (UNKNOWN: 0, LOW: 20, MEDIUM: 82, HIGH: 43, CRITICAL: 7)
...
Important

The older nginx:1.14.2 image contains numerous vulnerabilities. In production, you should use up-to-date images with security patches applied.

Implementing a Secure Image Policy

To enforce secure container images, you can:

  1. Use trusted base images with minimal attack surface
  2. Implement a CI/CD pipeline that scans images before deployment
  3. Use admission controllers like OPA Gatekeeper to enforce image policies

Here's an example policy that requires images to be from a trusted registry:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sTrustedImages
metadata:
  name: trusted-images
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces: ["default"]
  parameters:
    repositories:
      - "gcr.io/my-project"
      - "docker.io/library/nginx"

Kubernetes Resource Security Auditing

Let's audit our cluster resources for security issues using kubeaudit:

kubeaudit all -n default

You might see output like:

ERRO[0000] Container 'nginx' of deployment 'vulnerable-app' is running as root
     -> KubeAuditInfo[default/vulnerable-app-74d6b5b989/nginx]

ERRO[0000] Container 'nginx' of deployment 'vulnerable-app' is privileged
     -> KubeAuditInfo[default/vulnerable-app-74d6b5b989/nginx]

ERRO[0000] Pod uses the host network, which gives the pod access to the loopback device and services listening on localhost of the host
     -> KubeAuditInfo[default/vulnerable-app-74d6b5b989]

Common Security Issues and Remediation

Let's fix the security issues in our vulnerable deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        securityContext:
          privileged: false
          runAsNonRoot: true
          runAsUser: 1000
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
        resources:
          limits:
            cpu: "0.5"
            memory: "512Mi"
          requests:
            cpu: "0.2"
            memory: "256Mi"
      securityContext:
        runAsUser: 1000
        runAsGroup: 3000
        fsGroup: 2000
Note

The secure deployment addresses multiple security issues:

  1. Uses non-root user (1000)
  2. Disables privileged mode
  3. Drops all Linux capabilities
  4. Prevents privilege escalation
  5. Doesn't use host namespaces

Implementing Pod Security Standards

Kubernetes v1.25+ replaced Pod Security Policies with Pod Security Standards. The three security levels are:

  1. Privileged - Unrestricted policy with no security controls
  2. Baseline - Minimally restrictive policy that prevents known privilege escalation
  3. Restricted - Heavily restricted policy following security best practices

Let's create a namespace with the restricted profile:

kubectl create namespace secure-workloads

kubectl label --overwrite ns secure-workloads \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/audit=restricted

Now let's try to deploy our vulnerable workload to this namespace:

kubectl apply -f /tmp/vulnerable-deployment.yaml -n secure-workloads

You'll see an error because the Pod doesn't meet the restricted security requirements:

Error from server (Forbidden): error when creating "/tmp/vulnerable-deployment.yaml": pods "vulnerable-app" is forbidden: violates PodSecurity "restricted:latest": privileged (container "nginx" must not set securityContext.privileged=true), hostNetwork (pod must not set spec.hostNetwork=true), hostProcess (pod must not set spec.hostProcess=true)

Network Security with Network Policies

By default, Kubernetes allows all pods to communicate with each other. Let's create a network policy to restrict traffic:

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

This policy denies all traffic to and from pods in the default namespace. Now let's create a more granular policy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-nginx
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: secure-app
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 80

This allows only pods with the label role: frontend to access our secure-app pods on port 80.

RBAC and Service Account Security

Role-Based Access Control (RBAC) is essential for limiting access to Kubernetes resources. Let's create a restricted service account:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: restricted-sa
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: ServiceAccount
  name: restricted-sa
  namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

This creates a service account that can only read pods in the default namespace.

Important

Never use overly permissive service accounts, especially for production workloads. Always apply the principle of least privilege.

Security Compliance Checklist

Use this checklist to ensure your Kubernetes clusters meet security compliance requirements:

  1. ✅ Run CIS Benchmark scans regularly
  2. ✅ Scan all container images for vulnerabilities
  3. ✅ Implement Pod Security Standards
  4. ✅ Use Network Policies to restrict traffic
  5. ✅ Configure RBAC with least privilege principles
  6. ✅ Encrypt sensitive data using Secrets and encryption
  7. ✅ Implement strong authentication methods
  8. ✅ Enable audit logging for all cluster activities
  9. ✅ Use admission controllers to enforce security policies
  10. ✅ Perform regular security assessments and penetration tests

Conclusion

Kubernetes security compliance requires a multi-layered approach addressing various aspects of the container ecosystem. By implementing the techniques covered in this tutorial, you can significantly improve your cluster's security posture.

Remember that security is a continuous process, not a one-time task. Regularly review and update your security measures as new vulnerabilities and threats emerge.

For additional resources, check out:

About the Author

Ethan Troy

Ethan Troy

hacking, go, rust, ai | research & dev

Find this author online

More tutorials you might like

Native SSH Access with Pomerium (cover image)

Native SSH Access with Pomerium

Pomerium can be used as a native SSH reverse proxy, adding OAuth authentication and flexible Pomerium policy enforcement to standard SSH connections, without the need for tunnels, or custom clients or servers.

Native SSH Reverse Tunneling with Pomerium (cover image)

Native SSH Reverse Tunneling with Pomerium

Use Pomerium's native SSH support to publish a local service through a standard reverse SSH tunnel, with OpenID Connect (OIDC) authentication and continuous authorization on every request. Reach services behind Network Address Translation (NAT) without firewall holes or custom agents, and control both who can use the service and who can open the tunnel. Application traffic stays on infrastructure you control.

Secure Machine-to-Machine Access with mTLS and Pomerium (cover image)

Secure Machine-to-Machine Access with mTLS and Pomerium

Run a GitHub Actions-compatible continuous integration (CI) job on a private runner and protect its internal API call with mutual TLS (mTLS) and Pomerium. Build separate server and client trust chains, authorize one machine certificate by fingerprint, then revoke, restore, and rotate its credentials through live policy changes.

Harden Access to OpenClaw with Pomerium (cover image)

Harden Access to OpenClaw with Pomerium

Put OpenClaw, a self-hosted AI assistant with shell and file access, behind a web route and an SSH route, both gated by the same identity and Pomerium's context-aware policy. OpenClaw runs in trusted-proxy mode, trusting signed identity headers instead of its own login, while Pomerium's native SSH proxy signs short-lived certificates for shell access.

Learn by doing, not just by reading or watching

Sign up for a free account to start a VM playground right on this page, track your progress, and get notified about new learning materials.

Sign up for free