Hedronite · Dev Lesson · Polyglot-Dev / Python · Sat 2026-09-12

Python kubernetes client PSA census — namespace labels and restricted violations

List the labels before you flip enforce. Guessing which namespaces are restricted is how privileged Deployments survive review.

Lesson Class: Dev (Python + kubernetes client + PSA)
Paired Ops: AKS Pod Security Admission
Paired Cert: CKS PSA restricted enforce
Paired Go: client-go PSA namespace informer
Grounding: CKS Q14 · kubestronaut CKS §4
List
Namespace PSA labels first.
Scan
Privileged SecurityContext.
Read-only
No label patches tonight.
Ship a table ops can sort. Flag privileged SecurityContext under open namespaces.

List the labels before you flip enforce. Guessing which namespaces are restricted is how privileged Deployments survive review.

§I — Frame

Use the official Python kubernetes client to inventory namespace PSA labels and scan running pods for SecurityContext shapes that violate the restricted profile. Pair with Ops AKS labeling work. Do not reopen NetworkPolicy listing (09-09) or IRSA annotation walking (09-06).

§II — Client bootstrap

from kubernetes import client, config

config.load_kube_config()
core = client.CoreV1Api()
namespaces = core.list_namespace()
pods = core.list_pod_for_all_namespaces()

§III — Namespace census row

For each namespace, read labels with prefix pod-security.kubernetes.io/:

PREFIX = "pod-security.kubernetes.io/"
rows = []
for ns in namespaces.items:
    labels = ns.metadata.labels or {}
    psa = {k[len(PREFIX):]: v for k, v in labels.items() if k.startswith(PREFIX)}
    rows.append({
        "ns": ns.metadata.name,
        "enforce": psa.get("enforce"),
        "audit": psa.get("audit"),
        "warn": psa.get("warn"),
        "enforce_version": psa.get("enforce-version"),
    })

Print WARN when enforce is missing on non-system namespaces you expect to harden. Print INFO when enforce is privileged on an app namespace (likely too open).

§IV — Restricted-violation heuristics on pods

A read-only scan flags common restricted violations without mutating:

def violates_restricted(pod):
    flags = []
    for c in (pod.spec.containers or []):
        sc = c.security_context
        if not sc:
            flags.append(f"{c.name}:missing-securityContext")
            continue
        if sc.privileged:
            flags.append(f"{c.name}:privileged")
        if sc.run_as_user == 0:
            flags.append(f"{c.name}:runAsUser0")
        caps = (sc.capabilities.add or []) if sc.capabilities else []
        if caps:
            flags.append(f"{c.name}:caps-add")
        if sc.allow_privilege_escalation is not False:
            flags.append(f"{c.name}:allowPrivilegeEscalation")
    for v in (pod.spec.volumes or []):
        if v.host_path is not None:
            flags.append("hostPath")
    return flags

Join pod flags to the namespace enforce profile. Highest priority WARN: enforce is None or baseline while the pod shows privileged or hostPath.

§V — What not to invent

§VI — Relation to Cert and Go

Cert trains fixing a bad Deployment under enforce=restricted (Q14) and capturing FailedCreate after labeling (Q47). This census finds live risk before the label flip. Go companion watches namespace label changes via informer.

§VII — Closing

Ship a table ops can sort by enforce profile. Flag privileged SecurityContext under open namespaces. Leave mutation for a change window.

Related