CIS Kubernetes Benchmark

Secure configuration guidelines for Kubernetes clusters and workloads

v1.10.0 February 2025

Overview

▶

This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes. It covers both self-managed clusters and managed Kubernetes services (EKS, AKS, GKE). The benchmark addresses control plane components, worker nodes, RBAC policies, pod security, networking, and secrets management.

~220Recommendations
5Sections
2Profile Levels
Applicability: Some recommendations apply only to self-managed clusters, while others are specific to managed services (EKS, AKS, GKE). Each recommendation indicates its applicability scope.
SectionAreaRecommendationsFocus
1Control Plane Components~65API Server, Controller Manager, Scheduler, etcd hardening
2Worker Node Security~35Kubelet config, authentication, file permissions
3Control Plane Configuration~25Authentication, authorization, audit logging
4Policies~60RBAC, pod security standards, network policies, secrets
5Managed Services~35EKS/AKS/GKE specifics, image security, supply chain

Profile Definitions

▶
ProfileDescriptionIntended Use
L1 Level 1 — Base Security Core security settings that should be applied to all Kubernetes clusters. Minimal impact on cluster functionality.
L2 Level 2 — Defense in Depth Advanced security controls for environments requiring stronger security posture. May impose operational overhead.

1 — Control Plane Components

▶

Recommendations for securing Kubernetes control plane components including the API Server, Controller Manager, Scheduler, and etcd.

1.1 API Server

▶
1.1.1 Ensure --anonymous-auth is Set to False (Automated)
L1 Auto
Description

Disable anonymous requests to the API server. When enabled, requests not rejected by other configured authentication methods are treated as anonymous, with a username of system:anonymous and group system:unauthenticated.

Rationale

Anonymous access allows unauthenticated users to query the API server. This can expose cluster metadata and, in worst cases, allow modification of cluster state.

Audit
ps -ef | grep kube-apiserver | grep -- '--anonymous-auth'
# Verify the flag is set to false

# Or check the API server manifest:
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep anonymous-auth
Remediation

Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml and set:

--anonymous-auth=false
CIS Controls
ControlDescriptionIG
3.3Configure Data Access Control ListsIG1
1.1.2 Ensure --token-auth-file is Not Set (Automated)
L1 Auto
Description

Do not use static token-based authentication. The token file-based method stores plaintext credentials and lacks rotation, expiration, or revocation capabilities.

Rationale

Failure to --token-auth-file is Not Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--token-auth-file'
# This flag should NOT be present
Remediation

Remove the --token-auth-file=<filename> argument from the API server configuration. Use OIDC or certificate-based authentication instead.

1.1.3 Ensure --kubelet-https is Enabled (Automated)
L1 Auto
Description

Enable HTTPS connections between the API server and kubelets. TLS encryption protects data in transit between control plane and worker nodes.

Rationale

Without --kubelet-https enabled, the Kubernetes container orchestrator may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.

Audit
ps -ef | grep kube-apiserver | grep -- '--kubelet-https'
# Should be true or not set (defaults to true)
Remediation

Remove the --kubelet-https=false argument if present. The default is true, which is the desired configuration.

1.1.4 Ensure --authorization-mode Does Not Include AlwaysAllow (Automated)
L1 Auto
Description

Do not allow all requests. The API server --authorization-mode should not include AlwaysAllow. Instead, use combinations of Node, RBAC, and Webhook.

Rationale

Failure to --authorization-mode Does Not Include AlwaysAllow may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--authorization-mode'
# Verify it does NOT contain AlwaysAllow
# Expected: --authorization-mode=Node,RBAC
Remediation

Set --authorization-mode=Node,RBAC in the API server configuration.

1.1.5 Ensure --audit-log-path is Set (Automated)
L1 Auto
Description

Enable audit logging by setting the audit log path. Kubernetes audit logs provide a chronological record of API server calls, including authentication, authorization, and request/response details.

Rationale

Failure to --audit-log-path is Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--audit-log-path'
# Verify it is set to a valid path, e.g., /var/log/apiserver/audit.log
Remediation
--audit-log-path=/var/log/apiserver/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
1.1.6 Ensure --insecure-bind-address is Not Set (Automated)
L1 Auto
Description

Do not bind the API server to an insecure address. The insecure port serves HTTP without authentication or authorization and should be disabled entirely.

Rationale

Failure to --insecure-bind-address is Not Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--insecure-bind-address'
# This flag should NOT be present
Remediation

