Vanilla Kubernetes
Prethodna lekcija uspostavila je kontrolisan rečnik labels i annotations, vlasništvo resursa i vezu Kubernetes inventara sa CMDB sistemom. Takav standard nema punu operativnu vrednost ako njegova primena zavisi od toga da administrator ručno pregleda svaki manifest. U produkcionom klasteru promene dolaze kroz GitOps kontrolere, CI/CD naloge, operatore, Helm instalacije i neposredne API zahteve. Admission politika pretvara dogovoreni standard u izvršivu kontrolu na zajedničkoj tački kroz koju prolaze zahtevi za promenom Kubernetes objekata.
Policy as code znači da se pravilo opisuje deklarativno, verzioniše, pregleda, testira, promoviše i povlači kao i drugi kod. Cilj nije da se u jednu politiku prenesu sve organizacione procedure, već da se u trenutku prijema zahteva automatski provere činjenice koje Kubernetes API pouzdano vidi: prisustvo obaveznih metapodataka, dozvoljene vrednosti, bezbednosni kontekst, registar slike, granice resursa ili nedozvoljena promena zaštićenog polja. Dobra politika skraćuje vreme povratne informacije i daje isti rezultat bez obzira na to ko je poslao manifest. Loša politika može zaustaviti deployment-e, kontrolere, oporavak sistema ili sam rad API servera, pa se projektuje kao komponenta kontrolne ravni, a ne kao obična skripta za proveru YAML-a.
Mesto admission kontrole u Kubernetes API toku
Zahtev za kreiranje, izmenu ili brisanje objekta prvo prolazi autentikaciju i autorizaciju, a zatim admission kontrolu pre nego što bude trajno upisan u etcd. Admission kontroleri ne obrađuju read-only operacije get, list i watch. Zbog toga admission politika sprečava novu neusaglašenu promenu, ali sama ne pronalazi niti popravlja objekte koji već postoje. Za postojeće stanje potrebni su inventar, periodično skeniranje usklađenosti i kontrolisana remedijacija.
Admission se izvršava u dve logičke faze. Mutating kontroleri mogu dopuniti ili izmeniti zahtev, na primer dodati podrazumevanu vrednost. Posle njih se izvršava objektna validacija, a zatim validating kontroleri i politike odlučuju da li konačan oblik objekta sme biti prihvaćen. Pravilo koje mora videti konačno stanje objekta pripada validacionoj fazi. Ako bilo koja obavezna kontrola odbije zahtev, objekat se ne upisuje.
| Sloj | Pitanje na koje odgovara | Tipičan rezultat | Granica |
|---|---|---|---|
| Autentikacija | Ko šalje zahtev? | Identitet korisnika ili ServiceAccount-a | Ne određuje da li je željena konfiguracija dozvoljena |
| Autorizacija | Da li identitet sme da izvrši glagol nad resursom? | Dozvola ili zabrana API operacije | RBAC uglavnom ne procenjuje sadržaj manifesta |
| Mutating admission | Da li zahtev treba dopuniti ili izmeniti? | Izmenjen objekat ili odbijanje | Skrivena mutacija otežava razumevanje efektivnog stanja |
| Validating admission | Da li konačan objekat zadovoljava politiku? | Prihvatanje, upozorenje, audit zapis ili odbijanje | Ne sanira ranije objekte i ne proverava read zahteve |
| Reconciliation | Da li stvarno stanje ostaje usklađeno posle prijema? | Kontinuirana korekcija ili izveštaj o drift-u | Nije zamena za preventivnu admission kontrolu |
Redosled je važan za dijagnostiku. HTTP 401 obično upućuje na autentikaciju, 403 na autorizaciju, dok admission odbijanje vraća poruku politike i često HTTP 422 ili drugi odgovarajući status API greške. Administrator najpre utvrđuje koji je sloj doneo odluku; širenje RBAC prava neće ispraviti manifest koji krši CEL izraz.
Ugrađeni kontroleri, ValidatingAdmissionPolicy i webhook proširenja
Kubernetes sadrži skup ugrađenih admission kontrolera u kube-apiserver binarnoj datoteci. Među njima su kontrole kao što su NamespaceLifecycle, ResourceQuota, LimitRanger, ServiceAccount, PodSecurity, MutatingAdmissionWebhook, ValidatingAdmissionWebhook i ValidatingAdmissionPolicy. Podrazumevani skup zavisi od Kubernetes verzije; zato se ne prepisuje lista iz tutorijala u produkcionu proceduru, već se proveravaju dokumentacija konkretne minor verzije i efektivni argumenti svakog API servera.
ValidatingAdmissionPolicy je stabilan od Kubernetes v1.30. Pravila se pišu u Common Expression Language-u, CEL-u, i izvršavaju unutar API servera bez spoljnog HTTP poziva. Politika opisuje logiku i resurse na koje može da se odnosi, a ValidatingAdmissionPolicyBinding je povezuje sa konkretnim scope-om, opcionim parametrima i akcijama. Bez binding objekta politika nema efekat. Deklarativni in-process model smanjuje mrežne i TLS zavisnosti u odnosu na webhook i najčešće je prvi izbor kada CEL može jasno izraziti zahtev.
Admission webhook je HTTP servis kome API server šalje AdmissionReview. Mutating webhook može vratiti JSON Patch, dok validating webhook prihvata ili odbija zahtev. Webhook je opravdan kada je potrebna mutacija, složena logika ili integracija koju ugrađeni CEL model ne može bezbedno da izrazi. Cena je veća: dostupnost servisa, DNS, Service mreža, TLS identitet, CA bundle, latencija, timeout, skaliranje i ponašanje pri kvaru postaju deo API write putanje.
| Mehanizam | Najbolja primena | Prednost | Operativni rizik |
|---|---|---|---|
| Ugrađeni kontroler | Standardna funkcija platforme, na primer Pod Security Admission | Održava ga Kubernetes i radi u API serveru | Promena konfiguracije kontrolne ravni može zahtevati restart i strogu verzijsku proveru |
| ValidatingAdmissionPolicy + CEL | Deklarativna validacija API objekta i stare/nove vrednosti | Nema mrežnog poziva; verzioniše se kao Kubernetes resurs | Pogrešan scope ili izraz može masovno odbijati legitimne zahteve |
| Validating webhook | Složena validacija koju CEL ne pokriva | Fleksibilan programski model | Latencija, TLS, dostupnost i failure policy utiču na API zahteve |
| Mutating webhook | Kontrolisano dodavanje podrazumevanih polja ili sidecar-a | Standardizuje efektivni objekat | Više mutatora, redosled i reinvocation mogu dati neočekivano stanje |
| CI/linter provera | Rana povratna informacija pre slanja API zahteva | Brza i ne utiče na kontrolnu ravan | Može se zaobići drugim putem ka API serveru |
ValidatingAdmissionPolicy: politika, binding, parametri i CEL
Policy resurs sadrži matchConstraints, opcioni paramKind, CEL izraze u validations, opcione auditAnnotations, matchConditions i variables. Binding navodi policyName, validationActions, matchResources i, kada je potrebno, paramRef. Ovo razdvajanje omogućava da se jedna proverena logika primeni na različite namespace grupe ili sa različitim granicama bez kopiranja izraza.
Akcija Warn vraća upozorenje klijentu, ali prihvata zahtev. Audit dodaje informaciju audit događaju ako je audit politika podešena tako da događaj bude zabeležen. Deny odbija zahtev. Deny i Warn ne mogu se kombinovati u istom binding-u, dok je Warn sa Audit koristan za probni period. Produkciona primena zato počinje ograničenim scope-om i akcijama Warn i Audit, meri posledice, koriguje izuzetke, a tek zatim uvodi Deny kroz pregledanu promenu binding-a.
CEL izrazi u admission politici najčešće koriste promenljive object, oldObject, request, params, namespaceObject, deklarisane variables i, gde je podržano, authorizer. Pošto je object dinamički tipizovan za različite Kubernetes vrste, prisustvo opcionih polja proverava se makroom has() pre pristupa. Pravilo mora eksplicitno obraditi CREATE, UPDATE i DELETE semantiku; pri DELETE zahtevu novi object može biti null, a oldObject nosi prethodno stanje.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: workload-metadata.tashizza.example
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments", "statefulsets", "daemonsets"]
variables:
- name: labels
expression: "has(object.metadata.labels) ? object.metadata.labels : {}"
validations:
- expression: >-
'tashizza.example/owner-team' in variables.labels
message: >-
Obavezna je label tashizza.example/owner-team.
reason: Invalid
- expression: >-
'tashizza.example/environment' in variables.labels &&
variables.labels['tashizza.example/environment'] in
['development', 'test', 'staging', 'production']
message: >-
Environment mora biti development, test, staging ili production.
reason: Invalid
- expression: >-
'tashizza.example/criticality' in variables.labels &&
variables.labels['tashizza.example/criticality'] in
['low', 'medium', 'high', 'critical']
message: >-
Criticality mora biti low, medium, high ili critical.
reason: Invalid
Ovaj manifest samo definiše apstraktnu proveru; ne uključuje je. Binding je namerno odvojen kako bi rollout mogao da se menja bez izmene verifikovane logike.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: workload-metadata-warn.tashizza.example
spec:
policyName: workload-metadata.tashizza.example
validationActions: [Warn, Audit]
matchResources:
namespaceSelector:
matchLabels:
tashizza.example/policy-profile: standard
failurePolicy na politici određuje ponašanje kada dođe do greške evaluacije, na primer ako izraz pristupi nepostojećem polju. To nije isto što i neuspešna poslovna validacija. Uz Fail greška evaluacije tretira se kao odbijanje prema akciji binding-a; uz Ignore zahtev može proći. Bezbednosna politika obično zahteva fail-closed ponašanje, ali samo posle dokazane kompatibilnosti. Za politiku čiji kvar može blokirati oporavak klastera odluka mora da uključi threat model, zavisnosti i dokumentovan break-glass postupak.
Scope, izuzeci i granice pravila
Najopasnija politika nije nužno ona sa pogrešnim izrazom, već ona sa preširokim match pravilom. Scope se definiše kroz API grupe, verzije, operacije, resurse i podresurse, cluster ili namespaced opseg, namespace selector, object selector i CEL match uslove. Pravilo namenjeno Deployment objektima ne treba bez dokaza proširiti na sve resurse sa zvezdicom. Policy i binding resursi, Namespace, Node, Lease, TokenReview i kontrolni objekti mogu imati sasvim drugačiji životni ciklus i vlasnike.
namespaceSelector za namespaced zahtev bira labels Namespace objekta, ne labels workload-a. Za Namespace resurs i cluster-scoped resurse mora se pažljivo proveriti dokumentovana semantika. objectSelector olakšava canary rollout, ali nije bezbedna osnova za izuzetak koji korisnik može sam dodati svom objektu. Ako aplikacioni nalog ima pravo da postavi label koja isključuje politiku, on praktično poseduje pravo zaobilaženja.
Izuzetak mora imati vlasnika, razlog, odobrenje, scope i rok isteka. Preferira se ograničenje na poseban namespace čije labels kontroliše platformski tim ili na strogo definisan ServiceAccount uslov, uz audit. Trajna label policy-exempt=true bez roka pretvara privremeni incidentni postupak u nevidljivu rupu u kontroli. Break-glass nije tajni trik već unapred testirana procedura sa višestrukim odobrenjem, vremenski ograničenim pristupom, audit tragom i obaveznim vraćanjem politike.
Politike za workload metapodatke, slike i resurse
Pravila treba graditi oko kontrola koje imaju jasan tehnički dokaz. Obavezne labels iz prethodne lekcije dobar su početak jer imaju stabilan rečnik. Sledeće korisne kontrole mogu zahtevati da svaki kontejner ima resource requests i limits, zabraniti privilegovani security context, ograničiti registries ili sprečiti upotrebu promenljivog taga latest. Ipak, jedna sintaksna provera ne dokazuje celokupnu bezbednost: dozvoljeni registry ne znači da je konkretna slika skenirana ili potpisana, a postojanje limita ne znači da je vrednost pravilno dimenzionisana.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: deployment-runtime-baseline.tashizza.example
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
variables:
- name: containers
expression: "object.spec.template.spec.containers"
validations:
- expression: >-
variables.containers.all(c,
has(c.resources) &&
has(c.resources.requests) &&
'cpu' in c.resources.requests &&
'memory' in c.resources.requests &&
has(c.resources.limits) &&
'memory' in c.resources.limits)
message: >-
Svaki kontejner mora imati CPU i memory requests i memory limit.
- expression: >-
variables.containers.all(c,
c.image.startsWith('registry.tashizza.example/') &&
!c.image.endsWith(':latest'))
message: >-
Slika mora dolaziti iz odobrenog registra i ne sme koristiti tag latest.
Ovaj primer je namerno ograničen na Deployment i obične kontejnere. Produkciona politika mora odlučiti kako obrađuje initContainers, ephemeral containers, Job, CronJob, StatefulSet i DaemonSet pod template strukture. Kopiranje izraza bez te analize stvara lažan osećaj pokrivenosti. Digest pinning, provera potpisa i provenance zahtevaju zaseban dizajn; spoljne provere u admission putanji moraju imati determinističan rezultat, cache strategiju i jasno ponašanje kada registry ili verifikacioni servis nije dostupan.
Pod Security Admission i odnos prema prilagođenim politikama
Ugrađeni PodSecurity admission kontroler sprovodi Pod Security Standards profile privileged, baseline i restricted pomoću Namespace labels za režime enforce, audit i warn. Za opštu pod bezbednosnu osnovu on je primereniji od ponovnog pisanja desetina prilagođenih pravila. Prilagođena ValidatingAdmissionPolicy dopunjuje ga organizacionim zahtevima koje standard ne pokriva, ali ne treba da kopira njegovu logiku bez stručnog razloga.
Pod Security Admission procenjuje podove i workload kontrolere koji sadrže Pod template. Namespace labels mogu zaključati verziju standarda, na primer pod-security.kubernetes.io/enforce-version: v1.36, čime se izbegava nenamerna promena ponašanja posle nadogradnje. Pre promene minor verzije proverava se novi standard u warn/audit režimu. Sistemски namespace-i i infrastruktura često zahtevaju pažljivo profilisane izuzetke; globalno označavanje svih namespace-a kao restricted bez inventara može zaustaviti CNI, CSI, monitoring ili druge privilegovane komponente.
Admission webhook kao komponenta kritične putanje
Webhook konfiguracija mora precizno definisati rules, scope, namespaceSelector ili objectSelector, matchPolicy, opcione matchConditions, admissionReviewVersions, sideEffects, kratak timeoutSeconds, failurePolicy i TLS podatke. Kada clientConfig.service upućuje na servis u klasteru, sertifikat webhook servera mora važiti za odgovarajuće DNS ime oblika SERVICE.NAMESPACE.svc, a caBundle mora omogućiti API serveru proveru tog identiteta.
Webhook treba da bude stateless kada je moguće, sa najmanje dve replike raspoređene na različite čvorove i zone, odgovarajućim readiness proverama, PodDisruptionBudget-om, resource requests/limits, kontrolisanim rollout-om i nadzorom. Ipak, broj replika ne uklanja zavisnost: kvar DNS-a, mreže, sertifikata ili samog control-plane-to-Service puta može učiniti sve replike nedostupnim. Latencija svakog serijskog webhook-a ulazi u latenciju API zahteva, a timeout se obrađuje prema failurePolicy vrednosti.
| Odluka | Fail | Ignore | Administratorski kriterijum |
|---|---|---|---|
| Webhook je nedostupan ili timeout-uje | Zahtev se odbija; bezbednost ostaje zatvorena, dostupnost trpi | Zahtev prolazi; dostupnost ostaje, kontrola može biti zaobiđena | Threat model, kritičnost pravila i nezavisnost recovery puta |
| CEL evaluacija politike ima grešku | Greška se tretira prema failure policy i akciji binding-a | Greška se ignoriše | Testovi svih vrsta i operacija pre Deny režima |
| Objekat jasno krši ispravno pravilo | Rezultat određuje validation action ili webhook odgovor, ne dostupnost servisa | Poruka mora navesti pravilo i bezbednu korekciju | |
Webhook ne treba da poziva Kubernetes API ili udaljene sisteme za svaki zahtev ako se odluka može doneti iz AdmissionReview sadržaja. Takvi pozivi stvaraju petlje, deadlock rizik i kaskadne kvarove. Mutating webhook mora deklarisati side effects i ponašanje za dry-run zahteve. Mutacije treba da budu idempotentne, jer reinvocation može ponovo pozvati mutator nakon izmene drugog webhook-a. Konačna bezbednosna garancija pripada validating sloju koji vidi završni objekat.
Policy as code životni ciklus
Politika ima isti lifecycle kao aplikacioni kod, ali veći blast radius. Repozitorijum treba da sadrži zahtev, threat model, manifeste, testne slučajeve koji moraju proći i pasti, dokumentovane izuzetke, kompatibilnost Kubernetes verzija, plan rollout-a, metrike uspeha i rollback. Pull request pregled obuhvata vlasnika platforme, bezbednost i predstavnika timova na koje pravilo utiče. Samo sintakski ispravan YAML nije dovoljan dokaz.
- Definisanje namere. Pravilo se izražava kao proverljiva rečenica sa razlogom, scope-om, vlasnikom i očekivanom korekcijom.
- Offline i server-side test. Proveravaju se YAML šema, CEL izrazi, pozitivni i negativni manifesti i kompatibilnost sa ciljnim API serverom.
- Canary scope. Binding se primenjuje na namenski laboratorijski ili canary namespace sa
WarniAuditakcijama. - Posmatranje. Mere se upozorenja, audit događaji, API server latencija, webhook rejection i fail-open metrike, incidenti i legitimni use case-ovi.
- Postepeno sprovođenje. Scope se širi kontrolisano, a
Denyuključuje tek kada vlasnici mogu da isprave manifest i postoji testiran recovery put. - Održavanje. Svaka nadogradnja Kubernetes-a, promena CRD šeme ili workload obrasca ponavlja kompatibilnost i regresione testove.
CI provera i admission kontrola imaju različitu svrhu. CI daje ranu, prijatniju povratnu informaciju i može raditi nad Helm/Kustomize izlazom pre klastera. Admission je poslednja zajednička granica koja obuhvata i ručne i automatizovane klijente. Pravilo se po mogućnosti deli kao isti testni ugovor, ali rezultat u CI-u ne sme biti jedina zaštita API servera.
Validacija, audit i observability
Pre promene stanja administrator proverava dostupnost API-ja, postojanje admission API resursa, trenutne politike i binding-e, Namespace labels i efektivna prava. Sledeće komande su read-only:
kubectl api-resources --api-group=admissionregistration.k8s.io
kubectl get validatingadmissionpolicies,validatingadmissionpolicybindings
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations
kubectl get namespaces --show-labels
kubectl auth can-i create validatingadmissionpolicies.admissionregistration.k8s.io
kubectl auth can-i create validatingadmissionpolicybindings.admissionregistration.k8s.io
kubectl apply --dry-run=server šalje zahtev API serveru i aktivira relevantnu admission obradu, ali ne trajno čuva objekat. To je važna razlika u odnosu na --dry-run=client, koji ne dokazuje ponašanje klastera. Dry-run ipak može imati ograničenja kada webhook pogrešno prijavi side effects ili ne podržava dry-run; takav problem je nalaz o webhook konfiguraciji, a ne razlog da se test preskoči.
kubectl apply --dry-run=server -f 48-validating-policy.yaml
kubectl apply --dry-run=server -f 48-binding-warn.yaml
kubectl apply --dry-run=server -f 48-workload-valid.yaml
kubectl apply --dry-run=server -f 48-workload-invalid.yaml
Za ValidatingAdmissionPolicy proverava se status.typeChecking.expressionWarnings. Prazna lista upozorenja je potreban, ali ne i dovoljan uslov; objekat može imati logičku grešku koja je tipovski dozvoljena. Audit akcija daje vrednost samo ako je audit logging omogućen i audit politika beleži odgovarajući nivo. U audit događajima traže se policy i binding identitet, korisnik, operacija, resource, namespace, razlog i request UID. Osetljivi objekti i payload-i moraju biti zaštićeni audit pravilima i pravilima čuvanja logova.
kubectl get validatingadmissionpolicy \
workload-metadata.tashizza.example -o yaml
kubectl get --raw='/metrics' | grep -E \
'apiserver_admission|admission_webhook' | head -n 40
Direktan pristup /metrics zahteva posebna prava i u produkciji se obično radi kroz odobren monitoring sistem, ne interaktivnim administratorskim nalogom. Za webhook se prate request rate, latencija po kvantilima, timeout-i, rejection-i, fail-open događaji, HTTP/TLS greške, broj dostupnih replika i vreme do isteka sertifikata. Za CEL politike prate se odbijanja, audit upozorenja, API server admission latencija i promene broja neusaglašenih zahteva po timu i pravilu.
Praktikum: od upozorenja do kontrolisanog Deny režima
Cilj i kontekst.
Laboratorija uvodi izvršivu verziju standarda metapodataka iz lekcije 47. Politika proverava Deployment, StatefulSet i DaemonSet objekte u namespace-u označenom policy profilom. Najpre radi u Warn i Audit režimu, zatim se negativnim i pozitivnim testom potvrđuje ponašanje, a tek nakon dokaza uključuje Deny. Vežba ne instalira eksterni policy engine niti webhook i zato ne uvodi dodatnu mrežnu zavisnost.
Topologija i preduslovi.
- Jedan laboratorijski Vanilla Kubernetes klaster v1.30 ili noviji sa stabilnim
admissionregistration.k8s.io/v1ValidatingAdmissionPolicy resursima. kubectlkompatibilan sa klasterom i kubeconfig nalog sa pravima za policy, binding, Namespace i Deployment resurse.- Audit akcija je opciono vidljiva samo ako operator kontrolne ravni ima omogućen audit logging i odgovarajuću audit politiku.
- Fajlovi se verzionišu u radnoj grani; produkcioni klaster nije cilj ove laboratorije.
Rizik. Policy i binding su cluster-scoped resursi. Pogrešan binding može obuhvatiti više namespace-a nego što je planirano. Namespace selector zato koristi jedinstvenu laboratorijsku label, a pre svake state-changing komande izvršava se server-side dry-run. U deljenom klasteru vežba zahteva odobrenje vlasnika platforme.
Vežba 1: početni dokazi i laboratorijski namespace
Sledeće komande prvo čitaju capability i prava. Kreiranje namespace-a i label-a menja stanje klastera. Ako kubectl api-resources ne prikaže oba policy resursa, laboratorija se ne nastavlja; ne pokušava se beta API sa interneta bez dokumentacije konkretne verzije.
kubectl version
kubectl api-resources --api-group=admissionregistration.k8s.io \
| grep -E 'validatingadmissionpolic(y|ies)|validatingadmissionpolicybinding'
kubectl auth can-i create validatingadmissionpolicies.admissionregistration.k8s.io
kubectl auth can-i create validatingadmissionpolicybindings.admissionregistration.k8s.io
# Menja stanje: kreira izolovani laboratorijski scope
kubectl create namespace admission-lab
kubectl label namespace admission-lab \
tashizza.example/policy-profile=standard
# Read-only validacija scope-a
kubectl get namespace admission-lab --show-labels
Očekivani rezultat: API discovery prikazuje v1 policy i binding resurse, obe autorizacione provere vraćaju yes, a namespace ima tačno očekivanu label. Ako je odgovor no, ne vezuje se širi ClusterRole; zahtev se prosleđuje administratoru sa potrebnim glagolima i resursima.
Vežba 2: politika i neblokirajući binding
Sačuvaj sledeći višedokumentni manifest kao 48-policy-warn.yaml. Politika je ista kao u teorijskom delu, a binding je ograničen na laboratorijski namespace preko label selektora.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: workload-metadata.tashizza.example
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments", "statefulsets", "daemonsets"]
variables:
- name: labels
expression: "has(object.metadata.labels) ? object.metadata.labels : {}"
validations:
- expression: "'tashizza.example/owner-team' in variables.labels"
message: "Obavezna je label tashizza.example/owner-team."
reason: Invalid
- expression: >-
'tashizza.example/environment' in variables.labels &&
variables.labels['tashizza.example/environment'] in
['development', 'test', 'staging', 'production']
message: "Environment mora biti development, test, staging ili production."
reason: Invalid
- expression: >-
'tashizza.example/criticality' in variables.labels &&
variables.labels['tashizza.example/criticality'] in
['low', 'medium', 'high', 'critical']
message: "Criticality mora biti low, medium, high ili critical."
reason: Invalid
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: workload-metadata-warn.tashizza.example
spec:
policyName: workload-metadata.tashizza.example
validationActions: [Warn, Audit]
matchResources:
namespaceSelector:
matchLabels:
tashizza.example/policy-profile: standard
# Read-only lokalna provera renderovanih dokumenata
kubectl apply --dry-run=client -f 48-policy-warn.yaml
# Read-only u pogledu trajnog stanja; API server validira manifest
kubectl apply --dry-run=server -f 48-policy-warn.yaml
# Menja cluster-scoped stanje
kubectl apply -f 48-policy-warn.yaml
# Read-only dokaz kreiranja i type-check statusa
kubectl get validatingadmissionpolicy \
workload-metadata.tashizza.example -o yaml
kubectl get validatingadmissionpolicybinding \
workload-metadata-warn.tashizza.example -o yaml
Validacija: oba resursa postoje, binding ima samo Warn i Audit, a selector odgovara samo namespace-ima sa laboratorijskom label. U statusu politike pregledaju se type-check upozorenja. Svako upozorenje zahteva korekciju izraza pre testiranja; ne prelazi se na Deny.
Vežba 3: pozitivan i negativan zahtev
Sačuvaj sledeće kao 48-workloads.yaml. Prvi Deployment je usklađen. Drugom nedostaje owner-team, environment ima nedozvoljenu vrednost prod, a criticality je izostavljen.
apiVersion: apps/v1
kind: Deployment
metadata:
name: policy-demo-valid
namespace: admission-lab
labels:
app.kubernetes.io/name: policy-demo-valid
tashizza.example/owner-team: platform-operations
tashizza.example/environment: test
tashizza.example/criticality: medium
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: policy-demo-valid
template:
metadata:
labels:
app.kubernetes.io/name: policy-demo-valid
spec:
containers:
- name: web
image: nginx:1.27-alpine
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: policy-demo-invalid
namespace: admission-lab
labels:
app.kubernetes.io/name: policy-demo-invalid
tashizza.example/environment: prod
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: policy-demo-invalid
template:
metadata:
labels:
app.kubernetes.io/name: policy-demo-invalid
spec:
containers:
- name: web
image: nginx:1.27-alpine
kubectl apply --dry-run=server -f 48-workloads.yaml
kubectl apply -f 48-workloads.yaml
kubectl get deployments -n admission-lab --show-labels
Očekivani rezultat: u Warn/Audit režimu klijent prikazuje tri jasna upozorenja za neispravan Deployment, ali oba objekta mogu biti kreirana. Ako upozorenja nema, proveravaju se Namespace label, binding selector, policyName, operations i resourceRules. Ako je zahtev odbijen, postoji drugi binding sa Deny ili druga admission kontrola; pre promene se popisuju svi policy i webhook objekti.
Vežba 4: korekcija, Deny promocija i dokaz
Najpre se neispravan Deployment koriguje u izvornom manifestu. Ručni patch ovde služi samo kao laboratorijski dokaz i menja živi objekat; u GitOps okruženju korekcija mora ući u repozitorijum.
# Menja stanje laboratorijskog objekta
kubectl label deployment policy-demo-invalid -n admission-lab \
tashizza.example/owner-team=platform-operations \
tashizza.example/environment=test \
tashizza.example/criticality=medium --overwrite
# Read-only dokaz usklađenosti
kubectl get deployment policy-demo-invalid -n admission-lab \
-o jsonpath='{.metadata.labels}{"\n"}'
Zatim napravi 48-binding-deny.yaml. Novi binding uvodi Deny tek pošto su upozorenja analizirana i postojeći objekti usklađeni. Warn binding se uklanja da ne bi duplirao rezultat.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: workload-metadata-deny.tashizza.example
spec:
policyName: workload-metadata.tashizza.example
validationActions: [Deny, Audit]
matchResources:
namespaceSelector:
matchLabels:
tashizza.example/policy-profile: standard
kubectl apply --dry-run=server -f 48-binding-deny.yaml
kubectl apply -f 48-binding-deny.yaml
kubectl delete validatingadmissionpolicybinding \
workload-metadata-warn.tashizza.example
# Mora uspeti: validan zahtev
kubectl apply --dry-run=server -f 48-workloads-valid-only.yaml
# Mora biti odbijen: negativni test bez trajne promene
kubectl create deployment deny-proof -n admission-lab \
--image=nginx:1.27-alpine --dry-run=server -o yaml
Napomena: fajl 48-workloads-valid-only.yaml sadrži samo prvi dokument iz prethodnog manifesta. Poslednja komanda namerno ne postavlja obavezne labels i mora biti odbijena sa porukama politike. Ako prođe, Deny nije efektivan i rollout se zaustavlja. Kriterijum završetka je: usklađen manifest prolazi server-side dry-run, neusklađen je odbijen, a drugi namespace bez policy-profile label nije slučajno obuhvaćen.
Vežba 5: kontrolisan kvar i rollback
Bezbedna simulacija ne kvari API server niti webhook. U posebnoj radnoj kopiji namerno se uvede CEL izraz koji pristupa nepostojećem polju i primeni samo u Warn/Audit binding-u. Pregleda se status.typeChecking.expressionWarnings, potvrđuje da greška nije kandidat za Deny i promena se ne promoviše. Produkcioni incident se ne simulira globalnim neispravnim Deny pravilom.
Najbrži rollback enforcement-a je uklanjanje ili vraćanje binding-a, jer politika bez binding-a nema efekat. Ovo je state-changing break-glass postupak i mora biti auditovan. Brisanje same politike pre binding-a može zakomplikovati dijagnostiku i gubi centralni objekat koji objašnjava nameru.
# Read-only: sačuvaj dokaz pre rollback-a
kubectl get validatingadmissionpolicybinding \
workload-metadata-deny.tashizza.example -o yaml \
> 48-binding-deny-backup.yaml
# Menja stanje: hitno uklanja enforcement scope
kubectl delete validatingadmissionpolicybinding \
workload-metadata-deny.tashizza.example
# Read-only dokaz: zahtev više ne odbija upravo ovaj binding
kubectl create deployment rollback-proof -n admission-lab \
--image=nginx:1.27-alpine --dry-run=server -o yaml
# Kontrolisano vraćanje tek posle korekcije
kubectl apply --dry-run=server -f 48-binding-deny-backup.yaml
kubectl apply -f 48-binding-deny-backup.yaml
Prolazak rollback-proof testa ne dokazuje da nema drugih politika; samo dokazuje da je predmetni binding uklonjen ako poruka više ne pominje njegovo ime. Posle korekcije ponavljaju se svi pozitivni i negativni testovi, a incident beleži početak, obim odbijenih zahteva, request UID vrednosti, uzrok, privremenu meru, trajnu korekciju i vreme vraćanja enforcement-a.
Vežba 6: cleanup laboratorije
Cleanup je destruktivan samo za jasno imenovane laboratorijske objekte. Pre brisanja proverava se da namespace ne sadrži tuđe resurse. Redosled prvo uklanja binding, zatim politiku i na kraju namespace.
kubectl get all -n admission-lab
kubectl get validatingadmissionpolicybinding \
workload-metadata-deny.tashizza.example
kubectl delete validatingadmissionpolicybinding \
workload-metadata-deny.tashizza.example --ignore-not-found
kubectl delete validatingadmissionpolicy \
workload-metadata.tashizza.example --ignore-not-found
kubectl delete namespace admission-lab
rm -f 48-policy-warn.yaml 48-workloads.yaml \
48-workloads-valid-only.yaml 48-binding-deny.yaml \
48-binding-deny-backup.yaml
Kriterijum završetka: laboratorijski namespace, binding i politika više ne postoje; nijedan drugi policy ili webhook objekat nije izmenjen; Git radna grana čuva samo dokumentovane primere i rezultate koji ne sadrže poverljive podatke.
Tipični kvarovi i sistematična dijagnostika
| Simptom | Najverovatniji neposredni uzrok | Dokaz | Bezbedna korekcija |
|---|---|---|---|
| Legitimni deployment-i su masovno odbijeni | Preširok binding scope ili pogrešan CEL izraz | API odgovor, policy/binding YAML, audit request UID i poslednja Git promena | Ograničiti ili ukloniti binding, zatim ispraviti i ponovo testirati politiku |
| Neispravan manifest prolazi | Nema binding-a, pogrešan selector, operacija ili resource rule | Discovery, Namespace labels, policyName i server-side dry-run | Ispraviti scope; ne širiti ga na zvezdicu bez regresionih testova |
| API write zahtevi su spori | Spor ili serijski webhook, predugačak timeout ili spoljna zavisnost | API server admission metrike, webhook metrike i logovi sa request UID-om | Smanjiti scope/timeout, ukloniti udaljene pozive, skalirati i profilisati webhook |
| Webhook vraća TLS grešku | Pogrešan CA bundle, SAN/DNS ime ili istekao sertifikat | API server log, sertifikat i Service/DNS podaci | Rotirati sertifikat i CA kontrolisano; ne postavljati neprovereni endpoint |
| Audit akcija nije vidljiva | Audit logging nije omogućen ili politika ne beleži potreban nivo | kube-apiserver konfiguracija i audit politika na control-plane čvoru | Promeniti audit konfiguraciju kroz proceduru kontrolne ravni |
| UPDATE prolazi, CREATE pada ili obrnuto | Različita polja object/oldObject ili neusklađen operations scope | Odvojeni CREATE i UPDATE testovi i CEL expression warnings | Eksplicitno modelovati semantiku svake operacije |
Dijagnostika počinje očuvanjem API odgovora, vremena, korisnika, request UID-a, vrste i namespace-a. Zatim se određuje obim: jedan manifest, jedna vrsta, jedan namespace ili svi write zahtevi. Pregledaju se poslednje promene policy repozitorijuma, policy i binding generacije, Namespace labels, webhook konfiguracije, endpoint-i, sertifikati, API server i audit logovi. Tek nakon potvrđene hipoteze menja se binding ili webhook. Privremeno uklanjanje enforcement-a nije trajna korekcija; osnovni uzrok može biti nedovoljan testni skup, vlasništvo nad izuzetkom ili nepostojanje canary rollout-a.
Administratorske prakse
- Najmanji mogući scope. Svaka politika eksplicitno navodi API grupe, verzije, operacije i resurse. Zvezdice zahtevaju posebno obrazloženje i testove nad cluster-scoped, namespaced i subresource zahtevima.
- Warn/Audit pre Deny. Nova ili značajno izmenjena kontrola prvo radi najmanje jedan reprezentativan deployment ciklus u neblokirajućem režimu. Deny se uvodi tek kada su poznati vlasnici, izuzeci i korektivna uputstva.
- Razdvajanje logike i primene. Stabilna politika koristi odvojene binding-e za canary, standardni i eventualno stroži profil. Kopiranje CEL izraza u više politika izbegava se jer stvara verzijski drift.
- Regresioni test paket. Za svako pravilo postoje validan, nevalidan i granični manifest, CREATE i UPDATE test, kao i test nedostajućeg opcionog polja. Testovi se ponavljaju pri Kubernetes minor nadogradnji.
- Webhook SLO i sertifikati. Prate se dostupnost, p95/p99 latencija, timeout-i, rejection-i, fail-open događaji i rok sertifikata. Alarm se aktivira pre nego što kvar postane API incident.
- Kontrolisani izuzeci. Svaki izuzetak ima identitet vlasnika, ticket, razlog, precizan scope i rok. Dodela exemption label korisniku čiji objekat politika proverava nije dozvoljena.
- Zaštićeni policy repozitorijum. Obavezni review, potpisani commit-i gde politika organizacije to zahteva, zaštićena grana i audit primene sprečavaju da jedna nekontrolisana promena postane cluster-wide zabrana.
- Dokumentovan break-glass. Postupak navodi ko odobrava, koji binding se privremeno uklanja, kako se čuva dokaz, koliko izuzetak traje i kojim testom se enforcement bezbedno vraća.
- Bez tajni u pravilima i porukama. Policy, parametri, audit annotations i denial poruke ne sadrže tokene, privatne registry podatke ili sadržaj Secrets objekata.
- Komplementarne kontrole. Pod Security Admission, RBAC, NetworkPolicy, image scanning, potpisivanje, runtime nadzor i GitOps drift kontrola rešavaju različite slojeve; admission politika nije njihova zamena.
Završna kontrolna tačka
- ☐ Objašnjavam tačan položaj mutating i validating admission faza posle autentikacije i autorizacije.
- ☐ Razlikujem ugrađeni kontroler, ValidatingAdmissionPolicy/CEL, validating webhook, mutating webhook i CI proveru.
- ☐ Mogu da dokažem da je
admissionregistration.k8s.io/v1capability dostupan na ciljnom klasteru. - ☐ Policy i binding imaju odvojenu odgovornost, najmanji scope i eksplicitne operacije i resurse.
- ☐ CEL izrazi bezbedno proveravaju opciona polja i imaju pozitivne, negativne i granične testove.
- ☐ Razumem razliku između
validationActionsifailurePolicy. - ☐ Server-side dry-run dokazuje ponašanje API servera, dok client-side dry-run nije dovoljan admission dokaz.
- ☐ Warn/Audit canary daje merljive rezultate pre prelaska na Deny.
- ☐ Izuzetak ne može samostalno postaviti korisnik čiji se zahtev kontroliše.
- ☐ Webhook ima kratak timeout, ispravan TLS identitet, HA raspored, nadzor i dokumentovano fail-open/fail-closed obrazloženje.
- ☐ Znam gde tražim API odgovor, request UID, audit događaj, API server metriku i webhook log.
- ☐ Rollback binding-a i ponovno uključivanje politike testirani su bez globalnog kvara klastera.
- ☐ Nadogradnja Kubernetes minor verzije pokreće proveru CEL biblioteka, policy API-ja, Pod Security verzije i webhook kompatibilnosti.
Zaključak
Admission politike pomeraju standardizaciju sa ručnog pregleda na doslednu kontrolu samog Kubernetes API toka. Administrator sada treba da razume da RBAC odgovara na pitanje ko sme da pošalje promenu, dok admission procenjuje sadržaj dozvoljenog zahteva. ValidatingAdmissionPolicy i CEL pružaju stabilan, deklarativan i in-process način za veliki broj validacionih pravila; binding daje scope, parametre i režim sprovođenja. Pod Security Admission pokriva standardnu pod bezbednosnu osnovu, a webhook ostaje moćan, ali operativno skuplji izbor za mutaciju i složene provere.
Praktična vrednost policy as code pristupa nije samo u odbijanju pogrešnog manifesta. Ona je u sledljivom zahtevu, testovima, code review-u, canary primeni, jasnoj denial poruci, audit dokazu, merljivoj latenciji i pouzdanom rollback-u. Politika koja nema vlasnika, testni skup, ograničen scope i recovery proceduru nije enterprise kontrola, čak i kada je njen CEL izraz sintakski ispravan.
Odgovornost administratora je da izbalansira bezbednost i dostupnost kontrolne ravni. Fail-closed pravilo može sprečiti rizičnu konfiguraciju, ali i blokirati oporavak; fail-open čuva dostupnost, ali mora proizvesti vidljiv bezbednosni signal. Zato se odluke zasnivaju na threat modelu i dokazima, a ne na univerzalnom receptu. Ovaj disciplinovani model priprema teren za sledeću lekciju, u kojoj Git postaje izvor željenog stanja, a GitOps rekonsilijacija i detekcija drift-a povezuju odobrenu promenu sa dokazom njene stvarne primene.