İmajları çalışmadan önce tarıyoruz; kritik bulgusu olan imaj registry'ye hiç ulaşmıyor. Ama tarama imaja bakıyor, container'ın içinde sonradan olana değil. Biri içeri girip service account token'ını okursa Kubernetes'in kendisi bunu kaydetmiyor: dosya okumak bir API çağrısı değil. Bu yazıda Tetragon'un ne olduğuna, neyi çözdüğüne ve ne kazandırdığına bakıyorum; sonra bir pod'daki /etc/shadow okumasının önce görüldüğü, sonra tek bir bayt basılmadan öldürüldüğü, yanındaki pod'un ise çalışmaya devam ettiği lab'ı gösteriyorum. Birkaç yerde patladı; gerçek mesajlarıyla sonda.
Tetragon nedir?
Tetragon, Cilium projesinden bir runtime security aracı. Container'ların içinde süreçlerin ne yaptığını izliyor ve onları durdurabiliyor.
Node başına bir agent olarak çalışıyor ve eBPF kullanıyor: Linux kernel'ine yüklenen küçük programlar. Kernel her süreç başlangıcını, her dosya erişimini ve her ağ bağlantısını gördüğü için Tetragon da görüyor, üstüne Kubernetes bağlamını ekliyor: namespace, pod adı, label'lar.
Üç iş yapıyor:
- Süreç olayları: her sürecin başlaması ve bitmesi, argümanlarıyla, tek bir kural yazmadan.
- Policy'ler: bir
TracingPolicy(bir Kubernetes kaynağı) bir kernel fonksiyonunu seçiyor, örneğin "bir dosya okunuyor", ve onu kernel'in içinde filtreliyor, örneğin "sadece/etc/shadow". - Engelleme: policy eşleştiğinde Tetragon süreci öldürebiliyor (
Sigkill) ya da işlemi başarısız yapabiliyor (Override), orada, kernel'de.
Tetragon Cilium olmadan da çalışıyor. Ben serinin geri kalanıyla aynı cluster'da çalıştırıyorum.
Neyi çözüyor?
İmaj taraması imajda bitiyor. Yeşil bir tarama, bir hafta sonra container'da ne çalıştığı hakkında hiçbir şey söylemiyor. Bir shell, bilinmeyen bir IP'ye curl, bir secret'ın okunması: bunların hiçbiri imajda yok.
Kubernetes container'ın içini görmüyor. Audit log API çağrılarını kaydediyor: pod'u kim oluşturdu, kubectl exec'i kim çalıştırdı. Ondan sonra çalışan komut ve okuduğu dosya API çağrısı değil.
Log'lar geç kalıyor. Birçok araç olayları topluyor ve sonra userspace'te değerlendiriyor. Alarm çaldığında dosya çoktan okunmuş ve dışarı gönderilmiş oluyor. Durdurmak için karar, okuma tamamlanmadan verilmeli.
Tetragon ne kazandırıyor?
| Kazanım | Pratikte anlamı | Lab'da |
|---|---|---|
| Kuralsız süreç görünürlüğü | Her başlangıç ve bitiş, argümanlar ve pod adıyla | victim pod'unda head -1 /etc/shadow ve curl https://ebpf.io olay olarak |
| Hassas dosya okumaları | Kernel'in dosya izin kontrolüne bağlanan, yola göre filtrelenen policy | 📚 read victim/victim /usr/bin/head /etc/shadow |
| Cluster'dan çıkan bağlantılar | TCP connect'e bağlanan policy, cluster'ın kendi ağları hariç | 🔌 connect ... -> 104.26.4.27:443 |
| Kernel'de engelleme | Okuma dönmeden süreci öldürmek | exit code 137, hiçbir şey basılmadı |
| Label'a göre kapsam | Pod selector'lı namespaced policy | Label'sız komşu, aynı imaj, çalışmaya devam etti ve izlenmeye devam etti |
| Düşük maliyet | Filtre kernel'de, ilgisiz olaylar hiç üretilmiyor | Policy başına 0,5 ile 3,7 MB kernel belleği |
Karar vermeden önce neyi almadığınızı bilin:
| İhtiyaç | Tetragon 1.7 |
|---|---|
| Hazır kural seti | Yok. Boş bir sayfa ve projenin örnek policy'leriyle başlıyorsunuz. Falco'nun büyük bir hazır kural seti var. |
| Güvenli cluster geneli engelleme | Böyle bir şey yok. Cluster geneli bir öldürme kuralı kubelet'i, Cilium'u ve Tetragon'un kendisini de kapsıyor. |
| Ağ bağlantısını ilk paketten önce durdurmak | Override TCP connect noktasında çalışmıyor, sadece Sigkill. İlk paket çıkabilir. |
| Alarm ve saklama | Tetragon JSON olay yazıyor; Loki'ye ya da bir SIEM'e kendiniz taşıyorsunuz. |
Nasıl çalışıyor?