Remove the --insecure-bind-address argument from the API server configuration.

1.1.7 Ensure --profiling is Set to False (Automated)
L1 Auto
Description

Disable profiling on the API server. Profiling data can reveal system and program details that could be exploited.

Rationale

An improperly configured value for --profiling could weaken security controls or allow unintended behavior. Setting this to False ensures the Kubernetes container orchestrator operates within a well-defined security boundary.

Audit
ps -ef | grep kube-apiserver | grep -- '--profiling'
# Verify --profiling=false
Remediation

Set --profiling=false in the API server manifest.

1.1.8 Ensure --service-account-lookup is True (Automated)
L1 Auto
Description

Validate service account tokens. The API server should verify that the service account token exists in etcd before accepting it for authentication.

Rationale

Failure to --service-account-lookup is True may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--service-account-lookup'
# Should be true or not set (defaults to true)
Remediation

Set --service-account-lookup=true in the API server manifest.

1.1.9 Ensure --encryption-provider-config is Set (Manual)
L1 Manual
Description

Encrypt secrets at rest in etcd. Kubernetes supports encrypting Secret resources at rest using an EncryptionConfiguration with providers like aescbc, aesgcm, kms, or secretbox.

Rationale

Failure to --encryption-provider-config is Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--encryption-provider-config'
# Verify flag points to a valid EncryptionConfiguration file

# Check encryption config:
cat /etc/kubernetes/encryption-config.yaml
Remediation
# Create /etc/kubernetes/encryption-config.yaml:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-secret>
      - identity: {}

# Add to API server:
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml
1.1.10 Ensure --tls-cert-file and --tls-private-key-file Are Set (Automated)
L1 Auto
Description

Setup TLS for the API server. All API server traffic should be served over TLS. Ensure both the certificate and private key are configured.

Rationale

Failure to --tls-cert-file and --tls-private-key-file Are Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-apiserver | grep -- '--tls-cert-file'
ps -ef | grep kube-apiserver | grep -- '--tls-private-key-file'
# Both flags should be set to valid file paths
Remediation

Set both --tls-cert-file and --tls-private-key-file to valid certificate and key file paths in the API server manifest.

1.2 Controller Manager

▶
1.2.1 Ensure --profiling is Set to False (Automated)
L1 Auto
Description

Disable profiling on the controller manager. Profiling endpoints expose system metrics and should be disabled in production.

Rationale

An improperly configured value for --profiling could weaken security controls or allow unintended behavior. Setting this to False ensures the Kubernetes container orchestrator operates within a well-defined security boundary.

Audit
ps -ef | grep kube-controller-manager | grep -- '--profiling'
# Verify --profiling=false
Remediation

Set --profiling=false in /etc/kubernetes/manifests/kube-controller-manager.yaml.

1.2.2 Ensure --use-service-account-credentials is True (Automated)
L1 Auto
Description

Use individual service account credentials for each controller. This follows least privilege by giving each controller only the permissions it needs.

Rationale

Failure to --use-service-account-credentials is True may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-controller-manager | grep -- '--use-service-account-credentials'
# Should be set to true
Remediation

Set --use-service-account-credentials=true in the controller manager manifest.

1.2.3 Ensure --service-account-private-key-file is Set (Automated)
L1 Auto
Description

Configure the private key to sign service account tokens. This ensures service account tokens are signed with a dedicated key pair.

Rationale

Failure to --service-account-private-key-file is Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-controller-manager | grep -- '--service-account-private-key-file'
# Should be set to a valid key file path
Remediation

Set --service-account-private-key-file=<path/to/key> in the controller manager manifest.

1.2.4 Ensure --root-ca-file is Set (Automated)
L1 Auto
Description

Allow pods to verify the API server's serving certificate. The root CA file is used to validate the API server's TLS certificate.

Rationale

Failure to --root-ca-file is Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kube-controller-manager | grep -- '--root-ca-file'
# Should be set to the cluster CA certificate
Remediation

Set --root-ca-file=<path/to/ca.pem> in the controller manager manifest.

1.2.5 Ensure --bind-address is Set to 127.0.0.1 (Automated)
L1 Auto
Description

Bind the controller manager to the loopback interface only. This restricts access to the controller manager's HTTPS endpoint.

Rationale

An improperly configured value for --bind-address could weaken security controls or allow unintended behavior. Setting this to 127.0.0.1 ensures the Kubernetes container orchestrator operates within a well-defined security boundary.

