Falco ile Runtime Security Kuralları

Selamlar, bu yazıda Falco ile runtime security kurallarını cluster üstünde nasıl ayağa kaldırdığımıza birlikte bakacağız. Image scan'ler, admission controller'lar derken konteyner güvenliğinin önemli bir parçasını çoğu zaman atlıyoruz: konteyner ayağa kalktıktan sonra içeride neler olup bittiği. Statik tarama saldırganı kapıdan içeri girmeden yakalar; Falco ise içeri girdikten sonraki ilk hareketinde yakalamaya çalışır. Lafı uzatmadan başlayalım.

Falco ne yapar, nasıl dinler?

Falco, CNCF'in graduate ettiği bir runtime güvenlik aracı. İşin özü şu: node üzerinde syscall'ları dinliyor, bir kural setine göre değerlendiriyor ve eşleşince alert üretiyor. Dinleme kısmı için iki seçenek var, eBPF probe ya da kernel modülü. Bence yeni kurulumlarda eBPF tercih edilmeli, hem kerneli daha az kirletiyor hem de modern dağıtımların çoğunda doğrudan çalışıyor. Modern olmayan, eski 4.x kerneller varsa kernel modülü hâlâ yedek planınız olabilir.

Bunun yanında Falco, Kubernetes audit log'unu da kaynak olarak okuyabiliyor. Yani sadece syscall seviyesinde değil, API server'a düşen get secret veya exec istekleri gibi olayları da yakalayabiliyorsunuz. İki kaynağı birlikte kullanmak, hem node hem control-plane tarafını kapsıyor.

Helm ile cluster'a kurulum

Kuruluma resmi Helm chart ile başlamak en pratiği. eBPF sürücüsünü ve falcosidekick'i tek seferde aktif ediyoruz:

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update

helm install falco falcosecurity/falco \
  --namespace falco --create-namespace \
  --set driver.kind=ebpf \
  --set falcosidekick.enabled=true \
  --set falcosidekick.webui.enabled=true

Pod'lar ayağa kalkınca akan log'a bakıp ortamın sağlıklı olduğundan emin olun:

kubectl logs -n falco -l app.kubernetes.io/name=falco -f

İlk açılışta default rule set'ten gelen birkaç event görmek normaldir; gerçek alarmlar değil, çoğu zaman cluster'ın kendi günlük telaşıdır.

Kural yazmanın üç parçası: rule, macro, list

Falco kuralları YAML üç temel kavram üstüne kurulu. Rule asıl tespit cümlesidir, macro tekrar kullanılan koşul parçasıdır, list ise isimlendirilmiş bir öğe kümesidir. Şu örnekte üçü birden var:

- list: shell_binaries
  items: [bash, sh, zsh, ksh]

- macro: container
  condition: container.id != host

- macro: spawned_shell
  condition: evt.type = execve and proc.name in (shell_binaries)

- rule: Shell Spawned in Container
  desc: Konteyner icinde shell calismasi (olasi compromise)
  condition: spawned_shell and container
  output: >
    Shell spawned (user=%user.name container=%container.name
    image=%container.image.repository cmdline=%proc.cmdline)
  priority: WARNING
  tags: [container, shell]

Bu kuralın güzel yanı şu: konteynerin içine kabuk düşüren her execve çağrısında bir alert üretiyor. Production konteynerinin içinde kabuk açılmasının meşru bir nedeni nadiren olur; bu yüzden bu kural neredeyse her cluster'da bulunmalı bence.

Hassas dosya erişimi ve privilege escalation

Listeleri biraz daha iddialı kullanalım. Aşağıdaki kural /etc/shadow ve SSH anahtarları gibi dosyalara konteyner içinden okuma denenmesini yakalıyor:

- list: sensitive_files
  items:
    - /etc/shadow
    - /etc/sudoers
    - /root/.ssh/authorized_keys

- rule: Read Sensitive File
  desc: Konteynerden hassas dosya okuma
  condition: open_read and fd.name in (sensitive_files) and container
  output: >
    Sensitive file read (file=%fd.name user=%user.name
    container=%container.name cmd=%proc.cmdline)
  priority: WARNING

Privilege escalation kuralı da setuid/setgid syscall'larını izliyor. Burada not user.name = root koşulu kritik, çünkü zaten root olan bir process'in setuid çağırması anlamlı bir bulgu sayılmaz.

Falcosidekick ile alert routing

Falco tek başına sadece stdout'a yazar; alert'i bir yere ulaştırmak için falcosidekick kullanıyoruz. 50'den fazla hedefi destekliyor; biz tipik olarak Slack'e WARNING üstünü, PagerDuty'ye CRITICAL'ı yönlendiriyoruz:

falcosidekick:
  enabled: true
  config:
    slack:
      webhookurl: 'https://hooks.slack.com/services/XXX/YYY/ZZZ'
      channel: '#security-alerts'
      minimumpriority: 'warning'
    pagerduty:
      apikey: 'pd-api-key'
      minimumpriority: 'critical'
    elasticsearch:
      hostport: 'https://es.example.com:9200'
      index: 'falco'

minimumpriority ayarını dikkatli seçin. Hepsini Slack'e bağlarsanız iki gün sonra kanal sessize alınır ve gerçek olay kaçar.

Kubernetes audit log kaynağı

Audit log entegrasyonu için kube-apiserver'a bir webhook config'i veriyorsunuz, falco bunu k8s_audit source'u olarak okuyor. Örnek bir kural:

- rule: K8s Secret Get
  desc: Secret okuma denemesi
  condition: >
    ka.verb = get and ka.target.resource = secrets and
    not ka.user.name in (allowed_service_accounts)
  output: >
    Secret accessed (user=%ka.user.name ns=%ka.target.namespace
    secret=%ka.target.name)
  priority: WARNING
  source: k8s_audit

allowed_service_accounts listesini doğru tutmak işin püf noktası. Buraya operator'lerinizi, controller'larınızı koymazsanız kısa sürede gürültüye boğulursunuz.

Sık karşılaşılan tuzaklar

  • Default kuralları olduğu gibi açık bırakmak: Cluster'ınıza özel beyaz liste yapmadan default set'i bırakırsanız ilk gün yüzlerce false positive alırsınız. Önce iki üç gün stats ile gözleyin, sonra exception ekleyin.
  • eBPF probe'u eski kernelde zorlamak: 4.18 altı kerneller eBPF'in ihtiyacı olan özelliklere sahip değil. driver.kind=module deneyin ya da kerneli güncelleyin.
  • falcosidekick'i hedefsiz açmak: Sadece UI'ya bağlı kalırsa olay olduğunda kimsenin haberi olmaz. En az bir 'insanın bakacağı' kanal şart.
  • Gürültülü kuralı susturmak yerine kaldırmak: Gürültüden kurtulmak için kuralı silmek kolay ama riskli; doğrusu macro'larla istisna eklemek.

Kapanış

Bu yazıda Falco'yu eBPF probe ile cluster'a kurduk, rule/macro/list üçlüsüyle kendi kurallarımızı yazdık ve falcosidekick üzerinden alert akışını şekillendirdik. Bana sorarsanız runtime security'yi 'image scan yaptık, yeter' diye bırakmamak gerekiyor; Falco ile en azından konteynerin içinde olup biteni görmek elinizdeki en iyi pratiklerden biri. Umarım faydalı olur, görüşmek üzere.