- Kanca noktaları: policy bir kernel fonksiyonuna bağlanıyor. Dosyalar için
security_file_permission, kernel'in her okuma ya da yazmadan önce çalıştırdığı kontrol. Ağ içintcp_connect. - Kernel'de filtre: policy argümanları (dosya yolu, hedef IP) eBPF programının içinde karşılaştırıyor. Başka dosyaların okumaları kernel'den olay olarak hiç çıkmıyor.
- Aksiyon: eşleşince
Sigkillsüreci öldürüyor,Overridefonksiyonun dönüş değerini değiştiriyor, okuma başarısız oluyor. İkisi de program veriyi almadan oluyor.
Lab: ne kurdum?
Her şey bir MacBook'ta kind üzerinde (Colima, 4 CPU / 8 GB, BTF'li kernel 6.8): Kubernetes 1.37, Cilium 1.20.2 ve Tetragon 1.7.1. victim namespace'inde aynı imajı (shell ve curl olan netshoot) çalıştıran iki pod var: app: victim label'lı victim ve label'sız bystander. Her birinde, ele geçirilmiş bir pod'un yapabileceği aynı dört şeyi çalıştırıyorum: /etc/shadow'u okumak, service account token'ını okumak, dışarıdaki bir siteye bağlanmak, /etc/hosts'a yazmak. Bütün lab yaklaşık 5 dakika sürdü.
Adım 1: Süreç olayları, policy gerekmiyor
Süreç olayları için hiçbir policy gerekmiyor. Tetragon pod'daki her süreci gösterdi: shell, argümanlarıyla head, curl ve her birinin çıkış kodu.

Bu tek başına, Kubernetes'in cevaplayamadığı "o pod'da ne çalıştı?" sorusunu cevaplıyor.
Adım 2: Hassas dosyaları ve dışarı bağlantıları izle
Ardından sadece izleyen üç cluster geneli policy: hassas dosya okumaları, cluster ağları dışındaki adreslere TCP bağlantıları ve yetki değişiklikleri. tetra tracingpolicy list bunları monitor_only olarak gösteriyor.

Sadece bunlarla victim'deki komutlar yine çalıştı: /etc/shadow'un ilk satırı, token'ın başı ve siteden 200 ekrana basıldı. Ama artık her biri pod adıyla bir olay bıraktı: /etc/shadow'un iki okuması, token'ın bir okuması, 104.26.4.27:443'e bir bağlantı ve /etc/hosts'a bir yazma.

Adım 3: Engelleme, sadece bir label'da
Şimdi harekete geçen policy: victim namespace'inde, app: victim pod selector'lı bir TracingPolicyNamespaced. /etc/shadow ve token okumalarında Override (okuma başarısız) ve Sigkill; cluster dışına bağlantılarda Sigkill.

137, 128 + 9, yani öldürme sinyali. Öldürülmeden önce hiçbir şey basılmadı: dosyanın satırı yok, token yok, HTTP status yok. /etc/hosts'a yazma policy'de değil ve olması gerektiği gibi geçti.
Asıl test yandaki pod. Aynı namespace, aynı imaj, aynı komutlar, ama app: victim label'ı yok:

Her şey çalıştı ve her şey izleme policy'leri tarafından yine kaydedildi. Production'da engellemeyi ben de böyle açardım: label'la, önce tek bir workload, sonra daha geniş.
Adım 4: Tek başına Override
İki aksiyonu ayrı görmek için /etc/shadow'da sadece Override olan bir varyantla değiştirdim. Süreç hayatta kaldı, okuma I/O error ile başarısız oldu, komşu dosyayı her zamanki gibi okudu.

Override işlemi engelliyor; Sigkill süreci bitiriyor. İkisi birlikte verinin programa hiç ulaşmamasını sağlıyor.
Son kontrol

