SELinux Nedir: Temel Kavramlar ve Yönetim

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: audit2allow ile ö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 fcontext kullanı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.

Yorum yapın