Vanilla Kubernetes
Prethodne lekcije razdvojile su ljudske i mašinske identitete, ograničile njihova prava RBAC pravilima i sprečile privilegovane workload-e admission kontrolom. Ova lekcija zatvara bezbednosnu celinu pitanjem koje ostaje i kada su identitet i autorizacija dobro projektovani: kako zaštititi akreditacije koje aplikacije moraju da koriste, kako dokazati ko je pristupio API-ju i kako povezati tehnički događaj sa odobrenom administrativnom promenom.
Kubernetes Secret je API objekat namenjen maloj količini osetljivih podataka, ali nije samostalan trezor. Base64 zapis nije enkripcija; API server, etcd, RBAC, kubelet, čvor, aplikacioni proces, CI/CD sistem i rezervna kopija pripadaju istom životnom ciklusu tajne. Audit evidencija, sa druge strane, nije samo „uključen log”: njena politika određuje koji zahtev se beleži, u kom obimu, u kojoj fazi i uz kakav rizik da se osetljivi sadržaj ponovo otkrije u log sistemu.
Secret kao API objekat i granice njegove zaštite
Secret iz osnovne API grupe core/v1 čuva parove ključa i vrednosti i ograničen je na jedan namespace. Uobičajeni tip Opaque nema dodatnu semantičku validaciju poslovnog sadržaja, dok ugrađeni tipovi, kao što su kubernetes.io/tls, kubernetes.io/dockerconfigjson i kubernetes.io/basic-auth, opisuju namenu i mogu proveriti prisustvo određenih ključeva. Tip ne pretvara sadržaj u bezbedniji kriptografski format i ne zamenjuje RBAC, rotaciju ili enkripciju u mirovanju.
Polje data sadrži base64 kodirane bajtove. Ono omogućava prenos binarnog sadržaja kroz JSON/YAML, ali svako ko može da pročita objekat može jednostavno da ga dekodira. Polje stringData prihvata običan tekst pri upisu, koji API server spaja u data; zbog toga manifest sa stringData ne sme biti sačuvan u nezaštićenom Git repozitorijumu, tiketima ili CI logovima. stringData takođe ne funkcioniše dobro sa server-side apply postupkom i ne treba ga koristiti kao osnovu GitOps vlasništva nad poljima.
apiVersion: v1
kind: Secret
metadata:
name: inventory-db
namespace: plat-app
type: Opaque
stringData:
username: inventory_ro
password: REPLACE-OUTSIDE-GIT
Ovaj manifest je obrazac za laboratoriju, a ne preporučeni način čuvanja produkcione lozinke. Komanda kubectl get secret ... -o yaml vraća kodirane vrednosti, dok kubectl get secret ... -o jsonpath zajedno sa dekodiranjem vraća čist tekst. Obe operacije zahtevaju kontrolisani terminal i sprečavanje snimanja izlaza.
Životni ciklus tajne i površine curenja
Tajna nastaje izvan ili unutar klastera, prenosi se do API servera, čuva u etcd-u, distribuira kubelet-u samo kada je potrebna podu, projektuje u kontejner, čita u memoriju procesa, rotira i na kraju opoziva. Svaka etapa ima drugačiju granicu poverenja. TLS štiti prenos do API servera, ali ne štiti od autorizovanog čitanja. Enkripcija u etcd-u štiti podatke u mirovanju, ali API server i dalje vraća čist sadržaj ovlašćenom klijentu. Read-only mount sprečava aplikaciju da menja projektovani fajl, ali ne sprečava proces u kontejneru da ga pročita.
| Površina | Tipičan rizik | Primarna kontrola | Dokaz |
|---|---|---|---|
| Manifest, Git i CI/CD | Čist tekst u istoriji, artefaktu ili logu | Spoljni secret store, šifrovani Git format, maskiranje i kratkotrajne akreditacije | Repo skeniranje, CI audit i pregled istorije |
| API i RBAC | Preširoko get, list ili watch pravo | Najmanje privilegije, namenski namespace i admission politika | kubectl auth can-i i audit događaj |
| etcd i backup | Čitljiv sadržaj u bazi ili snapshot-u | EncryptionConfiguration ili KMS v2, zaštita ključeva i backup enkripcija | Direktna kontrolisana provera etcd zapisa i restore test |
| Čvor i kubelet | Privilegovani pod ili kompromitovan čvor | Pod Security, zaštita hosta, minimalan raspored i izolacija | Node audit, runtime detekcija i raspored podova |
| Kontejner i proces | Environment dump, core dump, debug endpoint ili log | Fajl mount samo potrebnom kontejneru, bez shell-a i bez ispisivanja tajni | Aplikacioni test i skeniranje logova |
| Rotacija i opoziv | Stara vrednost ostaje važeća kod izdavaoca | Preklapajuća rotacija, reload/rollout, opoziv i negativni test | Uspeh novog i neuspeh starog credential-a |
Volume projekcija, environment promenljive i ažuriranje
Secret može biti montiran kao volume, prosleđen kao environment promenljiva ili korišćen kao image pull credential. Za aplikacione akreditacije volume je često bolji izbor: kubelet periodično sinhronizuje projektovani sadržaj i atomski menja simboličke veze kada se Secret promeni. Aplikacija ipak mora ponovo da otvara fajl ili podržava reload; proces koji je vrednost učitao jednom pri pokretanju neće automatski promeniti stanje.
Secret prosleđen kao environment promenljiva ne menja se u već pokrenutom kontejneru. Potreban je kontrolisani rollout poda. Environment je lakše nenamerno izložiti kroz dijagnostičke komande, crash izveštaje ili aplikacioni dump. Volume projektovan korišćenjem subPath takođe ne dobija automatska ažuriranja, pa ga za rotirajuće tajne treba izbegavati. Ažuriranje projektovanog volumena nije trenutno: zavisi od kubelet sinhronizacije i strategije detekcije promena.
apiVersion: v1
kind: Pod
metadata:
name: inventory-api
namespace: plat-app
spec:
serviceAccountName: inventory-api
automountServiceAccountToken: false
containers:
- name: application
image: registry.example.invalid/inventory/api@sha256:REPLACE_DIGEST
volumeMounts:
- name: db-credentials
mountPath: /var/run/secrets/inventory-db
readOnly: true
volumes:
- name: db-credentials
secret:
secretName: inventory-db
defaultMode: 0400
Oktalni režim 0400 ograničava čitanje na vlasnika fajla u okviru modela dozvola kontejnera, ali efektivni UID/GID, fsGroup, runtime i aplikaciona prava moraju se proveriti u stvarnom podu. Jedan pod ima zajedničku granicu bezbednosti: procesi u sidecar kontejnerima dele mrežni i često procesni ili volume kontekst. Ako samo signer treba privatni ključ, mount se dodeljuje samo tom kontejneru, a aplikaciona arhitektura ograničava njegov interfejs.
RBAC, namespace i indirektan pristup tajnama
Pravo get nad Secret objektom otkriva njegov sadržaj. Prava list i watch takođe vraćaju podatke svih odgovarajućih objekata, pa nisu bezbedna „metadata-only” alternativa. resourceNames može ograničiti get na konkretan naziv, ali se ne može pouzdano primeniti na create i ne rešava svaki obrazac list/watch zahteva. Administrator zato ne dodeljuje čitanje svih tajni kontroleru samo zato što mu treba jedna akreditacija.
Mogućnost kreiranja Pod-a, Deployment-a ili drugog workload-a u namespace-u često predstavlja indirektnu mogućnost čitanja tajni u tom namespace-u: napadač može kreirati pod koji montira poznati Secret ili koristi privilegovaniji ServiceAccount. Pod Security Standards sprečavaju deo host eskalacija, ali ne odlučuju koji namespace Secret workload sme da referencira. Potrebni su razdvojeni namespace-i, najmanje RBAC privilegije, admission pravila i kontrola ServiceAccount dodele.
Secret se šalje samo čvoru na kome je raspoređen pod koji ga zahteva, a kubelet ga za volume drži u tmpfs. To smanjuje nepotrebnu distribuciju, ali privilegovani workload na istom čvoru ili kompromitovan node može preći ovu granicu. Lekcija 37 zato nije odvojena tema: zabrana privilegovanih podova neposredno štiti i tajne drugih workload-a na čvoru.
Immutable Secret i operativni kompromis
Polje immutable: true sprečava naknadnu promenu data i immutable sadržaja i može smanjiti opterećenje API servera jer kubelet ne mora da održava watch za taj objekat. Ono štiti od slučajnog prepisivanja, ali ne šifruje podatke, ne sprečava čitanje i ne obezbeđuje automatsku rotaciju. Jednom postavljen immutable Secret mora se obrisati i ponovo kreirati ili zameniti novim imenom; podovi koji ga koriste moraju biti kontrolisano rekonfigurisani.
apiVersion: v1
kind: Secret
metadata:
name: inventory-db-v2
namespace: plat-app
type: Opaque
immutable: true
data:
username: BASE64_VALUE
password: BASE64_VALUE
Produkcioni obrazac sa verzionisanim imenom omogućava da stari i novi credential kratko koegzistiraju, da se workload prebaci na novu referencu i da se stari credential opozove tek nakon validacije. Rizik je gomilanje zastarelih Secret objekata; vlasnik, rok opoziva i cleanup moraju biti deo promene.
Enkripcija podataka u mirovanju
Bez eksplicitne konfiguracije API server koristi provider identity, što znači da se resurs ne šifruje pre čuvanja u etcd-u. Enkripcija diska ili storage sistema korisna je, ali nije ista kontrola kao Kubernetes encryption at rest: EncryptionConfiguration štiti vrednost na nivou API resursa pre nego što je etcd primi. I dalje su potrebni TLS, RBAC, zaštita control-plane hosta i šifrovane rezervne kopije.
Provider-i se obrađuju redom. Prvi provider služi za novi upis, a naredni za čitanje postojećeg sadržaja. identity kao poslednji fallback omogućava migraciju ranije nešifrovanih zapisa; ako ostane prvi, novi podaci se i dalje čuvaju kao čist tekst. Lokalni ključ u EncryptionConfiguration fajlu štiti od krađe samog etcd-a, ali ne i od kompromitovanja control-plane hosta koji sadrži ključ.
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key-2026-07
secret: REPLACE_WITH_BASE64_32_BYTE_KEY
- identity: {}
Primer pokazuje format i migracioni redosled, ali lokalni aescbc nije najbolji izbor za novu produkcionu platformu: aktuelna Kubernetes dokumentacija ga označava slabijim zbog svojstava CBC režima. aesgcm zahteva disciplinovanu automatizovanu rotaciju zbog ograničenja bezbedne upotrebe nonce-a. Za novu enterprise implementaciju prednost ima stabilni KMS v2, dostupan kao stable od Kubernetes 1.29, sa ključem za šifrovanje ključeva izvan klastera. KMS v1 je deprecated od 1.28 i ne treba ga birati za novu arhitekturu.
KMS uvodi novu dostupnosnu zavisnost: API server mora komunicirati sa KMS pluginom i spoljnim sistemom ključeva. Pre produkcije proveravaju se redundansa plugina i KMS servisa, latencija, TLS ili druga zaštita transporta, prava korišćenja KEK-a, ponašanje pri prekidu, monitoring, backup konfiguracije i disaster-recovery postupak. Gubitak ključa može učiniti podatke trajno nečitljivim; dostupnost kopije etcd-a nije dovoljna za oporavak.
Uvođenje, migracija i rotacija ključa za enkripciju
EncryptionConfiguration mora biti dostupna svakom kube-apiserver procesu i konfiguracija mora biti usklađena na svim control-plane čvorovima. U kubeadm klasteru to obično znači bezbedno postavljanje fajla na svaki čvor, read-only mount u static Pod manifest i parametar --encryption-provider-config. Promena static Pod manifesta restartuje lokalni API server i zato se u HA klasteru izvodi jedan po jedan čvor, uz proveru health endpoint-a, quorum-a i klijentskog pristupa pre prelaska na sledeći.
Aktiviranje konfiguracije utiče samo na nove upise. Postojeći Secret objekti moraju se ponovo upisati da bi bili šifrovani prvim provider-om. Zvanični postupak koristi kontrolisani read/write svih Secret objekata, ali time se menja resourceVersion, može pokrenuti watch događaje i opteretiti API server i etcd. Pre migracije prave se provereni etcd snapshot i kopija konfiguracije ključeva, procenjuje broj objekata, prati latencija i bira period promene.
# State-changing: ponovo upisuje sve Secret objekte.
# Izvršava se samo u odobrenom prozoru promene i posle backup-a.
kubectl get secrets --all-namespaces -o json \
| kubectl replace -f -
Rotacija lokalnog ključa izvodi se dodavanjem novog ključa na prvo mesto, usklađivanjem svih API servera, ponovnim upisom resursa, proverom ciphertext-a i tek zatim uklanjanjem starog ključa. Uklanjanje ključa pre potpune migracije čini preostale zapise nečitljivim. Kod KMS-a se prati dokumentovani postupak konkretnog plugina i provajdera; rotacija KEK-a, dostupnost starih verzija ključa i re-encryption nisu univerzalno isti među implementacijama.
Dokaz da je enkripcija stvarno aktivna
kubectl get secret nije validan dokaz enkripcije u mirovanju, jer API server ovlašćenom klijentu namerno dešifruje objekat. Dokaz zahteva kontrolisan direktan pregled sirovog zapisa u etcd-u ili drugi podržani mehanizam platforme. Provera se izvršava na control-plane/etcd hostu nalogom sa pristupom etcd sertifikatima, bez prikazivanja tajne u tiketu ili zajedničkom terminalu.
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
get /registry/secrets/plat-app/encryption-check \
--write-out=fields
Tačne putanje sertifikata i endpoint zavise od instalacije. Očekuje se prefiks koji identifikuje Kubernetes enkripcioni provider, na primer k8s:enc:kms:v2: ili odgovarajući lokalni provider, a poznata čista test vrednost ne sme biti vidljiva. Komanda nosi visoku privilegiju i ne koristi se iz aplikacionog poda. U upravljanom klasteru direktan etcd pristup najčešće nije dostupan; tada se koristi dokaz i kontrola koju objavljuje provajder, uz proveru njegove dokumentacije i odgovornosti korisnika.
Spoljni secret store i CSI integracija
Spoljni trezor može centralizovati izdavanje, rotaciju, audit i HSM/KMS zaštitu. Secrets Store CSI Driver i provider specifični plugin-i mogu montirati sadržaj u pod bez trajnog Kubernetes Secret objekta, ali to nije deo osnovnog Kubernetes API-ja i zahteva dodatne komponente, CRD objekte i podržan provider. Sinhronizovanje spoljne vrednosti nazad u Kubernetes Secret ponovo uvodi etcd kopiju i sve njene rizike.
Arhitekta proverava autentikaciju workload-a prema trezoru, dostupnost i rate limit, ponašanje pri isteku lease-a, rotaciju montiranog sadržaja, restart aplikacije, fail-closed/fail-open ponašanje, backup metapodataka i recovery kada je trezor nedostupan. Spoljni proizvod ne uklanja potrebu za najmanjim privilegijama na Kubernetes strani niti za audit korelacijom između API servera, CSI komponente i samog trezora.
Kubernetes audit arhitektura
Audit događaj nastaje u kube-apiserver-u za zahtev koji prolazi kroz API. Audit nije isto što i Kubernetes Event objekat: Event opisuje operativne događaje resursa i ima ograničen životni vek, dok audit beleži bezbednosni kontekst API zahteva. Ako --audit-policy-file nije konfigurisan, API server ne beleži audit događaje. Politika bira sadržaj, a backend ga čuva; ugrađeni backend-i su log fajl i webhook.
Zahtev može proizvesti faze RequestReceived, ResponseStarted za dugotrajne zahteve, ResponseComplete i Panic. Čuvanje svih faza stvara duplikate iz perspektive jednostavne analize i povećava obim. Često se globalno izostavlja RequestReceived, a ResponseComplete koristi kao glavni dokaz ishoda. Kod watch zahteva relevantan je i ResponseStarted.
| Nivo | Sadržaj | Primena i rizik |
|---|---|---|
None | Nema događaja | Samo za dokazano bučne i niskorizične zahteve; stvara slepu tačku |
Metadata | Identitet, vreme, verb, resurs i odgovor bez tela | Bezbedna početna osnova i preporučeni nivo za Secret pristup |
Request | Metadata i telo zahteva | Korisno za promene, ali može zabeležiti lozinku, token ili privatni ključ |
RequestResponse | Metadata, zahtev i odgovor | Najbogatiji dokaz i najveći rizik curenja i potrošnje prostora |
Projektovanje audit politike bez curenja tajni
Pravila se obrađuju redom i prvo podudarno pravilo pobeđuje. Specifične zaštitne i visokorizične kategorije moraju zato stajati pre opšteg catch-all pravila. Za Secret objekte se koristi Metadata: telo create/update/patch zahteva ili odgovor na get/list može sadržati samu tajnu. Isto važi za TokenReview i SubjectAccessReview zahteve, određene ConfigMap objekte, exec/attach parametre i CRD resurse koji čuvaju akreditacije bez Secret tipa.
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- RequestReceived
rules:
# Nikada ne beležiti tela Secret zahteva ili odgovora.
- level: Metadata
resources:
- group: ""
resources: ["secrets"]
# TokenReview zahtev nosi bearer token u telu.
- level: Metadata
resources:
- group: authentication.k8s.io
resources: ["tokenreviews"]
# Detaljan zahtev za administrativne promene bez osetljivih tela.
- level: Request
verbs: ["create", "update", "patch", "delete", "deletecollection"]
resources:
- group: rbac.authorization.k8s.io
resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
- group: admissionregistration.k8s.io
resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"]
# Pod exec/attach je visokorizičan, ali telo nije potrebno za osnovni trag.
- level: Metadata
resources:
- group: ""
resources: ["pods/exec", "pods/attach", "pods/portforward"]
# Svi ostali API zahtevi: osnovni dokaz.
- level: Metadata
omitStages:
- RequestReceived
Politika je polazni enterprise profil, ne univerzalna gotova konfiguracija. Pre primene inventarišu se CRD objekti koji sadrže tajne, zahtevi cloud kontrolera, compliance rok čuvanja i kapacitet backend-a. Posebno se testiraju patch zahtevi: njihovo telo može sadržati vrednost koju ne želimo u logu. Ako je za istragu potrebno više detalja, ciljano podizanje nivoa mora imati vremensko ograničenje, vlasnika, procenu curenja i plan povratka.
Audit backend, dostupnost i zaštita evidencije
Log backend upisuje strukturisani JSON na putanju zadatu sa --audit-log-path; parametri ograničavaju veličinu, broj kopija, starost i kompresiju. Webhook backend šalje događaje spoljašnjem servisu preko kubeconfig-a. Režim blocking povezuje odgovor API servera sa upisom i povećava latenciju, dok batch poboljšava performanse, ali pri padu može izgubiti baferovane događaje. blocking-strict strože propagira greške backend-a i zahteva pažljivu procenu dostupnosti klastera.
--audit-policy-file=/etc/kubernetes/audit/policy.yaml
--audit-log-path=/var/log/kubernetes/audit/audit.log
--audit-log-format=json
--audit-log-mode=batch
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-log-compress=true
Putanja i vrednosti su primer; retention se određuje prema zakonu, internom standardu, obimu, SIEM kapacitetu i RPO/RTO ciljevima. Direktorijum mora postojati na hostu, biti montiran u kube-apiserver static Pod i zaštićen minimalnim filesystem pravima. Rotacija na svakom HA control-plane čvoru nije centralna evidencija: događaji se moraju pouzdano sakupiti, vremenski sinhronizovati i poslati u kontrolisani log sistem.
Audit log je bezbednosno osetljiv jer sadrži identitete, mrežne adrese, user-agent, nazive resursa i ponekad tela. Potrebni su enkripcija u prenosu i mirovanju, ograničen pristup, integritet ili WORM kontrola kada je zahtevana, detekcija prekida toka, monitoring popunjenosti diska i odvojeni administrativni domen. Administrator koji može menjati klaster ne bi trebalo neopaženo da briše i centralni dokaz sopstvene promene.
Anatomija audit događaja i korelacija
Najkorisnija polja su auditID, stage, requestURI, verb, user.username, grupe, sourceIPs, userAgent, objectRef, responseStatus, vreme prijema i završetka, kao i anotacije admission i authorization mehanizama kada postoje. auditID povezuje faze jednog API zahteva, ali nije automatski ID poslovne promene.
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "4f2d0c5a-EXAMPLE",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/plat-app/secrets/inventory-db",
"verb": "get",
"user": {
"username": "system:serviceaccount:plat-app:inventory-api"
},
"sourceIPs": ["10.244.2.17"],
"objectRef": {
"resource": "secrets",
"namespace": "plat-app",
"name": "inventory-db",
"apiVersion": "v1"
},
"responseStatus": {"code": 200}
}
Primer namerno nema requestObject ni responseObject. Kod get operacije telo odgovora bi sadržalo Secret podatke. Uspešan HTTP kod dokazuje da je zahtev izvršen, ali ne dokazuje da je promena bila odobrena. Za to su potrebni Git commit, pull request, tiket promene, identitet CI/CD sistema, digest artefakta i rezultat posle implementacije.
Trag administrativne promene
Pouzdan trag odgovara na pitanja: ko je odobrio, ko ili koji sistem je izvršio, šta je bilo planirano, koji objekat i UID su promenjeni, kada, iz kog izvora konfiguracije, sa kojim rezultatom i kako se vraća prethodno stanje. Kubernetes čuva metadata.managedFields radi vlasništva nad poljima server-side apply-a, ali to nije nepromenljiv istorijski dnevnik. Anotacija kubernetes.io/change-cause i lokalna istorija kubectl takođe nisu dovoljne.
| Sloj dokaza | Šta dokazuje | Šta ne dokazuje samostalno |
|---|---|---|
| Git commit i potpisani PR | Nameravanu deklarativnu razliku i pregled | Da je baš ta verzija primenjena |
| CI/CD ili GitOps zapis | Artefakt, identitet automatizacije i vreme deployment-a | Svaku ručnu promenu van pipeline-a |
| Kubernetes audit | Stvarni API zahtev, principal, objekat i ishod | Poslovno odobrenje i razlog |
| Tiket promene | Rizik, odobrenje, prozor, test i rollback | Tehničko izvršenje bez korelacije |
| Monitoring i test | Efekat promene i oporavak usluge | Tačan autor svake API operacije |
Praktičan obrazac je label ili anotacija sa internim change ID-jem koja ne sadrži tajnu, uz isti ID u Git/CI zapisu. Audit politika na nivou Request može zabeležiti taj metadata podatak za bezbedne resurse. Za Secret se ostaje na Metadata, pa korelacija koristi vreme, identitet automatizacije, namespace, naziv objekta, UID/resourceVersion i spoljašnji pipeline zapis umesto tela zahteva.
Provera audit stanja i dijagnostika
Na kubeadm control-plane čvoru API server je obično static Pod. Read-only provera najpre ispituje manifest, aktivni kontejner i postojanje mount-a. Ne pretpostavlja se da je /var/log/kubernetes/audit/audit.log univerzalna putanja.
sudo grep -E -- '--audit-(policy-file|log-path|webhook-config-file)' \
/etc/kubernetes/manifests/kube-apiserver.yaml
kubectl -n kube-system get pods -l component=kube-apiserver -o wide
sudo test -r /var/log/kubernetes/audit/audit.log && \
sudo tail -n 5 /var/log/kubernetes/audit/audit.log | jq .
Ako fajl ne postoji, moguće je da audit nije omogućen, da se koristi druga putanja, webhook ili upravljani servis provajdera, ili da static Pod nije uspeo da montira direktorijum. Promena politike nije običan kubectl apply API objekat: ona menja konfiguraciju svakog kube-apiserver procesa i može izazvati restart. Sintaksa se proverava u laboratoriji i na jednom HA članu, zatim se validira dostupnost pre nastavka.
# Primer filtera nad lokalnim JSON-lines audit fajlom.
sudo jq -c '
select(.stage == "ResponseComplete")
| select(.objectRef.resource == "secrets")
| {time: .stageTimestamp,
user: .user.username,
verb: .verb,
namespace: .objectRef.namespace,
name: .objectRef.name,
code: .responseStatus.code,
auditID: .auditID}' \
/var/log/kubernetes/audit/audit.log
Integrisani praktikum: tajna, rotacija i dokaz promene
Cilj i kontekst. Aplikacija inventory-api u namespace-u secret-audit-lab koristi baznu akreditaciju montiranu kao fajl. Tim mora dokazati da ServiceAccount ne može API-jem čitati Secret, da promena tajne ostavlja audit trag bez vrednosti, da aplikacija vidi novu verziju i da se stara akreditacija može opozvati. Praktikum ne menja EncryptionConfiguration; taj control-plane postupak izdvojen je u narednu bezbednu vežbu.
Preduslovi i rizik. Potrebni su laboratorijski klaster, kubectl, pravo kreiranja namespace resursa i odobren pristup audit evidenciji. Ne koriste se stvarne lozinke. Sadržaj tajne ne unosi se u shell argument, Git niti tiket; generiše se u privremenom fajlu sa režimom 0600. Cleanup briše namespace i zato se ne izvršava u deljenom okruženju.
-
Proveriti kontekst, identitet i audit preduslov.
Očekivanje: prve tri komande potvrđuju namenski laboratorijski klaster.kubectl config current-context kubectl auth whoami kubectl cluster-info kubectl get namespace secret-audit-labNotFoundza namespace je prihvatljiv. Audit pristup se zasebno potvrđuje prema načinu instalacije; bez njega funkcionalni deo može da se izvede, ali kriterijum dokaza nije ispunjen. -
Kreirati namespace, ServiceAccount i workload bez API tokena.
Ovo su state-changing komande. Validacija:kubectl create namespace secret-audit-lab kubectl -n secret-audit-lab create serviceaccount inventory-api kubectl -n secret-audit-lab patch serviceaccount inventory-api \ --type=merge \ -p '{"automountServiceAccountToken":false}'
Očekuju sekubectl -n secret-audit-lab get serviceaccount inventory-api \ -o jsonpath='{.automountServiceAccountToken}{"\n"}' kubectl auth can-i get secrets \ --as=system:serviceaccount:secret-audit-lab:inventory-api \ -n secret-audit-labfalseino. Druga komanda zahteva pravo impersonacije izvršioca. -
Kreirati testnu tajnu bez izlaganja kroz argument procesa.
umask 077 LAB_SECRET_FILE=$(mktemp) openssl rand -base64 24 > "$LAB_SECRET_FILE" kubectl -n secret-audit-lab create secret generic inventory-db-v1 \ --from-file=password="$LAB_SECRET_FILE" shred -u "$LAB_SECRET_FILE" unset LAB_SECRET_FILEshrednije pouzdana garancija na copy-on-write ili journaling storage-u; ovde smanjuje laboratorijski trag, dok produkcija koristi kontrolisani secret manager/pipeline. Vrednost se ne ispisuje. Validacija:
Filter ne prikazuje vrednosti. Ipak, ni nazive ključeva ne treba kopirati u javni log ako otkrivaju osetljivu strukturu sistema.kubectl -n secret-audit-lab get secret inventory-db-v1 -o json \ | jq '{name: .metadata.name, type: .type, keys: (.data | keys)}' -
Kreirati Deployment koji mount-uje samo potrebni Secret.
Ako slika ne podržava zadati non-root UID ili klaster nema pristup registru, pod neće postati Ready; proveravaju sekubectl -n secret-audit-lab apply -f - <<'EOF' apiVersion: apps/v1 kind: Deployment metadata: name: inventory-api labels: app: inventory-api change-id: CHG-LAB-0038 spec: replicas: 1 selector: matchLabels: app: inventory-api template: metadata: labels: app: inventory-api change-id: CHG-LAB-0038 spec: serviceAccountName: inventory-api automountServiceAccountToken: false securityContext: seccompProfile: type: RuntimeDefault containers: - name: application image: registry.k8s.io/busybox:1.36.1 command: ["sh", "-c", "while true; do sleep 3600; done"] securityContext: allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 65532 capabilities: drop: ["ALL"] volumeMounts: - name: credentials mountPath: /var/run/secrets/inventory readOnly: true volumes: - name: credentials secret: secretName: inventory-db-v1 defaultMode: 0400 EOF kubectl -n secret-audit-lab rollout status \ deployment/inventory-api --timeout=120sdescribe podi događaji, a ne slabi securityContext. -
Dokazati mount bez otkrivanja vrednosti.
Očekuje se neprazan fajl režima približnoPOD_NAME=$(kubectl -n secret-audit-lab get pod -l app=inventory-api \ -o jsonpath='{.items[0].metadata.name}') kubectl -n secret-audit-lab exec "$POD_NAME" -- \ sh -c 'test -s /var/run/secrets/inventory/password && \ stat -c "mode=%a bytes=%s" /var/run/secrets/inventory/password' kubectl -n secret-audit-lab exec "$POD_NAME" -- \ sh -c 'test ! -e /var/run/secrets/kubernetes.io/serviceaccount/token'400i odsustvo ServiceAccount tokena. Efektivni prikaz režima može zavisiti od runtime-a i securityContext-a; važan je uspešan read samo predviđenog procesa i dokumentovana interpretacija. -
Napraviti verziju v2 i kontrolisano prebaciti Deployment.
Očekivani rezultat: promena PodTemplate-a pokreće kontrolisani rollout i nova replika mount-ujeumask 077 LAB_SECRET_FILE=$(mktemp) openssl rand -base64 24 > "$LAB_SECRET_FILE" kubectl -n secret-audit-lab create secret generic inventory-db-v2 \ --from-file=password="$LAB_SECRET_FILE" shred -u "$LAB_SECRET_FILE" unset LAB_SECRET_FILE kubectl -n secret-audit-lab patch deployment inventory-api \ --type=json \ -p='[{"op":"replace","path":"/spec/template/spec/volumes/0/secret/secretName","value":"inventory-db-v2"}]' kubectl -n secret-audit-lab rollout status \ deployment/inventory-api --timeout=120sinventory-db-v2. U produkciji se ista izmena radi u izvornom deklarativnom manifestu i prolazi Git review; direktni patch ovde služi da laboratorija jasno pokaže API promenu i audit korelaciju. Ako rollout ne uspe,kubectl rollout undo deployment/inventory-apivraća prethodni PodTemplate dok je v1 Secret još prisutan i važeći. -
Proveriti audit korelaciju bez tela tajne.
Na audit backend-u filtrirati vreme laboratorije, namespace, Secret nazive i change ID pod-a. Primer za lokalni log:
Secret događaji moraju imatisudo jq -c ' select(.stage == "ResponseComplete") | select(.objectRef.namespace == "secret-audit-lab") | select(.objectRef.resource == "secrets" or .objectRef.resource == "pods") | {time: .stageTimestamp, user: .user.username, verb: .verb, resource: .objectRef.resource, name: .objectRef.name, code: .responseStatus.code, auditID: .auditID, hasRequestBody: has("requestObject"), hasResponseBody: has("responseObject")}' \ /var/log/kubernetes/audit/audit.loghasRequestBody: falseihasResponseBody: falsekada je primenjena politika iz lekcije. Ako sadrže telo, incidentno se ograničava pristup audit sistemu, procenjuje izlaganje i koriguje redosled pravila. -
Opozvati v1 i dokazati završno stanje.
Nakon potvrde da workload koristi v2 i da backend prihvata novu akreditaciju, stara akreditacija se opoziva u stvarnom izdavaocu, zatim se briše v1 Kubernetes Secret.
Očekuje se referenca nakubectl -n secret-audit-lab get deployment inventory-api \ -o jsonpath='{.spec.template.spec.volumes[?(@.name=="credentials")].secret.secretName}{"\n"}' kubectl -n secret-audit-lab delete secret inventory-db-v1 kubectl -n secret-audit-lab get secret inventory-db-v1inventory-db-v2i zatimNotFoundza v1. Brisanje Kubernetes objekta ne opoziva automatski lozinku u bazi, API ključ kod provajdera ili sertifikat kod CA; opoziv na izvoru je obavezna posebna akcija. -
Cleanup i rollback.
Pre brisanja sačuvati samo metadata/audit dokaz bez vrednosti. U izolovanoj laboratoriji:
Komanda briše sve namespace resurse i ne izvršava se u deljenom namespace-u. Rollback produkcione rotacije vraća referencu na v1 samo dok je v1 credential i dalje važeći; nakon opoziva potreban je novi kontrolisani credential, ne „oživljavanje” kompromitovane tajne.kubectl delete namespace secret-audit-lab
Kontrolisana vežba: uvođenje audit politike na kubeadm control-plane-u
Rizik. Ova vežba menja static Pod konfiguraciju kube-apiserver-a i može prekinuti API. Izvodi se samo u laboratoriji ili odobrenom HA prozoru, jedan control-plane čvor odjednom. Pre početka moraju postojati etcd snapshot, kopija static Pod manifesta, konzolni/SSH pristup i dokaz da preostali API serveri rade.
- Sačuvati SHA-256 hash i bezbednu kopiju postojećeg manifesta; proveriti etcd i API health.
- Kreirati policy i host direktorijum audit loga sa minimalnim pravima. Policy se prvo validira u neprodukcijskom okruženju.
- U static Pod manifest dodati hostPath/volumeMount za policy i log direktorijum i parametre iz prethodnog primera. Ne uređivati sve HA čvorove istovremeno.
- Pratiti lokalni container runtime i kubelet journal dok se API server ponovo kreira:
sudo journalctl -u kubelet --since '-10 minutes' -f sudo crictl ps -a --name kube-apiserver - Sa druge administratorske stanice potvrditi
/readyz, kreirati bezopasnu ConfigMap i pronaći odgovarajućiResponseCompleteaudit događaj. - Ako API server ne postane Ready u odobrenom roku, vratiti tačnu prethodnu kopiju manifesta preko konzolnog pristupa, sačekati static Pod recovery i tek onda analizirati YAML, mount i filesystem prava. Ne nastavljati na druge čvorove.
Incident response: otkrivena tajna ili kompromitovan audit trag
- Simptom i obim. Utvrditi koja vrednost, namespace, workload, spoljni sistem i period su pogođeni; razlikovati kodiranu vrednost, hash, ciphertext i stvarni credential. Proveriti Git, CI, audit, aplikacione logove, backup i terminalske snimke.
- Sačuvati dokaze. Sačuvati metapodatke, hash relevantnog artefakta, auditID, vreme, principal, source IP i promenu bez umnožavanja same tajne. Ograničiti pristup kompromitovanom log skladištu.
- Ograničiti štetu. Ukloniti nepotrebni RBAC binding, izolovati kompromitovani workload i privremeno zaustaviti distribuciju. Poslovni vlasnik odlučuje o prekidu usluge; bezbednosni tim vodi dokaz.
- Rotirati i opozvati na izvoru. Izdati novu akreditaciju, prebaciti potvrđene potrošače i opozvati staru kod baze, CA, registry-ja ili cloud provajdera. Promena samo Kubernetes Secret objekta nije opoziv.
- Validirati oporavak. Pozitivni test nove i negativni test stare vrednosti, stabilnost workload-a, odsustvo novih pristupa i konzistentan audit tok moraju biti dokazani.
- Trajna mera. Ukloniti tajnu iz Git istorije i keševa prema odobrenom postupku, korigovati audit nivo, uvesti skeniranje, razdvojiti namespace/identitete i dokumentovati osnovni uzrok. Sama revizija Git istorije ne ukida već kopirane credential-e.
Ako audit događaji iznenada prestanu, prvo se proveravaju health i kapacitet backend-a, disk, mreža, sertifikati webhook-a, queue/drop metrike i poslednje control-plane promene. Privremeni workaround može biti prelazak na lokalni log uz pojačan nadzor, ali trajna korekcija mora vratiti centralnu, zaštićenu evidenciju i utvrditi da li je tokom praznine bilo promena.
Tipične greške i njihovo razlikovanje
| Simptom | Neposredni uzrok | Osnovna provera i korekcija |
|---|---|---|
| Base64 vrednost se smatra šifrovanom | Pomešano kodiranje i enkripcija | Proveriti EncryptionConfiguration i sirov etcd zapis; uvesti KMS/encryption at rest |
| Aplikacija posle rotacije koristi staru lozinku | Environment promenljiva ili proces kešira fajl | Proveriti način projekcije; kontrolisani reload ili rollout |
| Secret volume se ne ažurira | Korišćen subPath, immutable objekat ili kubelet kašnjenje | Pregled Pod manifesta, Secret resourceVersion i kubelet loga |
| Novi zapisi su šifrovani, stari nisu | Postojeći resursi nisu ponovo upisani | Posle backup-a izvesti kontrolisanu migraciju i ponoviti etcd proveru |
| API server ne čita Secret posle rotacije ključa | Stari ključ prerano uklonjen ili čvorovi imaju različite konfiguracije | Vratiti prethodni provider/ključ, uskladiti sve API servere, zatim ponovo migrirati |
| Audit log sadrži lozinku ili token | Request/RequestResponse pravilo uhvatilo osetljivi resurs | Ograničiti log, rotirati izloženu tajnu i postaviti specifično Metadata pravilo pre catch-all pravila |
| Nema audit događaja | Nema policy parametra, pogrešan mount/putanja ili backend ne radi | Pregled static Pod args, kubelet/runtime logova, direktorijuma i webhook health-a |
| Ista promena se vidi više puta | Više audit faza ili retry klijenta | Korelisati po auditID, fazi, vremenu i objektu; ne brojati svaki red kao novu promenu |
Audit pokazuje system:serviceaccount umesto osobe | Promenu je izvršila automatizacija | Povezati ServiceAccount sa CI/GitOps run ID-jem, commit-om i odobrenjem |
Administratorske prakse
- Inventar i vlasništvo. Najmanje kvartalno evidentirati Secret naziv, tip, namespace, vlasnika, potrošače, izvor, poslednju rotaciju, rok isteka i klasifikaciju. Vrednosti se nikada ne izvoze u inventar.
- Pregled efektivnog pristupa. Posle svake RBAC promene i kvartalno proveriti ko ima
get,list,watchili indirektno pravo kreiranja workload-a u namespace-u. Neočekivan pristup je bezbednosni nalaz, ne samo administrativna neurednost. - Rotacija zasnovana na riziku. Rotirati pre isteka, posle promene vlasnika, sumnje na izlaganje ili promene trust boundary-ja. Svaka rotacija ima preklapanje, test nove vrednosti, opoziv stare i rok cleanup-a.
- Dokaz enkripcije i oporavka. Posle uvođenja ili rotacije encryption provider-a proveriti novi i migrirani sirovi etcd zapis, backup enkripciju i restore u izolovanom okruženju. KMS ključ i plugin konfiguracija ulaze u DR plan bez čuvanja ključa uz snapshot.
- Audit profil i kapacitet. Najmanje kvartalno proveriti pokrivenost visokorizičnih resursa, odsustvo tela tajni, stopu događaja, drop/queue stanje, disk i centralni prijem. Promena politike prolazi review kao promena bezbednosne kontrole.
- Nezavisnost evidencije. Audit se šalje u odvojeni sistem sa minimalnim pristupom, sinhronizovanim vremenom, retention politikom i alarmom za prekid. Periodično se proverava da klaster administrator ne može neopaženo da ukloni centralni trag.
- Deklarativne promene. Produkcione Secret reference, RBAC i audit konfiguracija prolaze kroz pregledan Git/CI ili GitOps tok. Same tajne ostaju u odobrenom trezoru ili šifrovanom mehanizmu, a change ID povezuje nameru, izvršenje i validaciju.
Završna kontrolna tačka
- Čitalac ume da objasni zašto base64, TLS, RBAC i encryption at rest rešavaju različite probleme.
- Može da izabere volume ili environment projekciju i predvidi ponašanje pri rotaciji.
- Može da dokaže da workload vidi potrebnu tajnu, a da ne ispiše njenu vrednost.
- Prepoznaje direktan i indirektan RBAC pristup Secret objektima.
- Razume redosled provider-a, migraciju postojećih zapisa i rizik preranog uklanjanja ključa.
- Zna zašto je KMS v2 preporučen za novu enterprise arhitekturu i koje dostupnosne zavisnosti uvodi.
- Može da projektuje audit politiku u kojoj Secret i TokenReview ostaju na nivou
Metadata. - Može da pronađe i protumači
auditID, principal, verb, objekat, fazu i ishod zahteva. - Razlikuje audit događaj, Kubernetes Event, managedFields, Git dokaz i poslovno odobrenje.
- Ima bezbedan postupak za rotaciju, opoziv, incident response, rollback i dokaz završnog stanja.
Zaključak
Kubernetes Secret uklanja potrebu da akreditacija bude ugrađena u sliku ili Pod specifikaciju, ali ne uklanja odgovornost za njeno stvaranje, skladištenje, distribuciju, korišćenje, rotaciju i opoziv. Bez encryption at rest konfiguracije etcd može čuvati čitljiv sadržaj; bez preciznog RBAC-a ovlašćeni API korisnik ga može preuzeti; bez zaštite workload-a kompromitovan proces ili čvor može ga pročitati iz izvršnog okruženja.
Audit politika pretvara API aktivnosti u proverljiv tehnički trag samo ako je dovoljno široka da pokrije važne promene, dovoljno selektivna da ne beleži same tajne i dovoljno pouzdano skladištena da preživi kvar ili zlonamernu intervenciju. Nivo RequestResponse nije automatski „bolji”; za Secret, TokenReview i druge poverljive objekte upravo je Metadata bezbedniji i profesionalniji izbor.
Administrativna odgovornost završava se tek kada namera iz odobrene promene može da se poveže sa Git/CI artefaktom, stvarnim audit događajem, monitoring rezultatom i proverljivim rollback-om. Audit ne zamenjuje change management, a change tiket ne dokazuje izvršenje. Njihova korelacija gradi dokaz da je promena bila odobrena, tehnički ispravna i bezbedno završena.
Ovom lekcijom završava se celina o identitetu, autorizaciji i zaštiti workload-a. Čitalac je pripremljen da u narednom delu pređe na dostupnost, skaliranje i observability sa važnom pretpostavkom: sistem se ne smatra pouzdanim samo zato što radi, već kada se može dokazati ko mu pristupa, šta se promenilo, kako su zaštićene akreditacije i kako će se bezbedno oporaviti.