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

client-go PSA namespace informer — watch enforce/audit/warn labels

List once for a ticket. Inform when the fleet must notice a label flip.

Lesson Class: DevOps-Go (client-go · Namespace PSA)
Paired Ops: AKS Pod Security Admission
Paired Dev: Python PSA label census
Paired Cert: CKS PSA restricted enforce
Grounding: CKS Q47
Watch
Namespace label flips.
Extract
pod-security.kubernetes.io/*
Warn
Missing enforce on app NS.
Watch the Namespace that Ops labels. Flag missing enforce on app tenancy.

List once for a ticket. Inform when the fleet must notice a label flip.

§I — Frame

Build a small Go program that uses client-go to watch Namespace objects and print add/update events when pod-security.kubernetes.io/* labels change. This is the live twin of the Python census. It is not the NetworkPolicy informer from 09-09 and not the IRSA ServiceAccount informer from 09-06.

§II — Informer sketch

factory := informers.NewSharedInformerFactory(clientset, 0)
nsInformer := factory.Core().V1().Namespaces().Informer()
nsInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) { report("ADD", obj) },
    UpdateFunc: func(oldObj, newObj interface{}) {
        if psaChanged(oldObj, newObj) {
            report("UPD", newObj)
        }
    },
    DeleteFunc: func(obj interface{}) { report("DEL", obj) },
})
factory.Start(ctx.Done())
factory.WaitForCacheSync(ctx.Done())

Use typed corev1.Namespace assertions inside report. Handle cache.DeletedFinalStateUnknown.

§III — PSA extract helper

const psaPrefix = "pod-security.kubernetes.io/"

func psaMap(ns *corev1.Namespace) map[string]string {
    out := map[string]string{}
    for k, v := range ns.Labels {
        if strings.HasPrefix(k, psaPrefix) {
            out[strings.TrimPrefix(k, psaPrefix)] = v
        }
    }
    return out
}

Log WARN when enforce is empty on namespaces that match an allowlist of app prefixes (for example team-, app-). Keep the helper pure for unit tests without a cluster.

§IV — Boundaries

§V — Relation to Python

Python owns one-shot API list plus pod SecurityContext heuristics for tickets. Go owns continuous cache of namespace label flips. Same WARN semantics so ops sees one language across tools.

§VI — Closing

Watch the Namespace that Ops labels. Flag missing enforce on app tenancy. Exit clean on context cancel.

Related