SELinux Kaynaklı Erişim Sorunlarını Giderme
Sistem yöneticiliğinin en sinir bozucu anlarından biri, her şeyin doğru yapılandırıldığını düşündüğün halde bir servisin çalışmaması veya bir kullanıcının erişim hatası almasıdır. Firewall kurallarını kontrol edersin, dosya izinlerini gözden geçirirsin, her şey yerli yerindedir ama sorun devam eder. İşte bu noktada genellikle gözden kaçan suçlu ortaya çıkar: SELinux.
SELinux (Security-Enhanced Linux), Linux çekirdeğine entegre edilmiş zorunlu erişim kontrolü (MAC) sistemidir. Geleneksel Unix izin modelinin üzerine ek bir güvenlik katmanı ekler ve süreçlerin yalnızca ihtiyaç duydukları kaynaklara erişebilmesini sağlar. Bu mükemmel bir güvenlik özelliğidir ama yanlış yapılandırıldığında veya beklenmedik durumlarda gerçek bir baş belası olabilir. Bu yazıda SELinux kaynaklı erişim sorunlarını sistematik bir şekilde nasıl tespit edip çözeceğimizi ele alacağız.
SELinux’u Anlamak: Temel Kavramlar
Sorun gidermeye geçmeden önce bazı temel kavramları netleştirmek gerekiyor.
SELinux her dosyaya, sürece ve kaynağa bir güvenlik etiketi (label) atar. Bu etiketlere context (bağlam) denir ve kullanıcı:rol:tip:seviye formatındadır. Örneğin bir Apache web sunucusu süreci system_u:system_r:httpd_t:s0 bağlamında çalışırken, web dosyaları system_u:object_r:httpd_sys_content_t:s0 bağlamına sahip olmalıdır.
SELinux’un üç çalışma modu vardır:
- Enforcing: Politikalar aktif olarak uygulanır, ihlaller engellenir ve loglanır
- Permissive: Politikalar kontrol edilir ama uygulanmaz, yalnızca loglanır
- Disabled: SELinux tamamen devre dışı
Mevcut durumu kontrol etmek için:
getenforce
sestatus
sestatus komutu daha detaylı bilgi verir: hangi politikanın yüklü olduğunu, hangi modda çalıştığını ve mevcut politika sürümünü gösterir.
Gerçek Dünya Senaryosu 1: Apache Web Sunucusu Dosyalara Erişemiyor
Klasik bir senaryo ile başlayalım. Yeni bir web uygulaması kurdunuz, belgeleri /var/www/html yerine /data/webapp dizinine koydunuz, Apache konfigürasyonunu düzenlediniz ama tarayıcı 403 Forbidden hatası veriyor. Dosya izinleri doğru, Apache çalışıyor, ama bir türlü olmadı.
İlk olarak audit loglarına bakalım:
tail -f /var/log/audit/audit.log | grep AVC
veya daha okunabilir bir format için:
ausearch -m avc -ts recent
Muhtemelen şöyle bir şey göreceksiniz:
type=AVC msg=audit(1234567890.123:456): avc: denied { read } for pid=1234
comm="httpd" name="index.html" dev="sda1" ino=123456
scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
Bu log bize şunu söylüyor: httpd_t bağlamında çalışan Apache süreci, default_t bağlamına sahip index.html dosyasını okumaya çalıştı ve reddedildi. Sorun açık, dosyalar yanlış SELinux bağlamına sahip.
Çözüm şu şekilde ilerler. Önce mevcut bağlamı kontrol edin:
ls -Z /data/webapp/
Sonra doğru bağlamı atayın:
semanage fcontext -a -t httpd_sys_content_t "/data/webapp(/.*)?"
restorecon -Rv /data/webapp/
semanage fcontext komutu kalıcı bir kural ekler, restorecon ise mevcut dosyalara bu kuralı uygular. Yalnızca chcon komutunu kullanırsanız değişiklikler geçici olur ve restorecon çalıştırıldığında veya sistem yeniden başlatıldığında silinir.
sealert ile Otomatik Analiz
Manuel log okumak zahmetli olabilir. sealert aracı SELinux ihlallerini analiz eder ve çözüm önerileri sunar. Genellikle setroubleshoot-server paketinin parçasıdır:
dnf install setroubleshoot-server -y
sealert -a /var/log/audit/audit.log
Bu komut her ihlalin neden gerçekleştiğini İngilizce açıklar ve hangi komutlarla düzeltebileceğinizi gösterir. Ayrıca /var/log/messages dosyasında da özetler görülebilir:
grep "SELinux is preventing" /var/log/messages
sealert çıktısı genellikle şunları içerir: ihlal sayısı, hangi işlemin engellendiği, önerilen semanage veya setsebool komutları ve politika modülü oluşturma seçeneği.
Gerçek Dünya Senaryosu 2: Nginx Özel Port Kullanıyor
Web sunucunuzu standart olmayan bir portta (örneğin 8888) çalıştırmak istiyorsunuz. Nginx konfigürasyonunu düzenlediniz ama servis başlamıyor. journalctl -xe bakıyorsunuz, port bind hatası görüyorsunuz.
SELinux, ağ servisleri için hangi portların kullanılabileceğini de kontrol eder. Mevcut izin verilen portları görmek için:
semanage port -l | grep http
Çıktıda http_port_t veya http_cache_port_t etiketlerine sahip portları göreceksiniz. 8888 burada yoksa Nginx bu porta bind olamaz.
Yeni portu eklemek için:
semanage port -a -t http_port_t -p tcp 8888
Sonra Nginx’i yeniden başlatın:
systemctl restart nginx
Eğer portu kaldırmak isterseniz -a yerine -d (delete) parametresini kullanın. Mevcut bir portun tipini değiştirmek için ise -m (modify) parametresini kullanırsınız.
Boolean Değerleri ile İnce Ayar
SELinux boolean değerleri, politikalarda belirli davranışları etkinleştirip devre dışı bırakmanın en temiz yoludur. Özel modül yazmadan veya bağlam değiştirmeden pek çok yaygın senaryoyu çözebilirsiniz.
Mevcut boolean değerlerini listelemek için:
getsebool -a
getsebool -a | grep httpd
Yaygın Apache/Nginx senaryolarında karşılaşılan boolean değerleri:
- httpd_can_network_connect: HTTP sunucusunun ağ bağlantısı kurmasına izin verir (reverse proxy senaryoları için şart)
- httpd_can_network_connect_db: Veritabanı bağlantısına izin verir
- httpd_use_nfs: NFS paylaşımlarından dosya sunmasına izin verir
- httpd_read_user_content: Kullanıcı home dizinlerinden okuma izni
- httpd_execmem: Bellek yürütme izni (bazı PHP uygulamaları için gerekli)
Bir boolean’ı etkinleştirmek için:
# Geçici olarak (reboot sonrası sıfırlanır)
setsebool httpd_can_network_connect on
# Kalıcı olarak
setsebool -P httpd_can_network_connect on
Reverse proxy kurulumu sıklıkla sorun çıkarır. Apache veya Nginx arka planda çalışan bir uygulama sunucusuna istek yönlendiriyorsa httpd_can_network_connect boolean’ı mutlaka açık olmalıdır.
Permissive Modun Sorun Gidermedeki Rolü
Sorunun SELinux kaynaklı olup olmadığından emin değilseniz geçici olarak permissive moda geçebilirsiniz. Bu mod ihlalleri engellemez ama yine de loglar.
# Tüm sistemi permissive moda al
setenforce 0
# Servisi test et
systemctl restart httpd
curl http://localhost/test
# Bitince enforcing moduna geri dön
setenforce 1
Önemli uyarı: Permissive modu production ortamında uzun süre açık bırakmayın. Bu yalnızca teşhis için kullanılmalıdır.
Daha iyi bir yaklaşım, yalnızca sorunlu servisin domain’ini permissive yapmaktır:
semanage permissive -a httpd_t
Bu sayede diğer servisler enforcing modunda kalırken yalnızca httpd_t domain’i permissive olur. Test sonrası geri almak için:
semanage permissive -d httpd_t
Audit Log Detaylı Analiz
ausearch ve aureport araçları audit loglarını analiz etmek için güçlü seçenekler sunar:
# Son 1 saatteki AVC redlerini göster
ausearch -m avc -ts recent
# Belirli bir süreçle ilgili ihlalleri filtrele
ausearch -m avc -c httpd
# Belirli bir dosya veya dizinle ilgili ihlalleri bul
ausearch -m avc -ts today | grep "/data/webapp"
# İhlal özetini göster
aureport --avc --summary
Log satırlarını elle okurken dikkat etmeniz gereken alanlar şunlardır:
- scontext: İşlemi gerçekleştirmeye çalışan öznenin bağlamı (süreç)
- tcontext: Erişilmeye çalışılan nesnenin bağlamı (dosya, soket vb.)
- tclass: Nesne sınıfı (file, dir, tcp_socket vb.)
- denied { }: Reddedilen izin türü (read, write, execute, bind vb.)
Gerçek Dünya Senaryosu 3: Özel Uygulama için Politika Modülü Oluşturma
Bazen hazır çözümler yetmez ve kendi uygulamanız için özel bir SELinux politikası yazmanız gerekir. Bu durumda audit2allow aracı büyük kolaylık sağlar.
Diyelim ki özel bir Python uygulamanız var ve SELinux onu çeşitli kaynaklara erişmekten engelliyor. Önce permissive modda çalıştırın ve tüm ihlalleri loğa düşürün, sonra bu loglardan politika oluşturun:
# İhlalleri filtrele ve politika modülü oluştur
ausearch -m avc -ts recent | audit2allow -M myapp
# Oluşturulan modülü incele
cat myapp.te
# Modülü yükle
semodule -i myapp.pp
audit2allow otomatik olarak bir .te (type enforcement) dosyası ve derlenmiş .pp (policy package) dosyası oluşturur. Modülü yüklemeden önce .te dosyasını gözden geçirin, çünkü bazen gereğinden fazla izin verilebilir.
Yüklü modülleri listelemek ve yönetmek için:
# Tüm yüklü modülleri listele
semodule -l
# Modülü kaldır
semodule -r myapp
# Modülü devre dışı bırak (kaldırmadan)
semodule -d myapp
# Modülü tekrar etkinleştir
semodule -e myapp
Dosya Bağlamı Yönetimi
Dosya bağlamları SELinux sorunlarının büyük çoğunluğunun kaynağıdır. Bağlamları doğru yönetmek kritik öneme sahiptir.
Bir dosyanın mevcut bağlamını görmek için:
ls -Z /etc/nginx/nginx.conf
stat --format="%C" /etc/nginx/nginx.conf
Tüm sistem için tanımlı bağlam kurallarını listelemek için:
semanage fcontext -l
semanage fcontext -l | grep httpd
Bağlamı geçici olarak değiştirmek (reboot veya restorecon sonrası kaybolur):
chcon -t httpd_sys_content_t /data/webapp/index.html
chcon -R -t httpd_sys_content_t /data/webapp/
Kalıcı kural ekleyip uygulamak için:
semanage fcontext -a -t httpd_sys_content_t "/data/webapp(/.*)?"
restorecon -Rv /data/webapp/
restorecon -n komutu değişiklikleri uygulamadan önce ne yapacağını gösterir, önizleme gibi kullanılabilir:
restorecon -Rnv /data/webapp/
Bir dosyanın bağlamını başka bir dosyayla eşleştirmek için --reference parametresi kullanılabilir:
chcon --reference=/var/www/html/index.html /data/webapp/index.html
Sistem Genelinde SELinux Durumu Kontrolü
Production sistemlerde periyodik olarak SELinux durumunu kontrol etmek iyi bir alışkanlıktır:
# Genel durum
sestatus -v
# Son ihlal sayısı
aureport --avc --summary -ts today
# Hangi süreçlerin en fazla ihlaline neden olduğunu göster
aureport --avc -ts this-week | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20
Büyük altyapılarda auditd servisinin düzgün çalıştığından emin olun:
systemctl status auditd
auditctl -s
Gerçek Dünya Senaryosu 4: NFS ve Samba Paylaşımları
Dosya paylaşımı senaryoları da sık karşılaşılan SELinux sorunlarına yol açar. Örneğin Samba üzerinden bir dizini paylaşıyorsunuz ama Windows istemciler erişemiyor veya sadece okuyabiliyor.
Samba için doğru bağlamı ayarlamak gerekir:
# Samba için okuma/yazma erişimi
semanage fcontext -a -t samba_share_t "/srv/samba/share(/.*)?"
restorecon -Rv /srv/samba/share/
# veya home dizinleri için
setsebool -P samba_enable_home_dirs on
# Samba'nın ev dizinlerini paylaşmasına izin ver
setsebool -P samba_export_all_rw on
NFS için de benzer yaklaşım geçerlidir:
setsebool -P use_nfs_home_dirs on
semanage fcontext -a -t nfs_t "/srv/nfs/data(/.*)?"
Sorun Giderme İş Akışı
Sistematik bir yaklaşım için şu adımları izleyin:
Birincisi, SELinux’un suçlu olup olmadığını doğrulayın. Geçici olarak permissive yapın ve sorunun devam edip etmediğini test edin. Devam etmiyorsa SELinux kaynaklıdır, devam ediyorsa başka bir sorun var demektir. Bunu yaptıktan sonra enforcing moda geri dönün.
İkincisi, ihlal loglarını toplayın. ausearch -m avc -ts recent ile son ihlalleri görün, sealert ile otomatik analiz yaptırın.
Üçüncüsü, çözüm türünü belirleyin. Eğer sorun yanlış dosya bağlamından kaynaklanıyorsa semanage fcontext ve restorecon kullanın. Eğer bir özellik veya davranış kısıtlanmışsa setsebool ile boolean ayarlayın. Eğer standart dışı bir port kullanıyorsanız semanage port ile portu tanımlayın. Eğer özel bir uygulama söz konusuysa audit2allow ile politika modülü oluşturun.
Dördüncüsü, değişikliği kalıcı yapın. setenforce 0 veya chcon geçici çözümlerdir, production’da her zaman kalıcı komutları kullanın.
Beşincisi, doğrulayın. Değişiklikten sonra servisi yeniden başlatın ve logları tekrar kontrol edin.
Sık Yapılan Hatalar
SELinux’u tamamen devre dışı bırakmak en kötü “çözümdür”. setenforce 0 koyup geçmek veya /etc/selinux/config dosyasında SELINUX=disabled yazmak güvenlik açığı oluşturur. Asıl sorunu çözmek her zaman daha doğru yaklaşımdır.
chcon kullanımı geçici bir çözümdür. Sistem yeniden başladığında veya restorecon çalıştırıldığında değişiklikler kaybolur. Her zaman semanage fcontext ile kalıcı kural ekleyin.
Audit log dolması durumunda eski loglar silinebilir ve önemli ihlaller kaçırılabilir. auditd konfigürasyonunu (/etc/audit/auditd.conf) düzenleyerek log boyutunu ve rotasyon politikasını ayarlayın.
Permissive modda test etmeyi unutmak da sık yapılan bir hatadır. Bir özelliği etkinleştirmeden önce permissive modda ne gibi ihlaller oluştuğunu görmek, daha hedefli politikalar yazmanızı sağlar.
Faydalı Araçlar ve Paketler
Sorun giderme sürecinde işinize yarayacak paketler:
- policycoreutils: Temel SELinux araçları (semanage, restorecon, setsebool)
- policycoreutils-python-utils: Python tabanlı araçlar, audit2allow dahil
- setroubleshoot-server: sealert ve otomatik analiz
- setools-console: sesearch, seinfo gibi politika analiz araçları
- libselinux-utils: getenforce, setenforce, getfattr gibi temel araçlar
dnf install policycoreutils policycoreutils-python-utils setroubleshoot-server setools-console -y
sesearch ile politika kurallarını inceleyebilirsiniz:
# httpd_t'nin hangi dosya tiplerine erişebildiğini göster
sesearch --allow -s httpd_t -c file
# Belirli bir tip üzerinde hangi domain'lerin izni olduğunu göster
sesearch --allow -t httpd_sys_content_t -c file
Sonuç
SELinux, başlangıçta karmaşık ve sinir bozucu görünebilir ama doğru araçları ve yaklaşımı öğrendikten sonra güçlü bir müttefikinize dönüşür. Çoğu sorun birkaç temel komutla çözülür: ausearch ile ihlalin kaynağını bulun, semanage fcontext ve restorecon ile dosya bağlamlarını düzeltin, setsebool ile politika boolean değerlerini ayarlayın, semanage port ile port izinlerini yönetin.
En önemli alışkanlık, sorunla karşılaştığınızda ilk refleksinizin SELinux’u devre dışı bırakmak olmaması gerektiğidir. Bunun yerine birkaç dakika harcayıp audit loglarına bakın, sealert çalıştırın ve gerçek sorunu çözün. Hem sistem güvenliğini korumak hem de sorunların kök nedenini anlamak açısından bu yaklaşım çok daha değerlidir.
Production sistemlerde SELinux’u enforcing modda tutmak bir tercih değil, bir zorunluluktur. Özellikle internet’e açık servislerin çalıştığı sunucularda SELinux devre dışı bırakıldığında, bir güvenlik açığından yararlanmak çok daha kolaylaşır. Doğru yapılandırılmış SELinux politikaları, bir servis ele geçirilse bile saldırganın sistem genelinde hareket etmesini ciddi ölçüde kısıtlar.