Audit
ps -ef | grep kube-controller-manager | grep -- '--bind-address'
# Should be 127.0.0.1
Remediation

Set --bind-address=127.0.0.1 in the controller manager manifest.

1.3 Scheduler

▶
1.3.1 Ensure --profiling is Set to False (Automated)
L1 Auto
Description

Disable profiling on the scheduler. Profiling data can expose sensitive operational details.

Rationale

An improperly configured value for --profiling could weaken security controls or allow unintended behavior. Setting this to False ensures the Kubernetes container orchestrator operates within a well-defined security boundary.

Audit
ps -ef | grep kube-scheduler | grep -- '--profiling'
# Verify --profiling=false
Remediation

Set --profiling=false in /etc/kubernetes/manifests/kube-scheduler.yaml.

1.3.2 Ensure --bind-address is Set to 127.0.0.1 (Automated)
L1 Auto
Description

Bind the scheduler to the loopback interface. This prevents external access to the scheduler's HTTPS endpoint.

Rationale

An improperly configured value for --bind-address could weaken security controls or allow unintended behavior. Setting this to 127.0.0.1 ensures the Kubernetes container orchestrator operates within a well-defined security boundary.

Audit
ps -ef | grep kube-scheduler | grep -- '--bind-address'
# Should be 127.0.0.1
Remediation

Set --bind-address=127.0.0.1 in the scheduler manifest.

1.4 etcd

▶
1.4.1 Ensure --cert-file and --key-file Are Set (Automated)
L1 Auto
Description

Configure TLS encryption for etcd. All client communication to etcd must be encrypted using TLS certificates.

Rationale

Failure to --cert-file and --key-file Are Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep etcd | grep -- '--cert-file'
ps -ef | grep etcd | grep -- '--key-file'
# Both should be set to valid file paths
Remediation

Set --cert-file=<path/to/cert> and --key-file=<path/to/key> in the etcd manifest.

1.4.2 Ensure --client-cert-auth is True (Automated)
L1 Auto
Description

Enable client certificate authentication for etcd. Require all clients (including the API server) to present a valid certificate when connecting.

Rationale

Failure to --client-cert-auth is True may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep etcd | grep -- '--client-cert-auth'
# Should be set to true
Remediation

Set --client-cert-auth=true in the etcd manifest.

1.4.3 Ensure --peer-cert-file and --peer-key-file Are Set (Automated)
L1 Auto
Description

Encrypt etcd peer communication. In multi-node etcd clusters, peer-to-peer traffic should be encrypted with TLS.

Rationale

Failure to --peer-cert-file and --peer-key-file Are Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep etcd | grep -- '--peer-cert-file'
ps -ef | grep etcd | grep -- '--peer-key-file'
# Both should be set
Remediation

Set both --peer-cert-file and --peer-key-file in the etcd manifest to valid certificate and key paths.

1.4.4 Ensure --peer-client-cert-auth is True (Automated)
L1 Auto
Description

Enable peer client certificate authentication. All etcd peers must authenticate using client certificates.

Rationale

Failure to --peer-client-cert-auth is True may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep etcd | grep -- '--peer-client-cert-auth'
# Should be true
Remediation

Set --peer-client-cert-auth=true in the etcd manifest.

2 — Worker Node Security

▶

Recommendations for securing Kubernetes worker nodes, focusing on kubelet configuration, authentication, and file permissions.

2.1 Kubelet Configuration

▶
2.1.1 Ensure --read-only-port is Set to 0 (Automated)
L1 Auto
Description

Disable the kubelet read-only port. The read-only port (default 10255) serves unauthenticated health and metrics endpoints.

Rationale

An improperly configured value for --read-only-port could weaken security controls or allow unintended behavior. Setting this to 0 ensures the Kubernetes container orchestrator operates within a well-defined security boundary.

Audit
ps -ef | grep kubelet | grep -- '--read-only-port'
# Should be 0

# Or check kubelet config:
cat /var/lib/kubelet/config.yaml | grep readOnlyPort
Remediation

Set readOnlyPort: 0 in the kubelet configuration file or --read-only-port=0 as a command-line argument.

2.1.2 Ensure --streaming-connection-idle-timeout Is Not Zero (Automated)
L1 Auto
Description

Do not disable streaming connection timeouts. Setting this to 0 means idle connections remain open indefinitely, wasting resources and increasing attack surface.

