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 aux ile süreci, stat ile dosyayı kontrol et.
  • Tüm yol üzerindeki izinleri kontrol et: namei -l /tam/yol/dosya kullan.
  • Sahiplik ve izinleri doğrula: ls -la ve stat ile kontrol et.
  • ACL var mı bak: getfacl ile kontrol et.
  • SELinux veya AppArmor’ı kontrol et: sestatus ve 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.

Benzer Konular

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir