TT Lab
Get started
Learn Learning paths Courses

KCSA — Kubernetes Security Associate

A Cluster-Wide RBAC Audit

Continue in TT Lab

Goal

Actually audit the RBAC of the entire cluster. Find ClusterRoles that have wildcard permissions and dangerous verbs, measure a service account's effective permissions with kubectl auth can-i, create a new least-privilege Role, prove that its boundary really works, and then write an audit report containing the evidence.

Why it matters

RBAC audits are hard because reading the manifests alone does not give the answer. Several bindings attach to one subject, permissions are inherited through groups, and built-in ClusterRoles are sometimes merged through aggregation. Do not compute it in your head; ask the apiserver. kubectl auth can-i --list --as= is that tool.

There is a reason to count wildcards separately. resources: ["*"] allows not only the resources that exist now but also resources that will be added later as CRDs. This is why the rebuttal "it's safe for now" does not hold.

escalate, bind, and impersonate are especially dangerous meta permissions. These verbs are "permissions to grant permissions," so with just one of them you can make yourself an administrator. They are the first thing to look for in an RBAC audit.

Finally, step 6. Least privilege does not mean "we gave what is needed" but "what is not needed does not work." If you stop after confirming only that reading works, you have done half the job. Only when you also confirm that deleting does not work and that it does not work in other namespaces have you proven the boundary.

Steps

  1. Create the directory /root/kcsa-audit and the namespace kcsa-audit, and in that namespace create two ServiceAccounts, auditor and probe. At this step, attach no permissions to either.
  2. Among all ClusterRoles in the cluster, find those where within a single rule both verbs and resources are *, and save only the names, one per line, to /root/kcsa-audit/wildcard-clusterroles.txt.
  3. Run kubectl auth can-i --list with --as=system:serviceaccount:kcsa-audit:probe and -n kcsa-audit, and save the entire output as it is, unprocessed, to /root/kcsa-audit/probe-can-i.txt. probe is a comparison baseline to which no role is bound until the end of this lab, so you must not attach permissions to it even later.
  4. Among all ClusterRoles in the cluster, find those whose verbs contain even one, literally, of escalate, bind, or impersonate, and save only the names, one per line, to /root/kcsa-audit/dangerous-verbs.txt.
  5. Ask three questions as system:serviceaccount:kcsa-audit:default and save the results to /root/kcsa-audit/default-sa.txt as three lines in 키=값 format (the placeholders are the key and the value) — create-pods= (create Pods in the namespace kcsa-audit), get-secrets= (get secrets in the namespace kcsa-audit), and list-nodes= (list nodes cluster-wide). Write the value as yes or no as it is.
  6. In the namespace kcsa-audit, create the Role configmap-reader — it has exactly one rule, with apiGroups being just the core group, resources just configmaps, and verbs just the three of get, list, and watch. And bind it to the SA auditor with the RoleBinding auditor-configmap-reader. After creating it, use auth can-i to check (a) that configmaps list works in kcsa-audit, (b) that delete does not work in the same place, and (c) that not even list works in the default namespace.
  7. Write /root/kcsa-audit/rbac-audit-report.md. The following four lines must appear exactly as section headings — ## 와일드카드 권한, ## 위험 동사, ## 기본 서비스어카운트, ## 최소 권한 적용 (the Korean headings mean "Wildcard permissions", "Dangerous verbs", "Default service account", and "Applying least privilege"). The body must mention the following five words — cluster-admin, escalate, impersonate, configmap-reader, auditor. And include one line in the form wildcard-count=<숫자> (the placeholder is the number) with the number of wildcard ClusterRoles you counted in step 2.

Notes

Prepare the audit workspace

Create the directory /root/kcsa-audit and the namespace kcsa-audit, and in that namespace create two ServiceAccounts, auditor and probe. At this step, attach no permissions to either.

Create the artifact directory, the namespace, and two service accounts. One is the subject that will later receive the least-privilege role, and the other is a comparison baseline that receives no permissions to the end. Without a baseline, you cannot say "permissions increased."

Find ClusterRoles with wildcard permissions

Among all ClusterRoles in the cluster, find those where within a single rule both verbs and resources are *, and save only the names, one per line, to /root/kcsa-audit/wildcard-clusterroles.txt.

Look for cases where both verbs and resources are * within a single rule. Rules are an array and a ClusterRole can have several, so if any one satisfies the condition, put that role on the list. Combining jq's select and any does it in one line.

Take the baseline of a service account with no permissions

Run kubectl auth can-i --list with --as=system:serviceaccount:kcsa-audit:probe and -n kcsa-audit, and save the entire output as it is, unprocessed, to /root/kcsa-audit/probe-can-i.txt. probe is a comparison baseline to which no role is bound until the end of this lab, so you must not attach permissions to it even later.

auth can-i has an option that prints the full list instead of individual questions. Specify the subject with --as, and to see namespace-scoped permissions too, you must also give -n. Do not process the output with grep or sorting; save it as it is. The few lines that appear here are the baseline of an "account with no permissions," and you must never attach any role to this account.

Detect ClusterRoles that hold dangerous verbs

Among all ClusterRoles in the cluster, find those whose verbs contain even one, literally, of escalate, bind, or impersonate, and save only the names, one per line, to /root/kcsa-audit/dangerous-verbs.txt.

If you recall what each of the three verbs makes possible, you understand why they are looked at together. Here, only those with the verb written literally are counted — wildcards were already tallied separately in an earlier step.

What can the default service account do

Ask three questions as system:serviceaccount:kcsa-audit:default and save the results to /root/kcsa-audit/default-sa.txt as three lines in 키=값 format (the placeholders are the key and the value) — create-pods= (create Pods in the namespace kcsa-audit), get-secrets= (get secrets in the namespace kcsa-audit), and list-nodes= (list nodes cluster-wide). Write the value as yes or no as it is.

Every namespace automatically has a default service account, and a Pod uses it if it does not specify an SA. Ask directly what this account can do and carry over the answers as they are. When asking about a cluster-scoped resource, you do not need the namespace option.

Create a least-privilege Role and prove its boundary

In the namespace kcsa-audit, create the Role configmap-reader — it has exactly one rule, with apiGroups being just the core group, resources just configmaps, and verbs just the three of get, list, and watch. And bind it to the SA auditor with the RoleBinding auditor-configmap-reader. After creating it, use auth can-i to check (a) that configmaps list works in kcsa-audit, (b) that delete does not work in the same place, and (c) that not even list works in the default namespace.

Put only what is needed in a single rule. The core API group has an empty string as its name. After creating it, you can call it least privilege only if you check not just that what you want works but also that what you do not want does not work — especially that it does not work in other namespaces.

Gather it into an audit report

Write /root/kcsa-audit/rbac-audit-report.md. The following four lines must appear exactly as section headings — ## 와일드카드 권한, ## 위험 동사, ## 기본 서비스어카운트, ## 최소 권한 적용 (the Korean headings mean "Wildcard permissions", "Dangerous verbs", "Default service account", and "Applying least privilege"). The body must mention the following five words — cluster-admin, escalate, impersonate, configmap-reader, auditor. And include one line in the form wildcard-count=<숫자> (the placeholder is the number) with the number of wildcard ClusterRoles you counted in step 2.

Make one document based on the artifacts of the earlier steps. The section headings must be exactly in the indicated form, and you need one line that writes the count from step 2 as a number. That number is recomputed and compared at grading time.