Rationale

Failure to --streaming-connection-idle-timeout Is Not Zero may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kubelet | grep -- '--streaming-connection-idle-timeout'
# Should not be 0. Default is 4h.
Remediation

Keep the default value or set streamingConnectionIdleTimeout: 5m in the kubelet config file for tighter timeouts.

2.1.3 Ensure --protect-kernel-defaults is True (Automated)
L1 Auto
Description

Protect tuned kernel parameters. The kubelet should error if kernel parameters differ from its defaults, preventing pods from modifying kernel settings.

Rationale

Failure to --protect-kernel-defaults is True may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
ps -ef | grep kubelet | grep -- '--protect-kernel-defaults'
# Should be true
Remediation

Set protectKernelDefaults: true in the kubelet configuration.

2.1.4 Ensure --event-qps is Set Appropriately (Automated)
L2 Auto
Description

Limit the rate of events the kubelet generates. High event rates can overwhelm the API server and storage.

Rationale

Failure to --event-qps is Set Appropriately may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
cat /var/lib/kubelet/config.yaml | grep eventRecordQPS
# Recommended: 5 (default) or lower
Remediation

Set eventRecordQPS: 5 (or lower) in the kubelet configuration file.

2.2 Kubelet Authentication

▶
2.2.1 Ensure --anonymous-auth is False (Automated)
L1 Auto
Description

Disable anonymous authentication on the kubelet. Anonymous requests should be rejected so that only authenticated principals can interact with the kubelet API.

Rationale

Failure to --anonymous-auth is False may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
cat /var/lib/kubelet/config.yaml | grep -A2 'authentication:'
# anonymous:
#   enabled: false
Remediation
# In kubelet config:
authentication:
  anonymous:
    enabled: false
2.2.2 Ensure --authorization-mode Is Not AlwaysAllow (Automated)
L1 Auto
Description

Enable kubelet authorization by setting the mode to Webhook. This delegates authorization to the API server, enforcing RBAC policies.

Rationale

Failure to --authorization-mode Is Not AlwaysAllow may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
cat /var/lib/kubelet/config.yaml | grep -A1 'authorization:'
# mode: Webhook
Remediation
# In kubelet config:
authorization:
  mode: Webhook
2.2.3 Ensure --client-ca-file is Set (Automated)
L1 Auto
Description

Enable certificate-based kubelet authentication. The client CA file validates client certificates presented to the kubelet.

Rationale

Failure to --client-ca-file is Set may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
cat /var/lib/kubelet/config.yaml | grep 'clientCAFile'
# Should be set to the cluster CA certificate
Remediation
authentication:
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.crt

2.3 Kubelet File Permissions

▶
2.3.1 Ensure kubelet config File Permissions Are 600 (Automated)
L1 Auto
Description

The kubelet configuration file contains security-sensitive parameters. Restrict permissions to prevent unauthorized reads or modifications.

Rationale

Incorrect permissions on kubelet config File could allow unauthorized reading, writing, or execution of critical files. Proper file permissions are a foundational control that prevents privilege escalation and data tampering.

Audit
stat -c %a /var/lib/kubelet/config.yaml
# Should be 600 or more restrictive
Remediation
chmod 600 /var/lib/kubelet/config.yaml
chown root:root /var/lib/kubelet/config.yaml
2.3.2 Ensure kubelet Service File Permissions Are 600 (Automated)
L1 Auto
Description

The kubelet systemd service file defines how the kubelet starts. Restrict permissions to prevent tampering.

Rationale

Incorrect permissions on kubelet Service File could allow unauthorized reading, writing, or execution of critical files. Proper file permissions are a foundational control that prevents privilege escalation and data tampering.

Audit
stat -c %a /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# Should be 600 or more restrictive
Remediation
chmod 600 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
2.3.3 Ensure PKI Directory Permissions Are 600 (Automated)
L1 Auto
Description

Kubernetes PKI certificates and keys must be protected. Incorrect permissions on these files can lead to cluster compromise.

Rationale

Incorrect permissions on PKI Directory could allow unauthorized reading, writing, or execution of critical files. Proper file permissions are a foundational control that prevents privilege escalation and data tampering.

