Client Certificate Authentication Should Not Be Used For Users
More Info:
Kubernetes provides the option to use client certificates for user authentication. However as there is no way to revoke these certificates when a user leaves an organization or loses their credential, they are not suitable for this purpose. It is not possible to fully disable client certificate use within a cluster as it is used for component to component authentication.
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify all client-certificate-based user configs on admin machines (evidence gathering)
- On any machine with kubectl access, search typical kubeconfig locations for client-certificate auth (non-service-account):
grep -RInE "client-certificate:|client-certificate-data:" \$HOME/.kube /etc/kubernetes/admin.conf /etc/kubernetes/controller-manager.conf \/etc/kubernetes/scheduler.conf 2>/dev/null
- For each kubeconfig found, list users and auth methods:
KUBECONFIG=$HOME/.kube/config kubectl config view --minify=false --raw
- Decision: treat any context where
userhasclient-certificate/client-certificate-dataand is used by a human admin/script (not a core control-plane component) as non-compliant.
- On any machine with kubectl access, search typical kubeconfig locations for client-certificate auth (non-service-account):
-
Confirm which client-cert identities have cluster privileges
- On any machine with kubectl access, list ClusterRoleBindings/RoleBindings that reference
Usersubjects (these may be backed by client certs):kubectl get clusterrolebindings -o yaml | grep -B5 -A5 "kind: User"kubectl get rolebindings --all-namespaces -o yaml | grep -B5 -A5 "kind: User" - For each
Usersubject, note whether that identity corresponds to a client certificate user from kubeconfig. - Decision: if such users are humans or automation that could instead use OIDC or another revocable mechanism, mark them for migration.
- On any machine with kubectl access, list ClusterRoleBindings/RoleBindings that reference
-
Design and enable an alternative auth mechanism (e.g., OIDC) on every control plane node
- On every control plane node, review the current API server flags to see if OIDC (or another centralized identity provider) is already configured:
ps -eo args | grep kube-apiserver | grep -v grep
- If OIDC is not enabled, follow your organization’s identity design to add the appropriate
--oidc-*flags (issuer-url, client-id, etc.) to the kube-apiserver manifest, usually at:
/etc/kubernetes/manifests/kube-apiserver.yaml- Editing this static pod manifest will restart the API server on that node.
- Decision: only proceed once a revocable and centrally managed authentication method is configured and tested.
- On every control plane node, review the current API server flags to see if OIDC (or another centralized identity provider) is already configured:
-
Migrate human and automation users from client certs to OIDC (or chosen mechanism)
- On any machine with kubectl access, for each non-compliant user:
- Create or identify the corresponding OIDC identity (subject/claim) in your IdP.
- Create/update Kubernetes
RoleBinding/ClusterRoleBindingto grant the same roles to the newUser/Groupas identified by OIDC claims. Example (adapt to your IdP and roles):kubectl apply -f - <<'EOF'apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: oidc-adminssubjects:- kind: Groupname: your-oidc-admin-grouproleRef:kind: ClusterRolename: cluster-adminapiGroup: rbac.authorization.k8s.ioEOF
- Update kubeconfig used by each human/automation to use OIDC auth (e.g., via an exec plugin or cloud CLI) instead of client certificate fields.
- On any machine with kubectl access, for each non-compliant user:
-
Remove or de-privilege client-certificate users once migration is confirmed
- On any machine with kubectl access, after verifying affected users can authenticate and operate via OIDC:
- Remove or adjust RBAC bindings that reference the old client-cert
Useridentities:# Example: delete a specific ClusterRoleBindingkubectl delete clusterrolebinding <old-client-cert-crb-name> - Optionally, revoke or delete the issuing CA or intermediate used solely for those user client certs in your PKI system (outside the cluster), ensuring it does not impact component-to-component certs.
- Remove or adjust RBAC bindings that reference the old client-cert
- On admin machines, clean up outdated kubeconfigs that still contain
client-certificatefor humans or automation:sed -i.bak '/client-certificate-data:/d;/client-key-data:/d;/client-certificate:/d;/client-key:/d' $HOME/.kube/config
- On any machine with kubectl access, after verifying affected users can authenticate and operate via OIDC:
-
Verify that client certificate authentication is no longer used for users (only components)
- On any machine with kubectl access, re-check kubeconfigs:
Ensure only control-plane/component configs (e.g.,grep -RInE "client-certificate:|client-certificate-data:" \$HOME/.kube /etc/kubernetes/admin.conf /etc/kubernetes/controller-manager.conf \/etc/kubernetes/scheduler.conf 2>/dev/null
kube-apiserver,kube-controller-manager,kube-scheduler,kubelet) use client certs. - Confirm RBAC no longer grants roles to user identities that are only accessible via client certs by re-running:
and ensuring any remainingkubectl get clusterrolebindings -o yaml | grep -B5 -A5 "kind: User"kubectl get rolebindings --all-namespaces -o yaml | grep -B5 -A5 "kind: User"
Usersubjects correspond only to component identities or identities authenticated via your new mechanism.
- On any machine with kubectl access, re-check kubeconfigs:
Using kubectl
kubectl cannot modify client certificate authentication for users because this is controlled by host-level configuration and API server flags on every control plane node. Make the necessary changes directly on those nodes as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Purpose:
# Enumerate where client-certificate authentication is used for *users*
# (as opposed to internal components), so it can be reviewed and phased
# out in favor of OIDC or other revocable mechanisms.
#
# Requirements:
# - Run on any machine with kubectl and (optionally) openssl/jq
# - KUBECONFIG configured with access to the cluster
set -euo pipefail
echo "=== 1) kubectl user identities (from current kubeconfig) ==="
# Machine: any machine with kubectl access
kubectl config view --flatten --output='jsonpath={.users[*].name}' | tr ' ' '\n' | sort -u | sed '/^$/d' || true
echo
echo "For each user above, inspect its auth mechanism:"
echo
# Show full users section so you can see client-certificate-data / client-key-data use
kubectl config view --flatten -o json | jq '.users' 2>/dev/null || kubectl config view --flatten
cat <<'EOF'
Interpretation:
- Any user entry that has fields like:
"client-certificate": "path/to/cert"
"client-key": "path/to/key"
or:
"client-certificate-data": "BASE64..."
"client-key-data": "BASE64..."
is using client certificate authentication.
- These are *suspect* for this control if they represent human users rather than components
(e.g. "alice", "devops-admin", "ci-bot" vs "kubernetes-admin", "system:admin", or node identities).
Action:
- Flag human/long‑lived users that rely on client certs and plan migration to OIDC or another
revocable method.
EOF
echo "=== 2) Detect client‑certificate auth in kubeconfig used by common automation accounts ==="
echo "Checking for client-certificate usage in typical locations (~/.kube/config, KUBECONFIG)..."
echo
for cfg in "$HOME/.kube/config" ${KUBECONFIG:-}; do
[ -f "$cfg" ] || continue
echo "---- $cfg ----"
if grep -E 'client-certificate|client-certificate-data' "$cfg" >/dev/null 2>&1; then
echo "POTENTIAL PROBLEM: client-certificate auth is in use in this kubeconfig."
grep -nE 'name:|user:|client-certificate|client-certificate-data' "$cfg" | sed 's/^/ /'
else
echo "OK: no client-certificate fields found in this kubeconfig (may be using tokens/OIDC)."
fi
echo
done
cat <<'EOF'
Interpretation:
- Lines under a user that reference client-certificate / client-certificate-data indicate use
of client cert auth. If those users are humans or long-lived service accounts, they are
non-compliant with this control.
- Kubeconfigs that use:
- exec: plugins (e.g. aws-iam-authenticator, gcloud, az) or
- id-token / access-token / auth-provider: oidc
are generally OK for this control.
EOF
echo "=== 3) Identify client‑certificate usage from apiserver audit logs (if available) ==="
echo "NOTE: This is optional and depends on audit logging configuration and log access."
echo " Run the following on every control plane node that has API server audit logs:"
cat <<'EOF'
# On every control plane node (adjust paths to your environment):
AUDIT_DIR="/var/log/kubernetes/audit" # or /var/log/kube-apiserver, /var/log/apiserver, etc.
LOG_FILE_PATTERN="*.log"
# Example grep to show client certificate subjects seen by the apiserver:
sudo find "$AUDIT_DIR" -name "$LOG_FILE_PATTERN" -type f -print0 2>/dev/null | \
xargs -0 sudo grep -Eo '"user":{"username":"[^"]+","groups":\[[^]]*\],"extra":\{[^}]*"authentication.kubernetes.io/x509name":"[^"]+"' | \
sed 's/.*"username":"\([^"]\+\)".*"authentication.kubernetes.io\/x509name":"\([^"]\+\)".*/USERNAME=\1 X509_SUBJECT=\2/' | \
sort -u
EOF
cat <<'EOF'
Interpretation:
- Any USERNAME/X509_SUBJECT pairs you see there are identities that authenticated
with an X.509 client certificate.
- If those usernames correspond to human or long‑lived users (as opposed to
system: nodes, controllers, or internal components), they are in scope for this finding.
EOF
echo "=== 4) Summary: what indicates a problem? ==="
cat <<'EOF'
You have a *problem* for this control when:
- A human user or long‑lived non‑system identity (e.g. "alice", "team-admin",
"jenkins-prod") in kubeconfig or in audit logs is authenticated via a client
certificate (client-certificate / client-certificate-data).
You are *aligned* with the control when:
- Humans and long‑lived identities authenticate using OIDC or another revocable
mechanism (tokens tied to IdP or short‑lived cloud IAM credentials), and
- Client certificate authentication is only used for internal Kubernetes
components where it cannot be disabled.
This script does not and cannot automatically fix the issue; it only surfaces
where client certificate auth is being used so you can plan migration to OIDC
or another revocable mechanism per the benchmark guidance.
EOF