NixOS Üzerinde Çekirdek Sıkılaştırma ve Immutable Auditd Kuralları

Geçenlerde patlayan “Bad Epoll” race condition açığı bir kez daha gösterdi ki; ortalıkta dolaşan yapay zeka modelleri veya koca koca güvenlik uzmanları bu tarz asenkron hataları patch çıkana kadar ruhları bile duymadan atlayabiliyor. Günün sonunda sistem zero-day bir zafiyetle delindiğinde elinde kalan tek savunma hattı, o anki runtime tespiti ve önceden çektiğin kernel hardening duvarları oluyor.

Sistemi güvene almak sadece port kapatıp firewall yazmakla bitmiyor. Aşağıda NixOS üzerinde kernel seviyesinde aldığım bazı sıkılaştırma önlemlerini ve bir saldırganın logları silmesini imkansız hale getiren auditd yapılandırmamı derledim.


1. Çekirdek Sıkılaştırma Parametreleri

Çekirdek içindeki bellek adreslerinin, debug çıktılarının ve process’lerin birbirini okuma yetkilerinin kısıtlanması şart. NixOS tarafında boot.kernel.sysctl modülü altında uyguladığım temel hardening parametreleri şunlar:

boot.kernel.sysctl = {
  # Çekirdek bellek adreslerini kısmen gizler.
  # Sunucularda 2 yapılır ama masaüstünde debug ihtiyacı olduğu için 1 bıraktım.
  "kernel.kptr_restrict" = 1;

  # Ptrace kapsamını daraltır.
  # Bir programın başka bir programın hafızasına kanca atmasını engeller.
  # Sunucularda 2 yapılır ama IDE debugger kullananlar 1'de bırakmalı.
  "kernel.yama.ptrace_scope" = 1;

  # Yetkisiz BPF kullanımını engeller.
  "kernel.unprivileged_bpf_disabled" = 1;
};

Burada dikkat edilmesi gereken nokta: bu bir masaüstü sistemi, sunucu değil. kptr_restrict ve ptrace_scope değerlerini 2 yerine 1 bıraktım çünkü günlük geliştirme işlerinde dmesg okumam veya debugger takmam gerekebiliyor. Tam paranoyak modda (= 2) bunların hepsi kilitlenir ve debugging imkansız hale gelir. Sunucu kuracak olanlar 2 yapıp kernel.dmesg_restrict = 1 ve net.core.bpf_jit_harden = 2 de eklesin.

Bu parametreler saldırganı sihirli bir şekilde durdurmaz ama exploit geliştirme maliyetini ve süresini ciddi şekilde artırır. O süre zarfında da devreye Audit Framework girer.


2. Auditd ve Filtreleme

Linux Audit Framework (auditd), çekirdekte dönen her syscall’u yakalayan muazzam bir araç. Ama default ayarlarla bırakırsanız, systemd veya dbus gibi arka plan daemon’larının yarattığı spam yüzünden diskiniz anında şişer ve asıl aradığınız logları bulamazsınız.

Benim audit.nix yapılandırmamda system daemon’larını yoksayıp sadece gerçek kullanıcıların EACCES/EPERM hatalarını yakalayan bir filtreleme kullanıyorum:

security.auditd.enable = true;
security.audit = {
  # 3. bölümde detaylı anlatacağım "lock" değeri burada devreye giriyor
  enable = "lock";

  rules = [
    # Sadece gerçek kullanıcıların (auid>=1000) izinsiz erişim denemelerini yakala
    "-a always,exit -F arch=b64 -S open,openat -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access_denied"
    "-a always,exit -F arch=b64 -S open,openat -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access_denied"

    # Sudoers ve SSH yapılandırma değişikliklerini izle
    "-w /etc/sudoers -p wa -k sudoers_changes"
    "-w /etc/ssh/sshd_config -p wa -k sshd_config"

    # NixOS deklaratif yapılandırma dizinini izle
    "-w /persist/nixos-config/ -p wa -k nixos_config"
  ];

  backlogLimit = 8192;
};

Buradaki backlogLimit kritik; ani bir syscall patlamasında çekirdeğin yetersiz buffer yüzünden logları düşürmesini engelliyor.


3. Kuralları Kilitlemek: -e 2 Bayrağı

Gelelim işin can alıcı noktasına. Bir saldırgan sisteme sızıp root yetkilerini alırsa, ilk yapacağı şey izlerini silmek için systemctl stop auditd çekmek veya auditctl -D ile kuralları sıfırlamaktır.

Bunu engellemenin tek yolu, audit kurallarını çekirdek seviyesinde değiştirilemez hale getirmek. Yukarıdaki kod bloğunda zaten gördüğünüz enable = "lock" tam olarak bunu yapıyor. NixOS’un security.audit.enable seçeneği true veya false dışında bir de "lock" değeri alıyor; "lock" yazdığınız an kural dosyasının en sonuna otomatik olarak -e 2 ekleniyor. Tek satır, workaround yok, native destek.

”-e 2” Gerçekte Ne Yapıyor?

-e 2 kernel’e düştüğü an audit yapılandırması beton gibi kilitlenir. Artık root bile olsanız auditctl ile yeni kural ekleyemez veya mevcutları silemezsiniz. Çoğu kişi “audit servisine restart atarım çözülür” sanıyor ama çözülmez; servis yeniden başlasa da kilit açılmaz.

Bu kilidi açmanın tek çıkış yolu makineye reboot atmaktır. Saldırganın izini silmek için sunucuya reboot atması demek, başlı başına koca bir alarm zili çalması demektir.

[!CAUTION] Rollback ve Kilit Tuzağı enable = "lock" yazmadan önce iki kere düşünün. Eğer yazdığınız kurallarda bir hata veya saçma bir filtre varsa; NixOS boot eder, kuralları uygular ve anında kilidi vurur. O hatalı kurallarla baş başa kalırsınız.

NixOS’un Generation Rollback özelliği can simidi olsa da, kilit devredeyken mevcut oturumda rollback yapıp nixos-rebuild switch atsanız dahi o audit kilidi açılmaz. Düzeltmek için mecburen reboot atmanız gerekir. O yüzden switch atmadan önce nixos-rebuild build yapın ve auditctl -l ile kurallarınızı test edin.

EOF.