Audit
ls -la /etc/kubernetes/pki/
# All .key files should be 600, .crt files 644 or 600
Remediation
chmod -R 600 /etc/kubernetes/pki/*.key
chmod -R 644 /etc/kubernetes/pki/*.crt
chown -R root:root /etc/kubernetes/pki/

3 — Control Plane Configuration

▶

Recommendations for Kubernetes control plane configuration including authentication, authorization, and audit logging.

3.1 Authentication & Authorization

▶
3.1.1 Ensure Client Certificate Authentication Is Used (Manual)
L1 Manual
Description

Use client certificate authentication for user access to the cluster. Certificate-based auth is more secure than token-based methods and supports rotation.

Rationale

Failure to client Certificate Authentication Is Used may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl config view --raw -o jsonpath='{.users[*].user}'
# Verify client-certificate-data and client-key-data are present
Remediation

Configure client certificates for all human users and service integrations. Use kubeadm to generate certificates or integrate with an external PKI.

3.1.2 Ensure OIDC Authentication Is Configured (Manual)
L2 Manual
Description

Configure OpenID Connect (OIDC) for user authentication. OIDC integrates with identity providers like Azure AD, Okta, or Dex for centralized identity management.

Rationale

Misconfiguration of OIDC Authentication can lead to security gaps that may be exploited by attackers. A properly configured Kubernetes container orchestrator reduces exposure to both known vulnerabilities and configuration drift.

Audit
ps -ef | grep kube-apiserver | grep -- '--oidc-issuer-url'
# Should be set to your identity provider URL
Remediation
--oidc-issuer-url=https://your-idp.example.com
--oidc-client-id=kubernetes
--oidc-username-claim=email
--oidc-groups-claim=groups
3.1.3 Ensure RBAC Is Enabled (Automated)
L1 Auto
Description

Enable Role-Based Access Control. RBAC is the recommended authorization mechanism for Kubernetes, providing fine-grained access control over cluster resources.

Rationale

Without RBAC enabled, the Kubernetes container orchestrator may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.

Audit
ps -ef | grep kube-apiserver | grep -- '--authorization-mode'
# Must include RBAC
kubectl api-versions | grep rbac
Remediation

Ensure --authorization-mode includes RBAC, e.g., --authorization-mode=Node,RBAC.

3.2 Logging & Auditing

▶
3.2.1 Ensure Audit Policy Covers Key Resources (Manual)
L1 Manual
Description

Configure an audit policy that logs access to secrets, configmaps, and other sensitive resources at the Metadata level or above.

Rationale

Failure to audit Policy Covers Key Resources may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
cat /etc/kubernetes/audit-policy.yaml
# Verify rules cover secrets, configmaps, roles, bindings
Remediation
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets", "configmaps"]
  - level: RequestResponse
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  - level: Metadata
    omitStages:
      - RequestReceived
3.2.2 Ensure Audit Logs Are Forwarded to an External System (Manual)
L2 Manual
Description

Forward audit logs to a centralized logging system (e.g., Elasticsearch, Splunk, CloudWatch) for analysis, alerting, and retention beyond local storage limits.

Rationale

Failure to audit Logs Are Forwarded to an External System may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit

Verify audit webhook backend is configured or a log shipping agent (Fluentd, Filebeat) is running on control plane nodes.

Remediation
# Option 1: Audit webhook backend
--audit-webhook-config-file=/etc/kubernetes/audit-webhook.yaml

# Option 2: Deploy Fluentd/Filebeat DaemonSet
# to ship /var/log/apiserver/audit.log

4 — Policies

▶

Recommendations for Kubernetes policies covering RBAC, pod security, network policies, and secrets management.

4.1 RBAC & Service Accounts

▶
4.1.1 Ensure Cluster-Admin Role Is Used Only When Necessary (Manual)
L1 Manual
Description

The cluster-admin ClusterRole grants superuser access. Minimize its use to only essential cluster administrators.

Rationale

Failure to cluster-Admin Role Is Used Only When Necessary may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get clusterrolebindings -o json | jq '.items[] |
  select(.roleRef.name == "cluster-admin") |
  {name: .metadata.name, subjects: .subjects}'
Remediation

Review all cluster-admin bindings and replace with scoped roles where possible. Use kubectl delete clusterrolebinding <name> for unnecessary bindings.

4.1.2 Ensure Service Accounts Do Not Auto-Mount Tokens (Automated)
L1 Auto
Description

Disable automatic mounting of service account tokens in pods that don't need API access. This limits the blast radius if a pod is compromised.

Rationale

Failure to service Accounts Do Not Auto-Mount Tokens may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get serviceaccounts --all-namespaces -o json | jq '.items[] |
  select(.automountServiceAccountToken != false) |
  {namespace: .metadata.namespace, name: .metadata.name}'
Remediation
# Set on the ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
automountServiceAccountToken: false

# Or per-pod:
spec:
  automountServiceAccountToken: false
4.1.3 Ensure Default ServiceAccount Is Not Used (Manual)
L1 Manual
Description

Do not use the default service account in namespaces. Create dedicated service accounts with only the permissions required by the workload.

Rationale

If Default ServiceAccount remains used, it presents an unnecessary risk vector that attackers could exploit. Removing or disabling unused components is a fundamental principle of secure system hardening.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.serviceAccountName == "default" or
         .spec.serviceAccountName == null) |
  {namespace: .metadata.namespace, pod: .metadata.name}'
Remediation

Create dedicated service accounts and assign them to pods. Restrict the default service account by disabling token automounting.

4.1.4 Ensure RBAC Permissions Follow Least Privilege (Manual)
L1 Manual
Description

Review RBAC roles and cluster roles to ensure they follow the principle of least privilege. Avoid wildcard (*) permissions and excessive verbs.

Rationale

Failure to rBAC Permissions Follow Least Privilege may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
# Find roles with wildcard access:
kubectl get roles,clusterroles --all-namespaces -o json | jq '.items[] |
  select(.rules[]?.resources[]? == "*" or .rules[]?.verbs[]? == "*") |
  {kind: .kind, name: .metadata.name}'
Remediation

Replace wildcard permissions with explicit resource and verb lists. Scope roles to specific namespaces rather than using cluster-wide ClusterRoles.

4.2 Pod Security

▶
4.2.1 Ensure Pod Security Admission Is Configured (Manual)
L1 Manual
Description

Configure Pod Security Admission (PSA) to enforce pod security standards. PSA replaced PodSecurityPolicy (PSP) in Kubernetes 1.25+.

Rationale

Misconfiguration of Pod Security Admission can lead to security gaps that may be exploited by attackers. A properly configured Kubernetes container orchestrator reduces exposure to both known vulnerabilities and configuration drift.

Audit
# Check namespace labels:
kubectl get namespaces -o json | jq '.items[] |
  {name: .metadata.name,
   enforce: .metadata.labels["pod-security.kubernetes.io/enforce"],
   warn: .metadata.labels["pod-security.kubernetes.io/warn"]}'
Remediation
# Apply PSA labels to namespaces:
kubectl label ns my-namespace \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/audit=restricted
4.2.2 Ensure Privileged Containers Are Not Used (Automated)
L1 Auto
Description

Do not run containers in privileged mode. Privileged containers have unrestricted access to the host's resources and kernel capabilities.

Rationale

If Privileged Containers remains used, it presents an unnecessary risk vector that attackers could exploit. Removing or disabling unused components is a fundamental principle of secure system hardening.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.containers[]?.securityContext?.privileged == true) |
  {namespace: .metadata.namespace, pod: .metadata.name}'
Remediation
securityContext:
  privileged: false
  allowPrivilegeEscalation: false
4.2.3 Ensure Containers Run as Non-Root (Automated)
L1 Auto
Description

Require containers to run as a non-root user. Running as root inside a container increases the risk of container breakout vulnerabilities.

Rationale

Failure to containers Run as Non-Root may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.securityContext?.runAsNonRoot != true and
         (.spec.containers[]?.securityContext?.runAsNonRoot != true)) |
  {namespace: .metadata.namespace, pod: .metadata.name}'
Remediation
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
4.2.4 Ensure Containers Have Read-Only Root Filesystem (Automated)
L2 Auto
Description

Mount the container's root filesystem as read-only. This prevents malicious processes from writing to the filesystem and reduces attack surface.

Rationale

Failure to containers Have Read-Only Root Filesystem may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.containers[]?.securityContext?.readOnlyRootFilesystem != true) |
  {namespace: .metadata.namespace, pod: .metadata.name}'
Remediation
securityContext:
  readOnlyRootFilesystem: true
# Use emptyDir volumes for writable paths:
volumeMounts:
  - name: tmp
    mountPath: /tmp
volumes:
  - name: tmp
    emptyDir: {}
4.2.5 Ensure Containers Drop All Capabilities (Automated)
L1 Auto
Description

Drop all Linux capabilities and only add back those explicitly needed. Containers run with a default capability set that is broader than necessary.

Rationale

Failure to containers Drop All Capabilities may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.containers[]? |
    (.securityContext?.capabilities?.drop // []) | (. | map(ascii_downcase) | contains(["all"]) | not)) |
  {namespace: .metadata.namespace, pod: .metadata.name}'
Remediation
securityContext:
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE  # only if needed

4.3 Network Policies

▶
4.3.1 Ensure Default Deny Network Policies Exist (Manual)
L1 Manual
Description

Create default deny NetworkPolicies for ingress and egress in every namespace. By default, Kubernetes allows all pod-to-pod traffic.

Rationale

The absence of Default Deny Network Policies leaves the Kubernetes container orchestrator without an important security control. Verifying its presence ensures the system meets the minimum security baseline required by the CIS benchmark.

Audit
# Check for default deny policies:
kubectl get networkpolicies --all-namespaces -o json | jq '.items[] |
  select(.spec.podSelector == {} and
         (.spec.policyTypes // [] | contains(["Ingress"]))) |
  {namespace: .metadata.namespace, name: .metadata.name}'
Remediation
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: my-namespace
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
4.3.2 Ensure CNI Plugin Supports Network Policies (Manual)
L1 Manual
Description

Use a CNI plugin that enforces NetworkPolicies. Not all CNI plugins (e.g., Flannel) support network policies. Use Calico, Cilium, or Weave Net.

Rationale

Failure to cNI Plugin Supports Network Policies may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
# Check installed CNI:
ls /etc/cni/net.d/
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave'
Remediation

Install a CNI plugin that supports NetworkPolicies. Recommended: Calico, Cilium, or Weave Net.

4.4 Secrets Management

▶
4.4.1 Ensure Secrets Are Encrypted at Rest (Manual)
L1 Manual
Description

Enable encryption at rest for Kubernetes Secrets stored in etcd. By default, Secrets are stored as base64-encoded plaintext in etcd.

Rationale

Without encryption, Secrets may transmit or store sensitive information in cleartext, exposing it to interception, eavesdropping, or tampering. Encryption is a critical control for data confidentiality and integrity.

Audit
# Verify encryption provider is configured:
ps -ef | grep kube-apiserver | grep -- '--encryption-provider-config'

# Verify a secret is actually encrypted:
ETCDCTL_API=3 etcdctl get /registry/secrets/default/my-secret \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key | hexdump -C | head
# Should show encrypted (not plaintext) data
Remediation

Configure the EncryptionConfiguration as described in recommendation 1.1.9.

4.4.2 Ensure Secrets Are Not Stored in Environment Variables (Manual)
L2 Manual
Description

Prefer volume mounts over environment variables for secrets. Environment variables are visible in process listings and crash dumps, while volume-mounted secrets can be updated without pod restart.

Rationale

Failure to secrets Are Not Stored in Environment Variables may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.containers[]?.env[]?.valueFrom?.secretKeyRef != null) |
  {namespace: .metadata.namespace, pod: .metadata.name}'
Remediation
# Mount secrets as volumes instead:
volumes:
  - name: db-creds
    secret:
      secretName: db-credentials
containers:
  - volumeMounts:
      - name: db-creds
        mountPath: /etc/secrets
        readOnly: true
4.4.3 Consider External Secrets Management (Manual)
L2 Manual
Description

Consider using an external secrets manager (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) with the External Secrets Operator or Secrets Store CSI Driver for enhanced secrets lifecycle management.

Rationale

Implementing this recommendation reduces the risk of security compromise on the Kubernetes container orchestrator. Unaddressed configuration weaknesses are frequently targeted by attackers during both automated scans and manual penetration testing.

Audit
# Check for external secrets operator:
kubectl get pods -n external-secrets
# Or secrets store CSI driver:
kubectl get csidrivers | grep secrets-store
Remediation

Deploy the External Secrets Operator or the Secrets Store CSI Driver and configure it with your cloud provider's secrets management service.

5 — Managed Services

▶

Recommendations specific to managed Kubernetes services (EKS, AKS, GKE) and container image security.

5.1 EKS / AKS / GKE Specifics

▶
5.1.1 Ensure Cluster Endpoint Is Not Publicly Accessible (Manual)
L1 Manual
Description

Restrict the Kubernetes API endpoint to private networks. Public API endpoints expose the cluster to internet-based attacks.

Rationale

Failure to cluster Endpoint Is Not Publicly Accessible may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
# EKS:
aws eks describe-cluster --name my-cluster \
  --query 'cluster.resourcesVpcConfig.endpointPublicAccess'

# AKS:
az aks show -g myRG -n myAKS --query 'apiServerAccessProfile'

# GKE:
gcloud container clusters describe my-cluster \
  --format='value(privateClusterConfig.enablePrivateEndpoint)'
Remediation

Disable public endpoint access and use a private endpoint with VPN or bastion host access.

5.1.2 Ensure Cluster Nodes Are in Private Subnets (Manual)
L1 Manual
Description

Deploy worker nodes in private subnets without direct internet access. Use NAT gateways for outbound connectivity.

Rationale

Failure to cluster Nodes Are in Private Subnets may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit

Verify that node subnets do not have public IP auto-assignment and use NAT gateways for internet access.

Remediation

Configure the managed cluster to use private subnets for node groups with NAT gateway for outbound traffic.

5.1.3 Ensure Managed Node Auto-Upgrade Is Enabled (Manual)
L1 Manual
Description

Enable automatic node upgrades to ensure security patches are applied promptly. All major managed services support automatic minor version and patch upgrades.

Rationale

Without Managed Node Auto-Upgrade enabled, the Kubernetes container orchestrator may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.

Audit
# EKS: Check managed node group update config
aws eks describe-nodegroup --cluster-name my-cluster --nodegroup-name my-ng

# AKS:
az aks show -g myRG -n myAKS --query 'autoUpgradeProfile'

# GKE:
gcloud container clusters describe my-cluster \
  --format='value(autoupgrade)'
Remediation

Enable auto-upgrade in the managed node group configuration.

5.1.4 Ensure Control Plane Logging Is Enabled (Automated)
L1 Auto
Description

Enable control plane logging for API server, authenticator, controller manager, and scheduler. This provides visibility into cluster operations.

Rationale

Without Control Plane Logging enabled, the Kubernetes container orchestrator may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.

Audit
# EKS:
aws eks describe-cluster --name my-cluster \
  --query 'cluster.logging.clusterLogging'

# AKS:
az monitor diagnostic-settings list --resource $AKS_ID

# GKE:
gcloud container clusters describe my-cluster \
  --format='value(loggingConfig)'
Remediation

Enable all control plane log types: api, audit, authenticator, controllerManager, scheduler.

5.2 Image Security

▶
5.2.1 Ensure Container Images Are From Trusted Registries (Manual)
L1 Manual
Description

Only deploy container images from trusted registries. Use admission controllers to enforce image source policies.

Rationale

Failure to container Images Are From Trusted Registries may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  {namespace: .metadata.namespace, pod: .metadata.name,
   images: [.spec.containers[].image]}'
# Verify all images are from approved registries
Remediation

Use OPA/Gatekeeper, Kyverno, or cloud-native admission controllers (ImagePolicyWebhook) to restrict image sources to approved registries.

5.2.2 Ensure Container Images Are Scanned for Vulnerabilities (Manual)
L1 Manual
Description

Scan all container images for known vulnerabilities before deployment. Integrate scanning into CI/CD pipelines and use admission controllers to block vulnerable images.

Rationale

Failure to container Images Are Scanned for Vulnerabilities may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit

Verify that image scanning is integrated into CI/CD pipelines and an admission controller blocks images with critical/high vulnerabilities.

Remediation

Use Trivy, Grype, Snyk, or your registry's built-in scanner (ECR scanning, ACR scanning, GCR scanning). Add scanning to CI/CD and use admission controllers to enforce.

5.2.3 Ensure Image Tags Are Not Mutable (Manual)
L1 Manual
Description

Use image digests or immutable tags instead of mutable tags like :latest. Mutable tags can change without notice, making deployments non-reproducible.

Rationale

Failure to image Tags Are Not Mutable may leave the Kubernetes container orchestrator vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.

Audit
kubectl get pods --all-namespaces -o json | jq '.items[] |
  select(.spec.containers[]?.image | test(":latest$") or (test("@sha256:") | not)) |
  {namespace: .metadata.namespace, pod: .metadata.name,
   images: [.spec.containers[].image]}'
Remediation
# Use digest references:
image: myregistry.io/app@sha256:abc123...

# Or use imagePullPolicy: Always is NOT sufficient
# Enable tag immutability in your registry