Yeni bir CentOS ya da Rocky Linux sunucu kurduğunuzda, ilk karşılaştığınız engellerden biri genellikle SELinux olur. Servis çalışmıyor, log dosyası yazılamıyor ya da web uygulaması port dinleyemiyor. Sonunda birisi “SELinux’u kapat, sorun çözülür” diyor. Ve maalesef çoğu zaman öyle yapılıyor. Ama bu, yangını söndürmek yerine yangın dedektörünü kapatmak gibidir. Bu yazıda SELinux’un ne olduğunu, nasıl çalıştığını ve gerçek dünyada nasıl yönetileceğini öğreneceğiz.
SELinux Nedir?
SELinux, Security-Enhanced Linux kelimelerinin kısaltmasıdır. NSA (Ulusal Güvenlik Ajansı) tarafından geliştirilmiş ve Linux çekirdeğine entegre edilmiş bir zorunlu erişim kontrolü (Mandatory Access Control – MAC) sistemidir.
Geleneksel Linux erişim kontrolü, DAC (Discretionary Access Control) modeline dayanır. Yani dosya sahibi kim ise, o dosyaya kimlerin erişeceğine o karar verir. chmod ve chown ile yönettiğimiz klasik kullanıcı/grup/diğerleri modeli budur. Bu modelin en büyük açığı şudur: root kullanıcısı her şeyi yapabilir. Bir servis root olarak çalışıyorsa ve ele geçirilirse, tüm sistem risk altına girer.
SELinux ise bunun üzerine bir katman daha ekler. “Bu işlem bu kaynağa erişebilir mi?” sorusunu, kullanıcı kimliğinden bağımsız olarak politikalar üzerinden yanıtlar. Root bile olsanız, SELinux politikası izin vermiyorsa o işlemi yapamazsınız.
SELinux’un Temel Çalışma Mantığı
SELinux, her şeye bir etiket (label) atar. Dosyalar, dizinler, process’ler, portlar, soketler… Hepsi etiketlenir. Bu etiketlere SELinux context (bağlam) denir.
Bir context şu yapıdadır:
kullanici:rol:tip:seviye
Gerçek bir örneğe bakalım:
ls -Z /var/www/html/index.html
Çıktı şuna benzer:
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
Burada:
- system_u: SELinux kullanıcısı
- object_r: Rol
- httpd_sys_content_t: Tip (en önemli kısım)
- s0: Güvenlik seviyesi (MLS için)
Günlük yönetimde en çok tip kısmıyla ilgileniriz. Apache web sunucusu sadece httpd_sys_content_t tipindeki dosyalara erişebilir. Başka bir dizindeki dosyaya, dosya izinleri ne olursa olsun erişemez.
SELinux Modları
SELinux üç modda çalışabilir:
- Enforcing: SELinux aktif ve politikaları uygular. İzin verilmeyen her şey engellenir ve loglanır.
- Permissive: SELinux aktif ama politikaları uygulamaz. Sadece ihlalleri loglar. Test için mükemmeldir.
- Disabled: SELinux tamamen kapalıdır. Önerilmez.
Mevcut durumu görmek için:
getenforce
sestatus
sestatus daha detaylı bilgi verir:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux mount point: /sys/fs/selinux
SELinuxfs mount: /sys/fs/selinux
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
Mod Değiştirme
Geçici olarak (reboot’a kadar) mod değiştirmek için:
# Permissive moda geç
setenforce 0
# Enforcing moda geri dön
setenforce 1
Kalıcı değişiklik için /etc/selinux/config dosyasını düzenleyin:
cat /etc/selinux/config
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
Önemli not: Disabled’dan Enforcing’e geçerken ya da uzun süre Permissive’de kaldıktan sonra Enforcing’e dönerken, sistemin dosyaları yeniden etiketlemesi gerekir. Aksi takdirde yanlış etiketlenmiş dosyalar yüzünden sistem boot bile olmayabilir.
Yeniden etiketleme için:
# Bir sonraki boot'ta tüm sistemi yeniden etiketle
touch /.autorelabel
reboot
Temel SELinux Araçları
semanage – Politika Yönetimi
semanage aracı SELinux politikalarını yönetmek için kullanılır. policycoreutils-python-utils paketinde gelir:
dnf install policycoreutils-python-utils
restorecon – Context Düzeltme
Yanlış etiketlenmiş dosyaları düzeltmek için kullanılır:
# Tek dosya
restorecon /var/www/html/yeni_dosya.html
# Dizin ve altındaki her şeyi özyinelemeli olarak düzelt
restorecon -Rv /var/www/html/
-R özyinelemeli, -v verbose (ayrıntılı çıktı) anlamına gelir.
chcon – Geçici Context Değişikliği
Dosya context’ini geçici olarak değiştirir. restorecon çalıştırıldığında eski haline döner:
chcon -t httpd_sys_content_t /baska/dizin/dosya.html
Gerçek Dünya Senaryosu 1: Apache Web Sunucusu
Diyelim ki /data/web dizinine Apache site dosyalarınızı koydunuz ama site çalışmıyor.
mkdir -p /data/web
echo "<h1>Merhaba</h1>" > /data/web/index.html
# Apache config'de DocumentRoot /data/web olarak ayarlandı
systemctl restart httpd
# Tarayıcıdan bağlandığınızda 403 Forbidden hatası alıyorsunuz
Sorunu SELinux loglarında görelim:
# audit loglarında SELinux engellemelerini filtrele
grep "denied" /var/log/audit/audit.log | grep httpd | tail -20
Ya da ausearch ile daha temiz bir çıktı:
ausearch -m avc -ts recent
Çıktıda şunun gibi bir satır göreceksiniz:
type=AVC msg=audit(1234567890.123:456): avc: denied { read } for pid=1234 comm="httpd" name="index.html" dev="sda1" ino=789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
Bu mesaj Apache’nin (httpd_t) default_t tipindeki dosyayı okumaya çalışırken engellendiğini söylüyor.
Çözüm için /data/web dizinine doğru SELinux tipi atayalım:
# Dizin için kalıcı context tanımla
semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?"
# Mevcut dosyalara yeni context'i uygula
restorecon -Rv /data/web/
Artık Apache bu dizine erişebilir.
Gerçek Dünya Senaryosu 2: Apache’nin Farklı Port Kullanması
Apache’yi 8080 yerine 8888 portunda çalıştırmak istiyorsunuz:
# httpd.conf'ta Listen 8888 eklediniz
systemctl restart httpd
# Servis başlamıyor
journalctl -xe | grep httpd
SELinux, Apache’nin 8888 portunu dinlemesine izin vermiyor çünkü bu port Apache için tanımlı değil. İzin verilen portları görelim:
semanage port -l | grep http
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_port_t tcp 80, 443, 488, 8008, 8009, 8443, 9000
8888 listede yok. Ekleyelim:
semanage port -a -t http_port_t -p tcp 8888
Doğrulayalım:
semanage port -l | grep http_port_t
http_port_t tcp 80, 443, 488, 8008, 8009, 8443, 8888, 9000
Artık Apache’yi yeniden başlatabilirsiniz.
Boolean’lar ile Politika Yönetimi
SELinux’un en kullanışlı özelliklerinden biri Boolean‘lardır. Önceden tanımlanmış politikaları açıp kapatmaya yarayan anahtarlardır. Politika yazmak zorunda kalmadan sık kullanılan senaryoları etkinleştirebilirsiniz.
Mevcut Boolean’ları listeleyin:
# Tüm boolean'lar
getsebool -a
# Sadece httpd ile ilgili olanlar
getsebool -a | grep httpd
Yaygın kullanılan bazı Boolean’lar:
- httpd_can_network_connect: Apache’nin dış ağ bağlantısı yapmasına izin verir (PHP uygulamaları için gerekebilir)
- httpd_can_network_connect_db: Apache’nin veritabanına bağlanmasına izin verir
- httpd_use_nfs: Apache’nin NFS dosyalarına erişmesine izin verir
- httpd_enable_homedirs: Apache’nin home dizinlerine erişmesine izin verir
- samba_enable_home_dirs: Samba’nın home dizinlerini paylaşmasına izin verir
Boolean değiştirme:
# Geçici değiştirme (reboot'ta sıfırlanır)
setsebool httpd_can_network_connect on
# Kalıcı değiştirme (-P flag'i)
setsebool -P httpd_can_network_connect on
Gerçek Senaryo: PHP Uygulaması Dış Servise Bağlanamıyor
WordPress ya da başka bir PHP uygulaması dış API’ye bağlanamıyor, curl işlemleri başarısız oluyor:
# Sorunu tespit et
ausearch -m avc -ts recent | grep httpd
# Büyük ihtimalle httpd_can_network_connect kapalıdır
getsebool httpd_can_network_connect
# httpd_can_network_connect --> off
# Kalıcı olarak aç
setsebool -P httpd_can_network_connect on
audit2allow ile Özel Politika Oluşturma
Bazen mevcut Boolean’lar ihtiyacınızı karşılamaz. Bu durumda kendi politikanızı yazabilirsiniz. audit2allow aracı, audit loglarındaki engellemeleri analiz ederek sizin için politika modülü oluşturur.
# Son engellemeleri görüntüle
ausearch -m avc -ts recent | audit2allow
# Politika modülü oluştur
ausearch -m avc -ts recent | audit2allow -M benim_politikam
# Politikayı yükle
semodule -i benim_politikam.pp
Daha spesifik bir örnek, diyelim ki özel bir uygulama çalıştırıyorsunuz:
# Önce permissive modda çalıştır ve logları topla
ausearch -m avc -c "uygulamam" | audit2allow -M uygulamam_politika
semodule -i uygulamam_politika.pp
Dikkat: audit2allow ile üretilen politikaları körü körüne uygulamayın. Önce audit2allow -w ile insan tarafından okunabilir açıklamasını inceleyin:
ausearch -m avc -ts recent | audit2allow -w
Process Context’ini İnceleme
Çalışan process’lerin SELinux context’ini görmek için:
# Tüm process'ler
ps auxZ
# Sadece httpd
ps -eZ | grep httpd
Çıktı:
system_u:system_r:httpd_t:s0 1234 ? 00:00:01 httpd
Kendi kullanıcınızın context’i:
id -Z
# unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
unconfined_t normal kullanıcıların tipidir ve daha az kısıtlamaya tabidir. Sistem servisleri ise httpd_t, mysqld_t gibi daha kısıtlı tiplerde çalışır.
SELinux Loglarını Okuma
SELinux ihlalleri /var/log/audit/audit.log dosyasına yazılır. setroubleshootd servisi aktifse daha anlaşılır açıklamalar /var/log/messages dosyasına da düşer.
# audit.log'dan son AVC mesajları
grep "AVC" /var/log/audit/audit.log | tail -20
# setroubleshoot mesajları
grep "sealert" /var/log/messages | tail -10
sealert aracı çok işe yarar. Hata ID’siyle detaylı analiz yapar:
# Tüm uyarıları listele
sealert -a /var/log/audit/audit.log
# Belirli bir uyarı ID'si için (log'da geçen UUID)
sealert -l <uuid>
sealert çıktısı genellikle sorunu açıklar ve çözüm önerileri sunar:
SELinux is preventing httpd from read access on the file index.html.
***** Plugin restorecon (99.5 confidence) suggests ****
If you want to fix the label.
/data/web/index.html default label should be httpd_sys_content_t.
Then you can run restorecon. The access attempt may have been stopped due to insufficient permissions...
Do
# /sbin/restorecon -v /data/web/index.html
Dosya Context’i Kalıcı Olarak Tanımlama
chcon ile yapılan değişiklikler geçicidir. restorecon çalıştırıldığında ya da sistem yeniden etiketlendiğinde sıfırlanır. Kalıcı tanımlama için semanage fcontext kullanılır:
# Tek dosya için
semanage fcontext -a -t httpd_sys_content_t "/data/web/index.html"
# Dizin ve tüm içeriği için
semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?"
# Tanımlanan context'leri listele
semanage fcontext -l | grep /data/web
# Tanımlamayı sil
semanage fcontext -d "/data/web(/.*)?"
Tanımladıktan sonra mevcut dosyalara uygulamak için restorecon çalıştırın:
restorecon -Rv /data/web/
Servis Dosyaları ve SELinux
Systemd ile başlatılan özel servisler için SELinux context’i doğru atanmalıdır. Bir Python/Node.js uygulamanızı systemd servisi olarak çalıştırıyorsanız:
# Servis dosyasının context'ini kontrol et
ls -Z /etc/systemd/system/uygulamam.service
# Binary veya betik dosyasının context'ini kontrol et
ls -Z /opt/uygulamam/app.py
Özel uygulama binary’leri için genellikle bin_t ya da usr_t tipi kullanılır. Eğer uygulama sistem kaynaklarına erişiyorsa özel bir politika yazmanız gerekebilir.
Troubleshooting Metodolojisi
SELinux sorunlarını sistematik olarak çözmek için şu adımları izleyin:
1. Gerçekten SELinux mi?
# Geçici olarak permissive yap
setenforce 0
# Servisi test et
systemctl restart httpd
curl http://localhost
# Çalışıyorsa sorun SELinux'tan, enforcing'e geri dön
setenforce 1
2. Logları incele
ausearch -m avc -ts recent
3. sealert ile analiz et
sealert -a /var/log/audit/audit.log
4. Çözümü uygula
- Yanlış context varsa:
semanage fcontext+restorecon - Port sorunu varsa:
semanage port - Boolean yeterliyse:
setsebool -P - Hiçbiri yetmiyorsa:
audit2allowile özel politika
5. Enforcing modda test et
setenforce 1
systemctl restart httpd
Sık Yapılan Hatalar
- SELinux’u disabled yapmak: Güvenlik katmanını tamamen kaldırır. Permissive yeterlidir sorun tespiti için.
- chcon kullanmak: Kalıcı değildir.
semanage fcontextkullanın. - audit2allow çıktısını incelemeden uygulamak: Güvenlik açığı yaratabilir.
- Permissive’de unutmak: Test için permissive’e geçip sonra enforcing’e dönmeyi unutmayın.
Özellikle production ortamda setenforce 0 yapıp unutmak tehlikelidir. Bunu önlemek için monitoring’inize SELinux mod kontrolü ekleyin:
# Cron ile her saat kontrol
echo "0 * * * * root getenforce | grep -q Enforcing || echo 'SELinux Enforcing degil!' | mail -s 'SELinux Uyarisi' [email protected]" >> /etc/cron.d/selinux_check
Sonuç
SELinux, doğru anlaşıldığında sisteminize çok güçlü bir güvenlik katmanı ekler. “Kapatayım da sorun çıkmasın” yaklaşımı, uzun vadede çok daha büyük sorunlara kapı aralar.
Öğrenme eğrisi biraz dik görünebilir ama pratikte en çok kullandığınız komutlar ausearch, sealert, semanage fcontext, restorecon ve setsebool olacak. Bu beş aracı iyi öğrenirseniz karşılaşacağınız sorunların büyük çoğunluğunu çözebilirsiniz.
Permissive mod sizin en iyi arkadaşınızdır: Sorun tespit ederken permissive’e geçin, logları toplayın, politikayı düzeltin, enforcing’e dönün. Bu döngüyü otomatikleştirmeyi ve CI/CD süreçlerinize entegre etmeyi düşünün.
Son olarak, Rocky Linux ve CentOS Stream’in SELinux dokümantasyonu oldukça kapsamlıdır. man semanage, man restorecon ve man audit2allow man sayfaları gerçekten okunmaya değer kaynaklardır.