Két éve futtatom a Falcót runtime securityre a legtöbb klaszteremen. Tette a dolgát, de a kernelmodulos megközelítés mindig törékenynek érződött. Minden kernel frissítésnél benne volt a pakliban, hogy valami eltörik. Amikor a Cilium Tetragon elérte az 1.3-as stabil verziót, tisztán eBPF alapon, kernel modul nélkül, úgy döntöttem, élesben is adok neki egy esélyt.
Ez történt.
Miért váltottam a Falcóról
A Falco jó eszköz, félreértés ne legyen. De újra és újra ugyanazokba a problémákba futottam:
- Kernel modul újrafordítás minden node frissítésnél (az eBPF probe-bal is volt kompatibilitási gond)
- Magas CPU használat 80+ podos node-okon
- Szabály szintaxis, amihez senki nem akart hozzányúlni a csapatban
- False positive-ok, amiktől mindenki ignorálta az alerteket
A Tetragon alacsonyabb overheadet ígért, mert közvetlenül eBPF-en keresztül kapcsolódik a kernelhez. Emellé TracingPolicy CRD-ket ad a finom szabályozáshoz és natív Kubernetes awareness-t. Szkeptikus voltam, de a teljesítményszámokat látva úgy voltam vele, ezt ki kell próbálni.
Tetragon telepítése
Nálam Cilium fut mint CNI, szóval a Tetragon hozzáadása egyszerű volt. Ha nem Cilium a CNI-d, az sem gond. A Tetragon önállóan is működik.
helm repo add cilium https://helm.cilium.io/
helm repo update
helm install tetragon cilium/tetragon \
--namespace kube-system \
--set tetragon.enableProcessCred=true \
--set tetragon.enableProcessNs=true \
--set tetragon.exportRateLimit=200
Az enableProcessCred és enableProcessNs flagek fontosabbak, mint elsőre tűnik. Nélkülük nincs uid/gid infó és namespace kontextus az eventekben. Az első deploynál kihagytam őket, és elment egy órám arra, hogy kiderítsem, miért nem matchelnek a policy-k.
Ellenőrzés:
kubectl get pods -n kube-system -l app.kubernetes.io/name=tetragon
Minden node-on látnod kell egy tetragon podot (DaemonSet).
Az első TracingPolicy
Alapból a Tetragon process lifecycle eventeket ad (exec, exit). Hasznos, de nem ez benne az igazán izgalmas rész. Az ereje a TracingPolicy-ban van.
Itt az első, amit írtam. Elkap minden containert, ami megnyitja az /etc/shadow-t:
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: sensitive-file-access
spec:
kprobes:
- call: fd_install
syscall: false
args:
- index: 0
type: int
- index: 1
type: "file"
selectors:
- matchArgs:
- index: 1
operator: Equal
values:
- "/etc/shadow"
- "/etc/passwd"
- "/etc/kubernetes/pki"
matchNamespaces:
- namespace: Pid
operator: NotIn
values:
- "host_ns"
Alkalmazás:
kubectl apply -f sensitive-file-access.yaml
Tesztelés: lépj be bármelyik podba és próbáld olvasni az /etc/shadow-t:
kubectl exec -it some-pod -- cat /etc/shadow
Nézd meg a Tetragon logokat:
kubectl logs -n kube-system -l app.kubernetes.io/name=tetragon -c export-stdout --tail=20 | \
jq 'select(.process_kprobe != null)'
Egy JSON eventet kell látnod teljes process fával, container ID-val, pod névvel, namespace-szel és labelekkel. Ebben ez a jó. Nincs külön korreláció, nincs sidecar, nincs törékeny log parsing. A kernel megmondja, mi történt, a Tetragon pedig hozzáadja a K8s kontextust.
A policy, ami megmentett minket
Két héttel a Tetragon deploy után elkapott valamit, amit a Falco nem vett észre. Az egyik Java szolgáltatásunk shell subprocesst indított, hogy curl-lel csináljon health checket (igen, tényleg). Csúnya megoldás, de nem rosszindulatú. Viszont ugyanez a minta, Java processből indított shell, pont úgy néz ki, mint egy container escape.
Írtam egy TracingPolicy-t, ami alertel minden nem-init process exec-re konténereken belül:
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: unexpected-process-exec
spec:
kprobes:
- call: sys_execve
syscall: true
args:
- index: 0
type: "string"
selectors:
- matchArgs:
- index: 0
operator: NotIn
values:
- "/bin/sh"
- "/usr/bin/java"
- "/usr/bin/python3"
matchNamespaces:
- namespace: Pid
operator: NotIn
values:
- "host_ns"
matchBinaries:
- operator: NotIn
values:
- "/pause"
- "/usr/bin/tini"
Egy napon belül elkapott egy kompromittált npm dependenciát egy staging szolgáltatásban, ami le akart tölteni és futtatni egy binárist. A process fa így nézett ki: node -> sh -> curl -> suspicious-binary. Simán észrevétlen maradt volna, mert a szolgáltatás közben átment a health checkeken.
Teljesítmény: a számok
Mértem a CPU és memória overheadet egy 120 podos node-on, 3 aktív TracingPolicy mellett:
| Metrika | Falco (eBPF probe) | Tetragon |
|---|---|---|
| CPU (átlag) | 180m | 45m |
| CPU (p99) | 620m | 110m |
| Memória | 340Mi | 95Mi |
| Event latency | ~8ms | ~1.2ms |
A különbség nagyon látványos. A Tetragon nagyjából 4x hatékonyabb CPU-ban és a memória negyedét használja. A jobb event latency azt is jelenti, hogy a policy-k valós időben tudnak enforceolni úgy, hogy nem adnak érezhető késleltetést a syscallokhoz.
Enforcement mód: óvatosan
A Tetragon képes kilőni a policy-nak megfelelő processeket. Ez erős, de kockázatos funkció. Adj hozzá matchActions-t Sigkill-lel egy selectorhoz:
selectors:
- matchArgs:
- index: 0
operator: Equal
values:
- "/usr/bin/wget"
matchActions:
- action: Sigkill
Egy hónapig teszteltem stagingen, mielőtt productionben bekapcsoltam. Kezdd Override actionnel (hibát ad vissza a syscallra) a Sigkill helyett (terminálja a processt). Az Override kevésbé durva, és ad időt a policy-k finomhangolására.
A javaslatom: futtasd observe-only módban legalább 2 hétig klaszterenként. Exportáld az eventeket a SIEM-be, építs dashboardokat, hangold ki a false positive-okat, és csak utána kapcsold be az enforcementet.
Eventek a stackedbe
A Tetragon JSON eventeket exportál, és ezt viszonylag egyszerű bejuttatni az observability stackedbe:
# Közvetlenül stdout-ra (az export-stdout konténer)
kubectl logs -n kube-system -l app.kubernetes.io/name=tetragon -c export-stdout -f
# Vagy használd a tetragon CLI-t szűrt, olvasható kimenethez
kubectl exec -n kube-system ds/tetragon -c tetragon -- \
tetra getevents -o compact
Productionben az export-stdout konténer logjait Fluent Biten keresztül tolom Lokiba. Egy egyszerű Fluent Bit szűrő parse-olja a JSON-t, és hozzáad egy severity mezőt a policy név alapján. Ezután Grafana dashboardokon nézem a process exec eventeket namespace-enként, a fájlhozzáférési szabálysértéseket és a váratlan binárisokból jövő hálózati kapcsolatokat.
A fő panelek nálam:
- Process exec heatmap namespace és bináris név szerint
- Policy violation-ök időben, TracingPolicy név szerint csoportosítva
- Top talkerek: a legtöbb security eventet generáló podok
Buktatók, amikbe belefutottam
1. ARM64 node-oknak friss kernel kell. Ha vegyes amd64/arm64 klasztert futtatsz (mint én Graviton node-okkal EKS-en), győződj meg róla, hogy az ARM node-ok legalább 5.15-ös kernelt futtatnak. Régebbi kerneleken eBPF verifier bugok vannak, amiktől a Tetragon podok CrashLoopolnak.
2. A TracingPolicy sorrend számít. Ha két policy matchel ugyanarra a syscallra, mindkettő tüzel. De ha az egyikben Sigkill action van, a másikban Override, a Sigkill nyer. Dokumentáld a policy-jaidat alaposan.
3. Az export rate limiting a barátod. exportRateLimit=200-at állítottam be a Helm values-ban. Enélkül egy zajos workload (rád nézek, PHP-FPM) másodpercenként ezres nagyságrendben dobja az eventeket, és elárasztja a log pipeline-t.
4. A tetra CLI nélkülözhetetlen a debuggoláshoz. Telepítsd lokálisan:
curl -LO https://github.com/cilium/tetragon/releases/latest/download/tetra-linux-amd64.tar.gz
tar xzf tetra-linux-amd64.tar.gz
sudo mv tetra /usr/local/bin/
Használd a tetra getevents-et --namespace és --pod szűrőkkel, hogy policy-t tudj debugolni anélkül, hogy belefulladnál a klaszterszintű eventekbe.
5. Ne felejtsd ki a kube-system-et. Az első heted tele lesz alertekkel a kubelet-től, kube-proxy-tól és más rendszer komponensektől, amik teljesen legit dolgokat csinálnak. Adj hozzá namespace kizárásokat a policy-jaidhoz korán.
Megérte?
Igen, abszolút. A Tetragon lecserélte a Falcót három klaszteremen a négyből. A negyediken régebbi kernel fut, ami nem támogat minden eBPF feature-t, amit a Tetragon igényel, szóval ott egyelőre marad a Falco.
Az alacsonyabb erőforráshasználat, a Kubernetes-natív policy-k és a valós enforcement együtt a Tetragont teszik jobb választássá a legtöbb 5.10+ kernelt futtató klaszterhez. A TracingPolicy CRD megközelítés pedig azt jelenti, hogy a security policy-kat ugyanúgy kezelem, mint bármi mást Kubernetesben, GitOps-szal, ArgoCD-vel.
Ha már Cilium a CNI-d, a Tetragon hozzáadása szerintem egyszerű döntés. Ha nem, akkor is érdemes önállóan kiértékelni. Az eBPF alapú runtime security egyértelműen az az irány, amerre az iparág tart, és a Tetragon a leginkább production-ready implementáció, amit eddig használtam.