İki pod da hâlâ Running: öldürme kubectl exec ile başlatılan komutlara değdi, container'ın ana sürecine değil. Gerçek bir uygulamada ana süreç öldürülür ve container yeniden başlar.
Nerede patladı: 3 gerçek hata
1. Token okuması durmadı: policy /var/run/...'ı izliyordu
Policy'nin ilk hâlinde herkesin yazdığı yol vardı: /var/run/secrets/kubernetes.io/serviceaccount. Token okundu, ekrana basıldı, süreç öldürülmedi. Container'ın içinde /var/run, /run'a bir bağlantı ve kernel gerçek yolu bildiriyor: /run/secrets/kubernetes.io/serviceaccount/..<zaman damgası>/token. İzleme policy'sinin olayı bunu gösteriyor. /var/run/... üzerindeki bir önek hiç eşleşmiyor. Yazdığınız yolu değil, kernel'in gördüğü ve olayda okuduğunuz yolu yazın.

2. Killed, ama exit=0
Doğru policy ile token komutu Killed bastı ve yine de exit=0 döndü. Bir atlatma gibi görünüyor. Değil: komut head ...; echo idi, yani head öldürüldü, shell hayatta kaldı ve echo'nun çıkış kodunu döndü. Olaylar bunu açıkça gösteriyor: head ... SIGKILL, ardından 0 ile shell. Engellemeyi test ederken komut başına tek süreç çalıştırın ve sadece çıkış koduna değil olaylara bakın.

3. Override Operation not permitted değil, I/O error diyor
Programın "permission denied" görmesini bekliyordum. I/O error gördü (Adım 4). Okuma iki durumda da engelleniyor, ama engellemeyi kanıtlamak için log'larda "Operation not permitted" ararsanız hiçbir şey bulamazsınız. Onun yerine Tetragon olaylarında override aksiyonunu arayın.
Bir pratik not daha: olaylar node başına. kubectl logs ds/tetragon agent'lardan birini seçiyor, çoğu zaman yanlış olanı. Son kontrolde sadece victim'in node'unda olay vardı (26), diğer ikisinde 0. Lab'ın verify script'i bütün agent'ları dolaşıyor.
Ne zaman kullanmalı, ne zaman değil?
| Durum | Seçim |
|---|---|
| Container'larınızda ne çalıştığını bilmek ve birkaç net davranışı durdurmak istiyorsunuz (secret okumak, bilinmeyen dış bağlantılar) | Tetragon. Cluster genelinde izle, label'la engelle. |
| Kutudan çıktığı gibi büyük bir hazır tespit kuralı seti ve alarm istiyorsunuz | Falco, belki Tetragon'un yanında. Falco userspace'te tespit ediyor ve harekete geçmek için başka bir bileşen istiyor. |
| Sadece pod'lar arası trafiği engellemeniz gerekiyor | Bir network policy (bkz. network policy yazısı). Tetragon trafik kurallarıyla değil süreçlerle ilgili. |
| Kötü imajları çalışmadan önce engellemek istiyorsunuz | İmaj taraması ve admission policy. Tetragon onların bittiği yerde başlıyor. |
Özet
- Tetragon container'ların içindeki süreçleri, dosya okumalarını ve bağlantıları eBPF ile izliyor ve pod adını ekliyor.
- Kural olmadan pod'daki her sürecin başlangıcını ve bitişini gösterdi.
- İzleme policy'leri
/etc/shadowve token okumalarını ve dış bir IP'ye bağlantıyı durdurmadan kaydetti. - Namespaced bir policy aynı komutları label'lı pod'da, hiçbir şey basılmadan 137 koduyla öldürdü; aynı imajlı komşu pod çalışmaya devam etti.
- Yolları kernel'in gördüğü gibi yazın:
/var/run/secrets/...değil,/run/secrets/....
Kaynaklar: Tetragon dokümanları Getting started, Tracing Policy (kanca noktaları, selector'lar, Sigkill ve Override aksiyonları), Policy filtering (namespaced policy, pod selector) ve Events export; Tetragon examples/ policy'leri.
Serinin devamı
Bu yazı Cilium Uçtan Uca serisinin yedinci ve son yazısı. Seri Cilium'u kind'a kurmakla başladı: Cilium Nedir: kube-proxy'siz Kubernetes, eBPF ve Hubble ile Uygulamalı Giriş. Önceki yazı: Cilium Cluster Mesh Nedir? Neyi Çözer, Kazanımları ve İki kind Cluster'lı Failover Lab'ı.
Bu lab'ın kodu (kind config'i, Cilium ve Tetragon values dosyaları, victim/bystander manifest'i, dört policy ve Override-only varyantı, trigger/events/verify script'leri ve Makefile) Buy Me a Coffee'deki Lab Access üyeleriyle paylaşılıyor; katıldıktan sonra repo daveti e-postayla geliyor: https://buymeacoffee.com/miraccanyilmaz/membership