Múlt héten hajnali 2-kor kaptam riasztást egy payment service-re, ami eldobálta a kéréseket. Az első ösztönöm ugyanaz volt, mint mindig: elő a cluster-admin kubeconfig-gal a csapat wiki oldaláról, aztán nézzük, mi van. Tíz perc alatt megtaláltam a hibát, de másnap reggel a security csapat jelezte, hogy az audit logokban ott virít a session-öm. Jogosan. Az a “temporary” cluster-admin kubeconfig nagyjából nyolc hónapja volt használatban.
Szóval végre nekiültem és összeraktam egy rendes debugging workflow-t. Olyat, ami pontosan annyi hozzáférést ad az ügyeletesnek, amennyire szüksége van, pontosan annyi időre, amennyire kell.
Mi a baj a “Használd a cluster-admint” megközelítéssel?
Minden csapatnál, ahol dolgoztam, ugyanaz a sztori. Valaki létrehoz egy magas jogosultságú kubeconfig-ot “csak vészhelyzetekre.” Aztán bekerül a password managerbe, megosztják az egész csapattal, sosem rotálják. Az audit logokban egy generikus service account csinál dolgokat, és senki nem tudja, ki futtatott kubectl exec-et hajnali 3-kor.
A valódi költség nem csak a biztonsági kockázat. Hanem az, hogy ha valami félremegy, nem tudod rekonstruálni, mi történt. A megosztott hitelesítő adatok megölik az audit trail-t.
1. lépés: Namespace-szintű Debug Role
A cluster-admin helyett csináltam egy Role-t, ami lefedi, amire az ügyeletnek tényleg szüksége van:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: oncall-debug
namespace: payments
rules:
- apiGroups: [""]
resources: ["pods", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: [""]
resources: ["pods/exec", "pods/portforward"]
verbs: ["create"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/ephemeralcontainers"]
verbs: ["update"]
Az utolsó szabály a kubectl debug-hoz kell, erről mindjárt lesz szó. A lényeg, hogy ezt egy csoporthoz kötjük, nem egyéni felhasználókhoz:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: oncall-debug
namespace: payments
subjects:
- kind: Group
name: oncall-payments
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: oncall-debug
apiGroup: rbac.authorization.k8s.io
Az identity provider kezeli, ki van az oncall-payments csoportban. Amikor változik az ügyeleti beosztás, senki nem nyúl a Kubernetes RBAC-hoz. A csoport tagság automatikusan frissül.
2. lépés: Rövid életű hitelesítő adatok
A legnagyobb nyereség az volt, hogy olyan credential-ökre váltottunk, amik lejárnak. OIDC-t használunk az identity providerrel, szóval a kubeconfig egyszerűen meghív egy credential helper-t:
users:
- name: oncall
user:
exec:
apiVersion: client.authentication.k8s.io/v1
command: cred-helper
args: ["--cluster=prod", "--ttl=30m"]
30 percenként lejár a token. Nincs több elavult kubeconfig a wiki oldalakon. Ha nincs OIDC beállítva, rövid életű kliens tanúsítványokat is használhatsz:
# Kulcs generálás lokálisan
openssl genpkey -algorithm Ed25519 -out oncall.key
# CSR létrehozása az identitásoddal és a csapat csoporttal
openssl req -new -key oncall.key -out oncall.csr \
-subj "/CN=robert/O=oncall-payments"
Aztán beküldünk egy CertificateSigningRequest-et 30 perces TTL-lel:
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: oncall-robert-20260319
spec:
request: <base64-encoded oncall.csr>
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 1800
usages:
- client auth
Jóváhagyás után kapsz egy tanúsítványt, ami pontosan 30 percig érvényes. A /O=oncall-payments a subject-ben a Kubernetes csoportra képeződik le, szóval az RBAC automatikusan életbe lép.
3. lépés: Ephemeral Containerek SSH Helyett
A régi módszer egy rosszul viselkedő pod debuggolására az volt, hogy kubectl exec-kel beléptünk és menet közben telepítettünk eszközöket. Ez működik, amíg rá nem jössz, hogy a distroless image-eidben nincs curl, tcpdump, de még shell sem.
Az ephemeral containerek ezt rendesen megoldják:
kubectl debug -it payment-api-7d4f8b-x2k9n \
--image=nicolaka/netshoot \
--target=payment-api \
-n payments
Ez egy debug containert csatol a futó podhoz anélkül, hogy újraindítaná. A netshoot image-ben minden hálózati eszköz megvan, amire szükséged lehet. A --target flag megosztja a process namespace-t az app containerrel, szóval látod a folyamatait és hálózati kapcsolatait.
Pár dolog, amit a saját bőrömön tanultam:
- Az ephemeral container ott marad lecsatlakozás után. Nem takarítja el magát. Én egy labelt teszek rá és egy CronJob-bal gyűjtöm össze az elavult debug containereket.
- A resource limitek számítanak. Ha a podod már közel van a memória limitjéhez, egy ephemeral container
tcpdump-pal átlökheti. Állíts be resource request-eket a debug containernek. - Nem minden runtime támogatja a process namespace megosztást. Ellenőrizd, hogy a
shareProcessNamespacenincs explicit kikapcsolva a pod spec-ben.
4. lépés: Mindent naplózz
OIDC-vel vagy kliens tanúsítványokkal minden API hívás valódi identitáshoz kötődik. De azt is tudni akarod, milyen parancsokat futtattak az exec session-ökben. A Kubernetes audit logging rögzíti az API hívásokat:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["pods/exec", "pods/portforward"]
verbs: ["create"]
- level: Metadata
resources:
- group: ""
resources: ["pods/ephemeralcontainers"]
verbs: ["update"]
Ez naplózza a teljes kérést és választ exec-nél és port-forward-nál, és metaadatokat az ephemeral container létrehozásnál. Küldd el a SIEM-edbe és megvan a teljes nyomvonal arról, ki mit debuggolt és mikor.
Mi változott
Miután ezt bevezettük, az incidenskezelésünk tényleg gyorsabb lett. Ellentmondásosan hangzik, de van oka: a mérnökök nem agyalnak azon, hogy “szabad-e” debuggolniuk valamit. A korlátok egyértelműek, a hozzáférés automatikus az ügyeletesnek, és senkinek nem kell hajnali 2-kor megosztott kubeconfig-ot vadásznia.
A beállítás nagyjából egy napot vett igénybe. Ennek nagy részét az OIDC provider csoportos claim-jeinek helyes konfigurálása tette ki (minden identity providernek megvannak a maga szeszélyei). Az RBAC manifestek namespace-enként talán 30 sor YAML.
Ha még mindig megosztott cluster-admin credential-öket használsz production debugging-hoz, ez egy jó hét, hogy abbahagyd. A Kubernetes blog épp tegnap publikált egy részletes útmutatót pontosan erről a témáról, ami még több mintát mutat be, például access broker-eket és hardveres kulcsokat.
Kezdd a namespace-szintű Role-lal és egy RoleBinding-gal egy csoporthoz. Ez önmagában kiküszöböli a kockázat nagy részét. Add hozzá a rövid életű credential-öket, amikor készen állsz, és az ephemeral containereket, amikor a csapat már kényelmesen használja a workflow-t. Nem kell mindent egyszerre megcsinálni.