Tetragon Nedir? Neyi Çözer, Kazanımları ve Bir Secret'ı Okumadan Süreci Öldüren Kubernetes Lab'ı

Tetragon'u bir Kubernetes lab'ıyla anlatıyorum: /etc/shadow okuması pod adıyla görüldü, sonra 137 ile öldürüldü; yan pod çalışmaya devam etti.

Yazan: Mirac Can Yılmaz 10 dk okuma
Tetragon Nedir? Neyi Çözer, Kazanımları ve Bir Secret'ı Okumadan Süreci Öldüren Kubernetes Lab'ı - Security yazısının kapak görseli

İ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?

Diyagram: solda imaj taraması ve audit log, pod'da /etc/shadow okuması ekrana basılıyor ve hiçbir şey kaydetmiyor; sağda node başına bir agent'lı Tetragon, okuma kernel'de security_file_permission'da yakalanıyor, pod adıyla bir read olayı, ardından 137 koduyla exit SIGKILL. Altta lab'dan dört sonuç: 0 kuralla süreç başlangıç ve bitişi, shadow ve token okumaları görüldü, 104.26.4.27:443'e bağlantı, label'lı pod için 137 ve dokunulmayan komşu

  • 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çin tcp_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 Sigkill süreci öldürüyor, Override fonksiyonun 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.

tetra getevents, policy gerektirmeyen süreç olayları: victim/victim'de /bin/sh, /usr/bin/head -1 /etc/shadow, token okuması ve /usr/bin/curl https://ebpf.io için process ve exit olayları, hepsi 0 koduyla

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.

tetra tracingpolicy list: file-monitor, network-egress-outside-cluster ve privilege-escalation monitor_only modunda, victim namespace'i için victim-enforce enforce modunda, her biri 0,5 ile 3,7 MB kernel belleği

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.

Sadece izleme: komutlar root:*, token başı eyJhbGci ve 200 basıyor; olaylar iki kez read /etc/shadow, /run/secrets altında token okuması, 104.26.4.27:443'e connect ve write /etc/hosts gösteriyor, hepsi victim/victim'de

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.

app=victim'de engelleme: head -1 /etc/shadow 137 koduyla çıkıyor, token okuması Killed basıyor, curl 137 ile çıkıyor, /etc/hosts yazması geçiyor; olaylar okumaları ve bağlantıları, ardından head, head ve curl için exit SIGKILL gösteriyor

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:

Engelleme policy'si dururken bystander pod'u: bütün komutlar exit 0 ile başarılı, shadow satırı, token başı ve 200 basılıyor; okumalar ve bağlantı yine olay olarak kaydediliyor

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.

Sigkill'siz Override: victim'de head /etc/shadow: I/O error basıyor ve 1 ile çıkıyor; bystander'da /etc/shadow'un ilk satırı exit 0 ile basılıyor

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

Son kontrol

make verify: victim-enforce enforce modunda ve üç policy monitor_only'de, iki pod da hâlâ Running, export'ta process_kprobe olayları sadece victim'in node'unda: 0, 0 ve 26

İ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.

Policy öneki /var/run/secrets: head token başı eyJhbGci basıyor ve 0 ile çıkıyor; olay okumayı /run/secrets/kubernetes.io/serviceaccount/..2026_10_23/token'da ve 0 çıkış kodunu gösteriyor, SIGKILL yok

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.

Token komutu Killed ve exit=0 basıyor; olaylar /usr/bin/head için exit SIGKILL ve onu çalıştıran /bin/sh için exit 0 gösteriyor

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/shadow ve 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

Hayatta en hakiki mürşit ilimdir.
Mustafa Kemal Atatürk