CKA Cluster User Management Meets CKS Access Control and Audit Logging
The Certified Kubernetes Administrator exam tests whether you can manage a cluster. The Certified Kubernetes Security Specialist exam tests whether you can harden it. On no topic do these two certs overlap more directly than RBAC and audit logging.
CKA scope: create users via the CertificateSigningRequest workflow, bind them to Roles and ClusterRoles, verify their access with kubectl auth can-i, manage kubeconfig files for multi-cluster contexts. CKS scope: audit what those users and ServiceAccounts actually do, identify over-permissioned bindings, write the audit policy YAML, disable ServiceAccount automounting where it is not needed, validate that projected token lifetimes are appropriately short.
The two lenses together reveal the full access-control picture: grant minimum required permissions, then verify what actually happens through the audit trail.
Every request to the Kubernetes cluster passes through the kube-apiserver. The server applies three sequential checks: (1) Authentication — who is making the request? (2) Authorization — may this authenticated subject perform this action? (3) Admission Control — does the request comply with policy?
A 401 means authentication failed. A 403 means authentication succeeded but authorization failed. Admission rejections return 400 or 422 with a policy-specific message.
Poulton (The Kubernetes Book, Ch 13, pp. 179–180) describes RBAC as controlling "who can make what kind of API requests against what resources in which namespaces." That four-part frame maps directly to the RBAC objects: who (subject in a binding), what kind (verbs in a Role), what resource (API groups and resource types), which namespace (scope of the RoleBinding).
Kubernetes has no user API object. A "user" is a client certificate whose Common Name the API server trusts. The CKA exam tests whether you can create one.
openssl genrsa -out alice.key 2048
openssl req -new -key alice.key \
-subj "/CN=alice/O=fleet-ops" \
-out alice.csr
cat alice.csr | base64 | tr -d '\n'
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: alice
spec:
request: <base64-encoded-csr>
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400
usages:
- client auth
kubectl apply -f alice-csr.yaml
kubectl certificate approve alice
kubectl get csr alice -o jsonpath='{.status.certificate}' | base64 -d > alice.crt
The O=fleet-ops field in the CSR subject becomes Group membership. A RoleBinding can reference fleet-ops as its Group subject, binding everyone whose certificate carries that organization to the same ClusterRole.
kubectl config set-credentials alice \
--client-key=alice.key \
--client-certificate=alice.crt \
--embed-certs=true
kubectl config set-context alice-context \
--cluster=prod-cluster \
--user=alice \
--namespace=fleet-ops
kubectl config use-context alice-context
kubectl auth can-i list pods --as=alice
kubectl auth can-i with --as impersonates the user for a dry-run permission check. The exam frequently asks: "verify that user X can Y but cannot Z." This command is the exact tool.
The kube-apiserver does not audit anything without an explicit --audit-policy-file flag. The CKS exam tests whether you can write and apply one. Four verbosity levels: None (no log), Metadata (who/what/when/code only), Request (metadata + request body), RequestResponse (metadata + request + response bodies).
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- "RequestReceived"
rules:
- level: None
resources:
- group: ""
resources: ["events", "endpoints"]
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps", "serviceaccounts"]
verbs: ["get", "list", "watch"]
- level: Request
resources:
- group: ""
resources: ["pods", "services"]
verbs: ["create", "update", "patch", "delete"]
- level: RequestResponse
userGroups: ["system:serviceaccounts"]
verbs: ["create", "update", "patch", "delete"]
To apply to the API server (static Pod manifest at /etc/kubernetes/manifests/kube-apiserver.yaml):
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-log-path=/var/log/kubernetes/audit/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
Every ServiceAccount defaults to automountServiceAccountToken: true. The CKS exam tests whether you know to disable this:
kubectl patch serviceaccount default \
-n fleet-intake \
-p '{"automountServiceAccountToken": false}'
For Pods that need API access, create an explicit ServiceAccount with automount disabled at the SA level, then enable it in the PodSpec. This makes token mounting a visible decision, not an invisible default.
A cluster has a namespace data-pipeline. The Pod processor-pod uses the default ServiceAccount, which has a RoleBinding to cluster-admin left by a developer who needed quick access.
Tasks:
cluster-admin RoleBinding from the default ServiceAccount in data-pipeline.processor-sa in data-pipeline with automountServiceAccountToken: false.data-processor permitting get, list, watch on configmaps and create, patch on datarecords.hedronite.io.data-processor to processor-sa in data-pipeline via a RoleBinding.processor-pod to use processor-sa (or recreate if immutable).kubectl auth can-i delete configmaps -n data-pipeline --as=system:serviceaccount:data-pipeline:processor-sa should return no.This scenario covers the full CKA+CKS arc: identify over-permissioned binding, remove it, create scoped ServiceAccount, author ClusterRole, bind it, verify. Approximately 8 minutes under exam conditions.
The Ops lesson builds the RBAC architecture for a multi-agent fleet in production. This cert lesson is the exam-prep face of the same knowledge: identical objects, same verification commands, same audit policy YAML you would write in production.
The Dev lesson applies the same pattern to JavaScript: role objects, guard functions, permission-scoped fetch wrappers, audit emission. The hasPermission(session, requiredScope) check in the browser is structurally identical to the RBAC admission check in the API server. Both evaluate a subject against a permission set and return admit or deny.
You need to create a user dev-alice in the dev-team group with access to list and get Pods in the development namespace only. Write the openssl CSR command, the CSR object manifest, and the RoleBinding.
The audit log shows: {"verb":"delete","user":{"username":"system:serviceaccount:prod:scraper-agent"},"objectRef":{"resource":"secrets","name":"db-credentials"},"responseStatus":{"code":200}}. What does this tell you, and what RBAC change should you investigate?
Write an audit policy rule that captures the full RequestResponse for any delete on secrets by any ServiceAccount, while dropping watch events on endpoints entirely.
A Pod in fleet-ops uses the default ServiceAccount and can successfully run kubectl get pods --all-namespaces. What is the most likely cause, and what two commands verify it?
Explain the difference between a RoleBinding referencing a ClusterRole vs. a ClusterRoleBinding referencing a ClusterRole. When would you use each?
Poulton (Ch 16, p. 235) observes that most production Kubernetes privilege-escalation incidents trace back to ServiceAccount tokens that were too powerful, too long-lived, or too broadly mounted. The CKS exam exists to verify that practitioners can fix exactly this pattern.
CKA builds the cluster. CKS secures what CKA built. RBAC is the seam between them. Learn both sides of the seam. Run the practice scenario in §V repeatedly until the full task completes in under ten minutes. Speed on this cluster of commands — openssl, kubectl certificate approve, kubectl auth can-i, kubectl create rolebinding, audit policy YAML — is not optional.