fanotify ve inotifywait ile Dosya Sistemi Olaylarını İzleme ve Tetikleyici Oluşturma
Üretim ortamında bir şeyler ters gittiğinde, çoğu zaman ilk soru şu oluyor: “Bu dosya ne zaman değişti, kim değiştirdi?” Audit log’larına bakıyorsun, uygulama loglarını karıştırıyorsun ama gerçek zamanlı izleme yoksa cevabı bulmak saatler alıyor. İşte tam bu noktada Linux’un dosya sistemi olay altyapısı devreye giriyor. inotify ve fanotify mekanizmaları, kernel seviyesinde dosya sistemi olaylarını yakalamana ve bunlara anında tepki vermene olanak tanıyor. Bu yazıda hem teorik altyapıyı hem de gerçek dünya senaryolarında nasıl kullandığımı paylaşacağım.
Kernel Tarafında Ne Oluyor?
Linux kernel’i, dosya sistemi olaylarını iki farklı arayüz üzerinden kullanıcı alanına taşır: inotify ve fanotify. İkisi de farklı amaçlar için tasarlanmış.
inotify, 2005 yılında kernel 2.6.13 ile geldi. Belirli dosya ve dizinleri izlemek için kullanılır, hafif ve kullanımı kolaydır. Ancak bir sınırlaması var: izleme yaptığın dizinin alt dizinlerini özyinelemeli olarak izleyemez, bunu manuel olarak halletmen gerekir.
fanotify ise çok daha güçlü. 2009’da kernel 2.6.36 ile tanıtıldı ama asıl yetenekleri sonraki versiyonlarda geldi. Mount point seviyesinde izleme yapabilir, dosya erişimini engelleyebilir (permission event), işlem kimliğini raporlayabilir. Yani bir antivirüs, bir DLP (Data Loss Prevention) sistemi ya da gerçek zamanlı backup çözümü yazmak istiyorsan fanotify senin arkadaşın.
inotifywait ile Başlamak
Araç kurulumu basit:
# Debian/Ubuntu
apt install inotify-tools
# RHEL/CentOS/Rocky
dnf install inotify-tools
# Arch
pacman -S inotify-tools
inotify-tools paketi sana iki komut veriyor: inotifywait (tek seferlik veya sürekli izleme) ve inotifywatch (istatistik toplama). Biz çoğunlukla inotifywait kullanacağız.
Temel kullanım:
inotifywait -m /etc/nginx/conf.d/
Bu komut /etc/nginx/conf.d/ dizinini izlemeye başlar ve her olay geldiğinde ekrana basar. -m (monitor) olmadan tek olay bekler ve çıkar.
Olay Tipleri
İzleyebileceğin başlıca olaylar şunlar:
- CREATE: Dosya veya dizin oluşturuldu
- MODIFY: Dosya içeriği değişti
- CLOSE_WRITE: Yazma amaçlı açılan dosya kapatıldı
- DELETE: Dosya veya dizin silindi
- MOVED_FROM / MOVED_TO: Dosya taşındı
- ACCESS: Dosyaya erişildi (okundu)
- ATTRIB: Metadata değişti (izin, timestamp vs.)
- OPEN: Dosya açıldı
Genellikle CLOSE_WRITE olayı, MODIFY‘dan daha güvenilir bir trigger noktası. Çünkü MODIFY bir dosyaya yazıldıkça defalarca tetiklenebilir; CLOSE_WRITE ise yazma işlemi bittikten sonra tetiklenir.
İlk Gerçek Senaryo: Nginx Config Değişince Reload Et
Production’da çalışan bir Nginx sunucunda, config dosyası değiştiğinde otomatik olarak nginx -s reload çalıştırmak istiyorsun. Bunu basit bir shell script ile yapabilirsin:
#!/bin/bash
# /usr/local/bin/nginx-config-watcher.sh
WATCH_DIR="/etc/nginx"
LOG_FILE="/var/log/nginx-config-watcher.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log "Nginx config watcher başlatıldı. İzlenen dizin: $WATCH_DIR"
inotifywait -m -r -e close_write,create,delete
--format '%T %w %f %e'
--timefmt '%Y-%m-%d %H:%M:%S'
"$WATCH_DIR" | while read -r date time dir file event; do
# Sadece .conf uzantılı dosyaları işle
if [[ "$file" == *.conf ]]; then
log "Değişiklik algılandı: $dir$file ($event)"
# Config test et
if nginx -t 2>/dev/null; then
log "Config testi başarılı, reload yapılıyor..."
nginx -s reload
log "Nginx reload tamamlandı."
else
log "HATA: Config testi başarısız! Reload yapılmadı."
nginx -t 2>&1 | tee -a "$LOG_FILE"
fi
fi
done
Bu scripti systemd servis olarak çalıştırmak için:
# /etc/systemd/system/nginx-config-watcher.service
[Unit]
Description=Nginx Config File Watcher
After=nginx.service
[Service]
Type=simple
ExecStart=/usr/local/bin/nginx-config-watcher.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now nginx-config-watcher
Debounce Problemi ve Çözümü
Yukarıdaki basit örnekte kritik bir sorun var: bir metin editörü dosyayı kaydettiğinde birden fazla olay tetikleyebilir. Vim mesela geçici dosya oluşturur, siler, yeniden yazar. Bu durumda nginx -s reload saniyeler içinde 3-4 kez çalışabilir.
Bunu çözmek için debounce mantığı uygulaman gerekiyor:
#!/bin/bash
# Debounce'lu nginx watcher
WATCH_DIR="/etc/nginx"
DEBOUNCE_SECONDS=2
LAST_RELOAD=0
inotifywait -m -r -e close_write,create,delete
--format '%w%f'
"$WATCH_DIR" | while read -r filepath; do
[[ "$filepath" != *.conf ]] && continue
NOW=$(date +%s)
DIFF=$((NOW - LAST_RELOAD))
if [ "$DIFF" -ge "$DEBOUNCE_SECONDS" ]; then
LAST_RELOAD=$NOW
echo "[$(date)] $filepath değişti, reload tetikleniyor..."
nginx -t && nginx -s reload
else
echo "[$(date)] Debounce aktif, atlanıyor: $filepath"
fi
done
Özyinelemeli İzleme ve inotify Limitleri
-r parametresi ile özyinelemeli izleme yapabilirsin, ama burada önemli bir nokta var. Kernel’in izin verdiği maksimum inotify izleyici sayısı varsayılan olarak genellikle 8192’dir:
cat /proc/sys/fs/inotify/max_user_watches
# 8192
# Büyük dizin ağaçları için artır
echo 524288 >> /etc/sysctl.conf
sysctl -p
Büyük bir Git repository’sini ya da Node.js projelerini izlemeye çalışıyorsan node_modules klasörü tek başına bu limiti patlatabilir. Bunu -e ile olay filtresi, --exclude ile de dizin/dosya filtresi kullanarak kontrol altına alabilirsin:
inotifywait -m -r
--exclude '(.git|node_modules|.swp$|~$)'
-e close_write,create,delete
/var/www/myapp/
fanotify ile Daha Güçlü İzleme
fanotify doğrudan shell’den kullanmak için hazır araç sayısı inotify‘a göre daha az. fatrace en bilinen kullanıcı alanı aracı:
# Debian/Ubuntu
apt install fatrace
# Çalıştır (root gerektirir)
fatrace
fatrace çıktısı şöyle görünür:
vim(12543): W /home/user/notes.txt
bash(8821): R /etc/profile
nginx(1024): O /etc/nginx/nginx.conf
Format: process(pid): event path şeklinde. Olaylar R (read), W (write), O (open), C (close), D (directory) olarak gösteriliyor.
Belirli bir mount point’i izlemek için:
# Sadece /var/www altındaki yazma olaylarını göster
fatrace --current-mount -f W --mount /var/www
# Belirli bir process'i izle
fatrace | grep "nginx"
# Çıktıyı dosyaya yaz ve aynı zamanda ekranda göster
fatrace 2>/dev/null | tee /var/log/fatrace.log
Python ile fanotify Kullanımı
fanotify‘ın gerçek gücü C veya Python ile programatik kullanımında. Aşağıda python-inotify yerine doğrudan fanotify syscall’ını kullanan minimalist bir örnek var:
#!/usr/bin/env python3
"""
fanotify ile dosya erişim izleme
Gereksinimler: pip install cffi (veya ctypes kullanımı)
Root yetkisi gerektirir
"""
import os
import struct
import ctypes
import ctypes.util
# fanotify sabitleri
FAN_CLASS_NOTIF = 0x00000000
FAN_CLOEXEC = 0x00000001
FAN_NONBLOCK = 0x00000002
FAN_ACCESS = 0x00000001
FAN_MODIFY = 0x00000002
FAN_CLOSE_WRITE = 0x00000008
FAN_OPEN = 0x00000020
FAN_MARK_ADD = 0x00000001
FAN_MARK_MOUNT = 0x00000010
O_RDONLY = 0
AT_FDCWD = -100
libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
def fanotify_init(flags, event_f_flags):
return libc.syscall(300, flags, event_f_flags) # __NR_fanotify_init
def fanotify_mark(fanotify_fd, flags, mask, dirfd, path):
path_bytes = path.encode()
return libc.syscall(301, fanotify_fd, flags, mask,
ctypes.c_longlong(mask >> 32),
dirfd, path_bytes)
if os.geteuid() != 0:
print("Bu script root yetkisi gerektirir!")
exit(1)
fd = fanotify_init(FAN_CLASS_NOTIF | FAN_CLOEXEC, O_RDONLY)
if fd < 0:
print(f"fanotify_init başarısız: errno={ctypes.get_errno()}")
exit(1)
print(f"fanotify fd: {fd}, izleme başlıyor...")
# Gerçek implementasyon için python-fanotify kütüphanesi önerilir
Pratikte python-fanotify veya inotify_simple kütüphanelerini kullanmak çok daha verimli.
Gerçek Senaryo: Güvenlik Tetikleyicisi
Bir production sunucunda /etc/passwd, /etc/shadow veya /etc/sudoers dosyaları değiştiğinde anında uyarı almak kritik. İşte bunun için basit ama etkili bir script:
#!/bin/bash
# /usr/local/bin/security-file-monitor.sh
# Kritik sistem dosyalarını izle ve alert gönder
ALERT_EMAIL="[email protected]"
SLACK_WEBHOOK="https://hooks.slack.com/services/XXXX/YYYY/ZZZZ"
HOSTNAME=$(hostname -f)
CRITICAL_FILES=(
"/etc/passwd"
"/etc/shadow"
"/etc/sudoers"
"/etc/ssh/sshd_config"
"/root/.ssh/authorized_keys"
)
send_alert() {
local file="$1"
local event="$2"
local user
user=$(who am i 2>/dev/null | awk '{print $1}' || echo "unknown")
local message="[UYARI] $HOSTNAME üzerinde kritik dosya değişikliği!
Dosya: $file
Olay: $event
Zaman: $(date '+%Y-%m-%d %H:%M:%S')
Aktif kullanıcı: $user"
# Mail gönder
echo "$message" | mail -s "[GÜVENLİK UYARISI] Kritik dosya değişikliği - $HOSTNAME" "$ALERT_EMAIL"
# Slack webhook (curl ile)
curl -s -X POST "$SLACK_WEBHOOK"
-H 'Content-type: application/json'
--data "{"text":"$message"}" > /dev/null
# Sistem loguna yaz
logger -t security-monitor -p auth.warning "$message"
echo "$message"
}
# inotifywait ile izleme başlat
inotifywait -m
--format '%w %e'
-e modify,attrib,close_write,moved_to,create,delete
"${CRITICAL_FILES[@]}" | while read -r filepath event; do
send_alert "$filepath" "$event"
done
inotifywatch ile İstatistik Toplama
Bir sistemde hangi dosyaların en çok değiştiğini, hangi dizinlerin en aktif olduğunu bulmak için inotifywatch kullanabilirsin:
# 60 saniye boyunca /var/log altındaki olayları say
inotifywatch -r -t 60 -l 10 /var/log/
# Çıktı örneği:
# Dosya modify close_write open
# /var/log/syslog 142 71 89
# /var/log/auth.log 23 12 15
# /var/log/nginx/access.log 891 445 512
Bu bilgi, disk I/O darboğazlarını tespit etmekte veya beklenmedik dosya aktivitesini yakalamak için oldukça işe yarıyor.
Gelişmiş Kullanım: İzleme + Otomatik Yedekleme
Bir dizini izleyip değişen dosyaları otomatik olarak yedekleyen, üstelik değişiklik geçmişini tutan bir sistem:
#!/bin/bash
# Dosya değişikliği tetiklemeli artımlı yedekleme
SOURCE_DIR="/var/www/html"
BACKUP_BASE="/backup/web-incremental"
LOCK_FILE="/tmp/backup-trigger.lock"
mkdir -p "$BACKUP_BASE"
do_backup() {
local changed_file="$1"
# Lock kontrolü (paralel çalışmayı engelle)
if [ -f "$LOCK_FILE" ]; then
echo "Yedekleme zaten çalışıyor, atlanıyor..."
return
fi
touch "$LOCK_FILE"
TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
BACKUP_DIR="$BACKUP_BASE/$TIMESTAMP"
echo "[$(date)] Tetiklendi: $changed_file -> Yedekleme: $BACKUP_DIR"
# rsync ile sadece değişenleri kopyala, link-dest ile disk tasarrufu
rsync -a --link-dest="$BACKUP_BASE/latest"
"$SOURCE_DIR/" "$BACKUP_DIR/" 2>/dev/null
# latest symlink'i güncelle
ln -sfn "$BACKUP_DIR" "$BACKUP_BASE/latest"
# 7 günden eski yedekleri temizle
find "$BACKUP_BASE" -maxdepth 1 -type d -mtime +7 -exec rm -rf {} + 2>/dev/null
rm -f "$LOCK_FILE"
echo "[$(date)] Yedekleme tamamlandı: $BACKUP_DIR"
}
inotifywait -m -r
--exclude '(.swp$|.swx$|~$|.git)'
-e close_write,create,delete,moved_to
--format '%w%f'
"$SOURCE_DIR" | while read -r filepath; do
do_backup "$filepath"
done
Sistemde Kaç İzleyici Kullandığını Görmek
Monitoring kurulumların büyüdükçe inotify limitlerini takip etmek önemli:
# Mevcut kullanılan izleyici sayısını göster (process bazlı)
for pid in /proc/[0-9]*/fd; do
count=$(ls -la "$pid" 2>/dev/null | grep -c inotify)
if [ "$count" -gt 0 ]; then
proc=$(cat "/proc/${pid%/fd}/comm" 2>/dev/null)
echo "$proc (${pid%/fd#*/proc/}): $count inotify fd"
fi
done
# Toplam kullanılan watch sayısı
cat /proc/sys/fs/inotify/max_user_watches
# Ne kadar kullanıldığını görmek için:
find /proc/*/fdinfo -name '*' -exec grep -l inotify {} ; 2>/dev/null | wc -l
Pratik İpuçları ve Yaygın Hatalar
Yıllar içinde bu araçlarla uğraşırken öğrendiğim birkaç şey:
- NFS ve network dosya sistemleri üzerinde inotify çalışmaz. NFS mount’larını izlemek istiyorsan sunucu tarafında izleme yapman gerekiyor.
- Symbolic link’leri inotify takip etmez. Symlink’in kendisini değil, hedef dosyayı izlemelisin.
CLOSE_WRITE>MODIFY: Tetikleyici scripti için neredeyse her zamanCLOSE_WRITEkullan. Editörler dosyayı yazarkenMODIFYdefalarca tetiklenir.- Çok sayıda dizin izlerken
--fromfileparametresiyle izlenecek yolları dosyadan okuyabilirsin, komut satırı sınırını aşmazsın. fanotifyiçin production sistemlerdeFAN_CLASS_CONTENTveyaFAN_CLASS_PRE_CONTENTile permission event kullanacaksan kernel 5.1+ gerekiyor, bunu deployment öncesi doğrula.- Script’lerin başına
set -euo pipefailkoy, beklenmedik hata durumlarında script sessizce devam etmesin.
Sonuç
inotify ve fanotify, Linux’un sağladığı en kullanışlı kernel arayüzlerinden ikisi. Basit bir shell scriptiyle config reload otomasyonu yapabilir, Python ile özel bir dosya izleme daemon’ı yazabilir ya da güvenlik monitoring altyapının temelini kurabilirsin.
inotifywait günlük sysadmin işlerinde hızlıca sonuç almanı sağlar; hafif, kurması kolay, shell script’lere entegre edilmesi basit. fanotify ise daha karmaşık gereksinimlerde, özellikle işlem kimliği takibi ve erişim engelleme istediğinde devreye giriyor.
Şunu da söyleyeyim: bu araçları production’a almadan önce mutlaka yük testlerinden geçir. Yoğun yazma trafiği olan sistemlerde inotify event queue dolabilir ve olaylar kaybedilebilir. max_queued_events parametresini (/proc/sys/fs/inotify/max_queued_events) ihtiyaca göre ayarlamayı unutma. Gerçek zamanlı dosya sistemi izleme güçlü bir araç, ama kendi olay döngüsünde bir darboğaz yaratmaması için dikkatli tasarlanması gerekiyor.
