Files
rootnode-academy/content/root/root-09-kubernetes-security/m02-serviceaccounts-and-rbac/03-demonstration-rbac-denial.md
T
ced4568andClaude Sonnet 5 7f6e1857c0 feat(curriculum): Phase 6C module upgrades, security assessment bank, ROOT 11 orientation
Upgrades six PARTIAL modules to the gold-module standard (lesson/demonstration/
knowledge-check/guided-exercise/lab(s)/reflection), preserving every existing lab
activity_id and scenario_id: root-06-m03 (jobs/cronjobs/daemonsets), root-07-m04
(ingress/networkpolicy), root-07-m02 (configuration/secrets, converted in place
from a bare 5-lab bank), root-09-m02 (serviceaccounts/rbac), root-09-m03
(network/supply-chain security), root-10-m03 (troubleshooting framework).

root-05-m01 (20-task kubectl-fluency bank) gets a minimal bookending lesson +
reflection rather than a full redesign, since each task already carries its own
explanation. root-12-m01, root-capstone-m01, and root-09-m04 are promoted to
READY via documented exceptions (no new activities) where adding one would
misrepresent their intentional design.

Wires a new rootnode-security-assessment (exam, 60min, hint_policy disabled)
using the existing Phase 3B assessment engine: 3 required hands-on CORE
scenarios + 4 random-draw pools covering SecurityContext, RBAC, network
policy, and the 7 previously-unwired CKS MCQs. Wires the previously-unwired
readiness-probe-task scenario as an OPTIONAL practice lab in root-10-m01,
using the existing is_required model.

Adds root-11-m01-devops-platform-thinking — an honest, lesson-only ROOT 11
orientation module naming DevOps/platform engineering practices already
exercised in ROOT 05-10/12, explicit that GitOps/CI-CD/IaC/observability need
lab infrastructure this platform doesn't yet provide. No fake labs.

Adds infra/scripts/validate-course-content.js: cross-checks the DB against
scenario/content files for duplicate ids, orphans, invalid references, cycles,
sequence collisions, instructor-notes leakage, and (new) self-paced content
deferring explanation to a live instructor. 0 errors against the resulting
22 courses/modules, 163 activities, 98 scenario files.

No application code changed — every gap was satisfiable with existing tables
(course_modules, module_activities, assessment_definitions) and the existing
content-delivery pipeline.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-26 11:20:17 -05:00

2.5 KiB

Demonstration: Watching RBAC Actually Deny Something

The setup

A ServiceAccount readonly-bot has a Role granting only get/list on pods — nothing else.

What it CAN do

$ kubectl auth can-i list pods --as=system:serviceaccount:default:readonly-bot
yes

$ kubectl get pods --as=system:serviceaccount:default:readonly-bot
NAME          READY   STATUS    RESTARTS   AGE
web-abc123    1/1     Running   0          2h

What it CANNOT do

$ kubectl auth can-i delete pods --as=system:serviceaccount:default:readonly-bot
no

$ kubectl delete pod web-abc123 --as=system:serviceaccount:default:readonly-bot
Error from server (Forbidden): pods "web-abc123" is forbidden:
User "system:serviceaccount:default:readonly-bot" cannot delete resource "pods"
in API group "" in the namespace "default"

This is what least privilege actually looks like in practice — not a policy document, a real, enforced denial with a specific, readable error naming exactly which permission was missing. kubectl auth can-i is your fastest way to CHECK a permission before attempting an action that might fail — useful both for debugging "why can't my workload do X" and for verifying a Role is actually as narrow as intended.

What happens when the ServiceAccount tries something it was never even considered for

$ kubectl auth can-i get secrets --as=system:serviceaccount:default:readonly-bot
no

Notice this returns no the same way delete pods did — RBAC has no concept of "not yet decided," only "explicitly allowed" or "everything else, denied." This is the practical meaning of default-deny applied to permissions: nothing is grey area.

Instructor Notes

Demo script: Run all three kubectl auth can-i/action pairs live — the FORBIDDEN error message's exact wording (naming the verb, resource, and namespace) is worth reading aloud, since that's exactly the evidence a student would use to debug a real permissions issue later.

Approximate timing: 8 minutes live; 5 minutes self-paced.

Common misconception to preempt: students sometimes think kubectl auth can-i REQUIRES the action to actually be attempted to know the answer. It doesn't — it's a dry-run permission check against the same RBAC rules, safe to run repeatedly without side effects.

Optional extension: ask what the error message would look like if readonly-bot tried to act on a DIFFERENT namespace than the one its Role/RoleBinding applies to — a good check that students understand Role scope is namespace-specific unless a ClusterRole+ClusterRoleBinding is used instead.