Linux’ta Dosya İzinleri Kaynaklı Sorunları Giderme
Bir web sunucusu gece yarısı çöküyor, uygulama log yazamıyor, kullanıcılar “Permission denied” hatası alıyor. Bu senaryoların hepsinin arkasında çoğu zaman tek bir şey yatıyor: yanlış yapılandırılmış dosya izinleri. Linux’ta dosya izinleri sistemi güçlü ama acımasızdır. Bir karakter yanlış olduğunda sistem tam anlamıyla felç olabilir. Bu yazıda dosya izni sorunlarını nasıl teşhis edip çözeceğimizi, gerçek dünya senaryolarıyla birlikte ele alacağız.
Dosya İzin Sistemini Hızlıca Hatırlayalım
Linux dosya izin sistemini anlamadan sorun gidermeye başlamak, haritasız bir şehirde yön aramak gibidir. Temel kavramları netleştirelim.
Her dosya ve dizin üç grup için üç tür izin barındırır:
- Sahip (owner/user): Dosyayı oluşturan kullanıcı
- Grup (group): Dosyanın ait olduğu grup
- Diğerleri (others): Geri kalan herkes
İzin türleri ise şunlardır:
- r (read – 4): Okuma izni
- w (write – 2): Yazma izni
- x (execute – 1): Çalıştırma izni (dizinler için girme izni)
ls -la /var/www/html/
# Örnek çıktı:
# -rw-r--r-- 1 www-data www-data 1234 Jan 15 10:30 index.html
# drwxr-xr-x 2 www-data www-data 4096 Jan 15 10:30 assets/
Burada -rw-r--r-- ifadesini okuyalım: Sahip okuyup yazabilir, grup sadece okuyabilir, diğerleri de sadece okuyabilir. Çalıştırma izni hiç yok.
Sorunları Teşhis Etmek: Nereden Başlamalı?
stat Komutu ile Detaylı Bilgi Alma
ls -la iyi bir başlangıç noktasıdır ama stat komutu çok daha fazla bilgi verir. Özellikle inode numarası, tam zaman damgaları ve sekizlik (octal) format görünümü açısından paha biçilmezdir.
stat /etc/nginx/nginx.conf
# Çıktı:
# File: /etc/nginx/nginx.conf
# Size: 2674 Blocks: 8 IO Block: 4096 regular file
# Device: fd00h/64768d Inode: 524291 Links: 1
# Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
# Access: 2024-01-15 10:30:00.000000000 +0300
# Modify: 2024-01-15 09:15:00.000000000 +0300
# Change: 2024-01-15 09:15:00.000000000 +0300
Sekizlik formattaki 0644 bilgisi, izinleri script ile kontrol ederken veya chmod ile set ederken doğrudan kullanabileceğiniz formattır.
find Komutu ile İzin Sorunlarını Taramak
Büyük bir dizin yapısında belirli izin sorunlarını bulmak için find komutu vazgeçilmezdir.
# 777 izinli tehlikeli dosyaları bul
find /var/www -perm 0777 -type f
# Sahipsiz dosyaları bul (kullanıcısı veya grubu silinmiş)
find /home -nouser -o -nogroup
# SUID bit'i set edilmiş dosyaları bul (güvenlik açısından kritik)
find / -perm -4000 -type f 2>/dev/null
# Belirli bir kullanıcının sahip olmadığı ama o dizinde olması gereken dosyalar
find /var/www/html -not -user www-data -type f
Bu komutları düzenli aralıklarla çalıştırmak, hem sorun giderme hem de güvenlik denetimi açısından son derece faydalıdır.
Gerçek Zamanlı İzin Hatalarını Yakalamak
Bir uygulama çalışırken izin hatası veriyorsa ve tam olarak hangi dosyaya erişmeye çalıştığını bilmiyorsanız, strace aracı hayat kurtarır.
# Bir sürecin sistem çağrılarını izle, sadece izin hatalarını filtrele
strace -e trace=openat,open,stat,access -p <PID> 2>&1 | grep -i "EACCES|EPERM"
# Ya da sıfırdan başlatarak izle
strace -e trace=file nginx -t 2>&1 | grep -i "permission|EACCES"
strace çıktısında EACCES görüyorsanız erişim reddedilmiş demektir, EPERM ise işlem izninin olmadığı anlamına gelir. Bu iki hata kodu arasındaki farkı bilmek, sorunun kaynağını hızlıca daraltmanıza yardımcı olur.
Yaygın Senaryolar ve Çözümleri
Senaryo 1: Web Sunucusu 403 Forbidden Hatası
En klasik izin sorunlarından biri bu. Nginx veya Apache çalışıyor, dosyalar yerli yerinde ama kullanıcılar 403 alıyor.
Önce web sunucusunun hangi kullanıcı ile çalıştığını tespit edelim:
ps aux | grep -E "nginx|apache|httpd" | grep -v grep
# www-data 1234 0.0 0.1 12345 6789 ? S 10:30 0:00 nginx: worker process
# Web sunucusunun erişmeye çalıştığı dosyanın izinlerini kontrol et
namei -l /var/www/html/index.html
# Çıktı her dizin seviyesinin izinlerini gösterir:
# f: /var/www/html/index.html
# drwxr-xr-x root root /
# drwxr-xr-x root root var
# drwxr-xr-x root root www
# drwx------ root root html <-- SORUN BURADA!
# -rw-r--r-- www-data www-data index.html
namei -l komutu bu senaryoda çok kritiktir. Dosyanın kendi izinleri doğru olsa bile, üst dizinlerden biri execute izni olmadığında web sunucusu dosyaya ulaşamaz. Yukarıdaki örnekte /var/www/html dizini drwx------ olarak görünüyor, yani sadece root okuyup girebilir.
# Çözüm
chmod 755 /var/www/html
# ya da sadece execute bitini ekle
chmod o+x /var/www/html
Senaryo 2: Uygulama Log Yazamıyor
Bir Django veya Laravel uygulaması çalışıyor ama log dosyasına yazamıyor. Uygulama sessizce fail oluyor ya da “Permission denied: /var/log/myapp/app.log” hatası veriyor.
# Log dizininin sahipliğini kontrol et
ls -la /var/log/myapp/
# drwxr-xr-x 2 root root 4096 Jan 15 10:30 .
# Uygulama hangi kullanıcı ile çalışıyor?
ps aux | grep gunicorn
# myappuser 5678 ... gunicorn myapp:app
# Sorun: Dizin root'a ait, uygulama myappuser ile çalışıyor
# Çözüm 1: Sahipliği değiştir
chown myappuser:myappuser /var/log/myapp/
# Çözüm 2: Grup bazlı çözüm (daha iyi pratik)
chown root:myappuser /var/log/myapp/
chmod 775 /var/log/myapp/
Burada grup bazlı çözümü tercih etmenizi öneririm. Birden fazla servis aynı log dizinine yazacaksa, hepsini aynı gruba ekleyip dizini o gruba 775 izinle verebilirsiniz. Bu hem güvenli hem de yönetilebilir bir yaklaşım.
Senaryo 3: SSH Key Authentication Çalışmıyor
“Permission denied (publickey)” hatası alıyorsunuz ama key’i doğru kopyaladığınıza eminsiniz. SSH izin konusunda son derece titizdir.
# SSH verbose modda bağlanmayı dene
ssh -vvv user@server 2>&1 | head -50
# Sunucu tarafında doğru izinleri kontrol et
ls -la ~/.ssh/
# Olması gereken:
# drwx------ 2 user user 4096 Jan 15 10:30 .ssh/
# -rw------- 1 user user 391 Jan 15 10:30 authorized_keys
# Home dizininin izinleri de önemli!
ls -la /home/ | grep user
# drwxr-xr-x 15 user user 4096 Jan 15 10:30 user <-- Bu doğru
# drwxrwxrwx 15 user user 4096 Jan 15 10:30 user <-- Bu SSH'ı reddeder!
SSH daemon’ı home dizini, .ssh dizini veya authorized_keys dosyası group/world-writable ise key authentication’ı tamamen reddeder. Bu bir güvenlik özelliğidir.
# Düzeltme
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 755 ~ # Home dizini en fazla bu olmalı
Senaryo 4: Cron Job Sessizce Başarısız Oluyor
Cron job’lar en sinsi izin sorunlarına neden olur çünkü hata mesajları gözden kaçabilir.
# Cron job'ların loglarını kontrol et
tail -f /var/log/cron
# ya da
journalctl -u cron -f
# Cron environment'ı çok kısıtlıdır. Test etmek için:
# Cron'un çalıştırdığı şekilde simüle et
sudo -u crondaemon env -i HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin /bin/bash -c '/path/to/script.sh'
# Script izinlerini kontrol et
ls -la /path/to/script.sh
# -rw-r--r-- 1 root root 234 Jan 15 10:30 script.sh
# SORUN: Execute izni yok!
chmod +x /path/to/script.sh
Cron’da önemli bir nokta daha: Script’in içinde kullandığı dosyalar ve dizinler de cron’u çalıştıran kullanıcı için erişilebilir olmalı. Script manuel çalıştığında root ile çalışıyorsa ama cron başka bir kullanıcı ile çalışıyorsa, her şey farklıdır.
Gelişmiş Konular: ACL ve Özel Bitler
Access Control Lists (ACL) ile İnce Ayar
Standart Unix izinleri bazen yeterli gelmez. Birden fazla kullanıcıya farklı izinler vermek gerektiğinde ACL devreye girer.
# ACL desteğini kontrol et
mount | grep acl
# ya da
tune2fs -l /dev/sda1 | grep "Default mount options"
# Mevcut ACL'leri görüntüle
getfacl /var/www/html/
# Belirli bir kullanıcıya özel izin ver
setfacl -m u:developer1:rwx /var/www/html/
setfacl -m u:designer:rx /var/www/html/assets/
# Varsayılan ACL ekle (yeni oluşturulacak dosyalara otomatik uygulanır)
setfacl -d -m u:developer1:rwx /var/www/html/
# ACL'yi kaldır
setfacl -x u:developer1 /var/www/html/
# ACL varsa ls çıktısında + işareti görürsün
ls -la /var/www/html/
# drwxrwxr-x+ 2 www-data www-data 4096 Jan 15 10:30 html
ACL kullandığınızda ls -la çıktısındaki + işaretine dikkat edin. Bu işaret o dizin ya da dosyada ACL tanımlandığını belirtir ve sadece standart izinlere bakarak tam resmi göremezsiniz.
SUID, SGID ve Sticky Bit
Bu özel bitleri anlamak hem sorun giderme hem de güvenlik açısından kritiktir.
# SUID bit: Dosya sahibinin yetkisiyle çalışır
# Klasik örnek: passwd komutu
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 Jan 5 10:00 /usr/bin/passwd
# 's' harfi SUID'i gösterir
# SGID bit: Grup yetkisiyle çalışır
# Ortak çalışma dizinlerinde faydalı
chmod g+s /shared/team/
ls -la /shared/
# drwxrwsr-x 2 root teamgroup 4096 Jan 15 10:30 team/
# Bu dizinde oluşturulan dosyalar otomatik olarak 'teamgroup' grubuna ait olur
# Sticky bit: Sadece dosya sahibi silebilir
# /tmp dizininin klasik kullanımı
ls -la /tmp
# drwxrwxrwt 15 root root 4096 Jan 15 10:30 tmp/
# 't' harfi sticky bit'i gösterir
# Ortak upload dizini için pratik kullanım
chmod +t /var/uploads/shared/
Özellikle SUID bitini taramak güvenlik açısından önemlidir. Sisteminizde beklenmedik SUID binary’leri varsa bu ciddi bir güvenlik sorununa işaret edebilir.
Sorun Giderme Araç Seti
auditd ile İzin Değişikliklerini Takip Etmek
Kimin hangi dosyanın iznini değiştirdiğini bilmek istiyorsanız, auditd tam size göre.
# auditd kural ekle: belirli dosyayı izle
auditctl -w /etc/passwd -p wa -k passwd_changes
auditctl -w /var/www/html -p wa -k webroot_changes
# Logları görüntüle
ausearch -k webroot_changes -ts today
aureport --file --start today
# Kalıcı kural eklemek için
echo "-w /etc/sudoers -p wa -k sudoers_mod" >> /etc/audit/rules.d/audit.rules
systemctl restart auditd
Bu özellikle ekip ortamında çok kritik. “Kim bu izinleri değiştirdi?” sorusunun cevabını her zaman bulabilirsiniz.
İzinleri Script ile Düzeltmek
Bir web uygulamasının tüm izinlerini düzeltmek gerektiğinde elle uğraşmak yerine script kullanın:
#!/bin/bash
# Web uygulama dizini izinlerini düzelt
# Kullanım: ./fix_permissions.sh /var/www/myapp www-data
APP_DIR=$1
WEB_USER=$2
if [ -z "$APP_DIR" ] || [ -z "$WEB_USER" ]; then
echo "Kullanim: $0 <dizin> <kullanici>"
exit 1
fi
echo "Sahiplik düzeltiliyor: $APP_DIR -> $WEB_USER"
chown -R $WEB_USER:$WEB_USER $APP_DIR
echo "Dizin izinleri ayarlanıyor: 755"
find $APP_DIR -type d -exec chmod 755 {} ;
echo "Dosya izinleri ayarlanıyor: 644"
find $APP_DIR -type f -exec chmod 644 {} ;
echo "Çalıştırılabilir dosyalar ayarlanıyor: 755"
find $APP_DIR -name "*.sh" -exec chmod 755 {} ;
find $APP_DIR/bin -type f -exec chmod 755 {} ; 2>/dev/null
echo "Tamamlandı!"
ls -la $APP_DIR
Bu tür script’leri /usr/local/bin/ altına koyup gerektiğinde hızlıca çalıştırabilirsiniz.
SELinux ve AppArmor: Gizli Engeller
Standart izinler tamam görünüyor ama hala “Permission denied” alıyorsanız, SELinux veya AppArmor devreye girmiş olabilir. Bu katman standart izinlerin üzerinde çalışır ve çoğu zaman gözden kaçar.
# SELinux durumunu kontrol et
sestatus
getenforce # Enforcing, Permissive, Disabled
# SELinux loglarını kontrol et
ausearch -m avc -ts recent
# ya da
journalctl -t setroubleshoot
# Dosyanın SELinux context'ini görüntüle
ls -lZ /var/www/html/
# -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html
# Yanlış context'i düzelt
chcon -t httpd_sys_content_t /var/www/html/myfile.html
# Kalıcı çözüm için:
semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
restorecon -Rv /var/www/html/
# AppArmor için
aa-status
cat /var/log/kern.log | grep "apparmor.*DENIED"
SELinux sorunlarını teşhis ederken audit2why ve audit2allow araçları inanılmaz faydalıdır:
# Neden reddedildi açıkla
ausearch -m avc -ts recent | audit2why
# İzin vermek için gerekli policy oluştur (dikkatli kullanın!)
ausearch -m avc -ts recent | audit2allow -M mypolicy
semodule -i mypolicy.pp
Pratik Hata Ayıklama Akışı
Bir izin sorunuyla karşılaştığınızda izlemeniz gereken adımlar şunlardır:
- Hata mesajını tam olarak oku: “Permission denied” mi, “Operation not permitted” mi? Fark önemli.
- Hangi kullanıcı, hangi dosyaya erişiyor:
ps auxile süreci,statile dosyayı kontrol et. - Tüm yol üzerindeki izinleri kontrol et:
namei -l /tam/yol/dosyakullan. - Sahiplik ve izinleri doğrula:
ls -lavestatile kontrol et. - ACL var mı bak:
getfaclile kontrol et. - SELinux veya AppArmor’ı kontrol et:
sestatusve audit logları. - Değişiklik yaptıysan test et: Uygulamayı restart etmeyi unutma.
Sonuç
Dosya izinleri kaynaklı sorunlar, Linux sistem yönetiminin en sık karşılaşılan ama aynı zamanda en kolay çözülebilen problemleri arasındadır. Temel prensipler basit görünse de SELinux, ACL, özel bitler ve servis kullanıcıları gibi katmanlar işi karmaşıklaştırabilir.
En önemli alışkanlık, değişiklik yapmadan önce mevcut durumu kaydetmektir. stat, ls -la, getfacl çıktılarını bir yere not edin. Yanlış bir chmod -R 777 komutu sonrasında neyin değiştiğini bilmiyorsanız geri dönmek çok zor olur.
Production ortamında her zaman en az ayrıcalık prensibini uygulayın: bir servise ne kadar az izin verirseniz, potansiyel güvenlik açıkları o kadar azalır. www-data kullanıcısının /etc dizinine yazma iznine ihtiyacı yoktur, mysql kullanıcısının home dizininde ne işi var?
Son olarak, auditd ile kritik dosyaları ve dizinleri izlemeye alın. Sorun çıktıktan sonra kim ne yaptı sorusuna cevap aramak yerine, her değişikliği önceden kayıt altına almak hayatı çok kolaylaştırır.
