Bir sunucuda birden fazla kullanıcıya erişim vermek zorunda kaldığınızda, “bu kullanıcı acaba sistemin başka yerlerine girip bir şeyler karıştırır mı?” diye düşünmeyen sysadmin yoktur. İşte tam bu noktada chroot devreye giriyor. chroot, bir kullanıcının ya da sürecin görebileceği kök dizini değiştirerek onu belirli bir dizin yapısına hapseden güçlü bir Linux mekanizması. Bu yazıda chroot’u gerçek senaryolarla, sıfırdan yapılandırma adımlarıyla ve dikkat etmeniz gereken ince noktalarıyla ele alacağız.
chroot Nedir, Ne İşe Yarar?
chroot (change root) sistem çağrısı, bir process ve onun child process’leri için kök dizini (/) olarak görünen yolu değiştirir. Yani bir kullanıcıyı /home/guvenli-alan dizinine chroot’ladığınızda, o kullanıcı bu dizini / olarak görür. /etc/passwd dosyasına ulaşmak istese, aslında /home/guvenli-alan/etc/passwd dosyasına ulaşır. Gerçek sistem dosyalarına hiç dokunamaz.
Bu mekanizmanın kullanım alanları oldukça geniş:
- SFTP kullanıcı kısıtlaması: Müşterilere veya dış ekiplere sadece kendi dizinlerine erişim sağlamak
- FTP sandbox: vsftpd veya proftpd kullanıcılarını belirli dizine kilitlemek
- Geliştirici izolasyonu: Dev ekibine production sunucusunda kısıtlı bir alan açmak
- Güvenli servis çalıştırma: Apache, DNS gibi servisleri izole ortamda koşturmak
- Sistem kurtarma: Bozuk bir sistemi başka bir live ortamdan chroot ile düzeltmek
chroot ile SFTP Kullanıcısı Hapsetme (En Yaygın Senaryo)
Diyelim ki bir web ajansı çalışıyorsunuz ve müşterilerinize sadece kendi web dosyalarına erişim veren SFTP hesapları açmanız gerekiyor. Bu senaryoyu adım adım kuralım.
1. Kullanıcı ve Grup Oluşturma
Önce SFTP kullanıcıları için özel bir grup oluşturalım:
groupadd sftp_users
useradd -m -d /home/musteri1 -s /sbin/nologin -G sftp_users musteri1
passwd musteri1
Burada -s /sbin/nologin ile kullanıcının SSH shell erişimini engelliyoruz. Sadece SFTP yapabilecek.
2. Dizin Yapısını Hazırlama
chroot için en kritik nokta şu: chroot dizininin sahibi root olmalı ve group/other için write izni olmamalı. OpenSSH bu kurala çok katı uyar, aksi halde bağlantıyı reddeder.
# chroot kök dizini root'a ait olmalı
chown root:root /home/musteri1
chmod 755 /home/musteri1
# Kullanıcının yazabileceği alt dizini oluştur
mkdir -p /home/musteri1/files
chown musteri1:musteri1 /home/musteri1/files
chmod 755 /home/musteri1/files
3. SSH Yapılandırması
/etc/ssh/sshd_config dosyasını düzenleyelim:
# Mevcut Subsystem satırını değiştir veya kontrol et
Subsystem sftp internal-sftp
# Dosyanın sonuna ekle
Match Group sftp_users
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
%h burada kullanıcının home dizinini temsil eder. Tüm sftp_users grubundaki kullanıcılar kendi home dizinlerine hapsedilir. Yapılandırmayı uygulamak için:
systemctl restart sshd
# veya
service sshd restart
Bağlantı testi yapmak için:
sftp musteri1@sunucu_ip
# Başarılı olursa /files dizinini görmeli, üst dizine çıkamamalı
Manuel chroot Ortamı Kurma
Bazen SFTP değil, gerçek bir shell ortamı oluşturmanız gerekebilir. Mesela bir geliştirici takımına sınırlı bir bash ortamı vermek istiyorsunuz. Bu durumda chroot içine gerekli binary’leri ve kütüphaneleri taşımanız gerekiyor.
Temel Dizin Yapısı
CHROOT_DIR="/opt/chroot_env"
# Temel dizinleri oluştur
mkdir -p ${CHROOT_DIR}/{bin,lib,lib64,etc,home,tmp,usr/bin}
# tmp dizinine uygun izinler
chmod 1777 ${CHROOT_DIR}/tmp
Binary ve Kütüphaneleri Kopyalama
Bir binary’yi chroot içinde çalıştırmak için o binary’nin ihtiyaç duyduğu tüm shared library’leri de kopyalamanız gerekiyor. ldd komutu bize bu bağımlılıkları gösterir:
# bash için gerekli kütüphaneleri bul
ldd /bin/bash
# Örnek çıktı:
# linux-vdso.so.1 (0x00007ffce8fd3000)
# libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
# /lib64/ld-linux-x86-64.so.2
# bash'i kopyala
cp /bin/bash ${CHROOT_DIR}/bin/
# Kütüphaneleri kopyala
cp /lib/x86_64-linux-gnu/libtinfo.so.6 ${CHROOT_DIR}/lib/
cp /lib/x86_64-linux-gnu/libc.so.6 ${CHROOT_DIR}/lib/
cp /lib64/ld-linux-x86-64.so.2 ${CHROOT_DIR}/lib64/
Bu işlemi her binary için tek tek yapmak yorucu. Şu script ile otomatize edebilirsiniz:
#!/bin/bash
# copy_binary.sh - Binary ve bağımlılıklarını chroot'a kopyalar
CHROOT_DIR="/opt/chroot_env"
BINARY=$1
if [ -z "$BINARY" ]; then
echo "Kullanim: $0 /path/to/binary"
exit 1
fi
# Binary'yi kopyala
cp "$BINARY" "${CHROOT_DIR}/bin/"
# ldd çıktısını işle ve kütüphaneleri kopyala
ldd "$BINARY" | grep -o '/[^ ]*' | while read lib; do
if [ -f "$lib" ]; then
# Hedef dizini oluştur
LIB_DIR=$(dirname "$lib")
mkdir -p "${CHROOT_DIR}${LIB_DIR}"
cp "$lib" "${CHROOT_DIR}${LIB_DIR}/"
echo "Kopyalandi: $lib"
fi
done
echo "Tamamlandi: $BINARY"
Bu scripti kullanarak temel araçları ekleyebilirsiniz:
chmod +x copy_binary.sh
./copy_binary.sh /bin/bash
./copy_binary.sh /bin/ls
./copy_binary.sh /bin/cat
./copy_binary.sh /usr/bin/vim
/etc/passwd ve /etc/group Kopyalama
chroot içindeki bazı araçların kullanıcı bilgilerine ihtiyacı olabilir:
# Sadece chroot kullanıcısı ile ilgili satırları ekle
grep "musteri1" /etc/passwd > ${CHROOT_DIR}/etc/passwd
grep "musteri1" /etc/group > ${CHROOT_DIR}/etc/group
# Gerekirse temel sistem satırlarını da ekle
echo "root:x:0:0:root:/root:/bin/bash" >> ${CHROOT_DIR}/etc/passwd
chroot’a Girmek ve Kullanıcı Yönetimi
Root olarak chroot ortamına girmek için:
chroot /opt/chroot_env /bin/bash
# Artık / olarak /opt/chroot_env'i görüyorsunuz
# Test
pwd
# /
ls /
# bin etc home lib lib64 tmp usr
Belirli bir kullanıcı olarak chroot’a girmek için:
chroot --userspec=musteri1:musteri1 /opt/chroot_env /bin/bash
SSH ile chroot Shell Erişimi
Kullanıcıya chroot içinde gerçek bir bash shell’i vermek istiyorsanız, bu sefer /etc/ssh/sshd_config‘i farklı yapılandırıyoruz:
Match User gelistirici1
ChrootDirectory /opt/chroot_env
AllowTcpForwarding no
X11Forwarding no
Dikkat: Bu durumda ForceCommand internal-sftp satırını eklemeyin, çünkü kullanıcıya gerçek shell erişimi veriyorsunuz. Kullanıcının shell’i /bin/bash olarak ayarlı olmalı ve bu bash chroot içinde mevcut olmalı.
usermod -s /bin/bash gelistirici1
Gerçek Dünya Senaryosu: Web Hosting Müşteri İzolasyonu
Diyelim ki küçük bir hosting altyapısı yönetiyorsunuz. Her müşterinin kendi web dosyalarına erişmesi, ama başka müşterilerin dosyalarına ya da sistem dosyalarına ulaşamaması gerekiyor. İşte bunu otomatize eden bir script:
#!/bin/bash
# create_sftp_user.sh
# Kullanim: ./create_sftp_user.sh kullanici_adi
USERNAME=$1
BASE_DIR="/var/www/clients"
SFTP_GROUP="sftp_users"
if [ -z "$USERNAME" ]; then
echo "Kullanici adi belirtmediniz!"
echo "Kullanim: $0 kullanici_adi"
exit 1
fi
# Kullanici var mi kontrol et
if id "$USERNAME" &>/dev/null; then
echo "Hata: $USERNAME kullanicisi zaten mevcut!"
exit 1
fi
# Kullaniciyi olustur
useradd -m -d "${BASE_DIR}/${USERNAME}"
-s /sbin/nologin
-G "$SFTP_GROUP"
"$USERNAME"
if [ $? -ne 0 ]; then
echo "Kullanici olusturma basarisiz!"
exit 1
fi
# Dizin izinlerini ayarla (chroot kurallari)
chown root:root "${BASE_DIR}/${USERNAME}"
chmod 755 "${BASE_DIR}/${USERNAME}"
# Kullanicinin yazabilecegi web dizinini olustur
mkdir -p "${BASE_DIR}/${USERNAME}/www"
chown "${USERNAME}:${USERNAME}" "${BASE_DIR}/${USERNAME}/www"
chmod 755 "${BASE_DIR}/${USERNAME}/www"
# Rastgele guclu sifre olustur
PASS=$(openssl rand -base64 16)
echo "${USERNAME}:${PASS}" | chpasswd
echo "============================================"
echo "Kullanici basariyla olusturuldu!"
echo "Kullanici Adi : $USERNAME"
echo "Sifre : $PASS"
echo "SFTP Dizini : ${BASE_DIR}/${USERNAME}/www"
echo "============================================"
echo "Bu bilgileri guvenli bir yerde saklayin!"
Bu scripti kullandıktan sonra /etc/ssh/sshd_config‘e şu blok eklenmiş olmalı:
Match Group sftp_users
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
AllowAgentForwarding no
Yaygın Sorunlar ve Çözümleri
“bad ownership or modes for chroot directory” Hatası
Bu hata OpenSSH’ın en sık verdiği chroot hatasıdır. Çözüm:
# Sahiplik ve izinleri kontrol et
ls -la /home/musteri1
# Düzelt
chown root:root /home/musteri1
chmod 755 /home/musteri1
# Alt dizinler de kontrol edilmeli
ls -la /home/musteri1/
Kural: chroot dizini ve üstündeki tüm dizinler root’a ait olmalı, başkaları tarafından yazılabilir olmamalı.
“No such file or directory” Hatası (Kütüphane Eksikliği)
chroot içinde bir binary çalıştırmaya çalışırken bu hatayı alıyorsanız, muhtemelen bir kütüphane eksiktir:
# strace ile neyin eksik olduğunu bul
strace chroot /opt/chroot_env /bin/bash 2>&1 | grep "No such file"
# Ya da doğrudan ldd ile kontrol et
ldd /bin/bash
/dev/null ve Diğer Device Dosyaları
Bazı uygulamalar /dev/null, /dev/zero gibi device dosyalarına ihtiyaç duyar:
mkdir -p /opt/chroot_env/dev
# null device oluştur
mknod -m 666 /opt/chroot_env/dev/null c 1 3
mknod -m 666 /opt/chroot_env/dev/zero c 1 5
mknod -m 666 /opt/chroot_env/dev/random c 1 8
mknod -m 444 /opt/chroot_env/dev/urandom c 1 9
# Sahipliği ayarla
chown root:root /opt/chroot_env/dev/*
/proc Bağlama (Gerekirse)
Eğer chroot ortamında process bilgilerine ihtiyaç varsa:
mkdir -p /opt/chroot_env/proc
mount -t proc proc /opt/chroot_env/proc
# Kalıcı olması için /etc/fstab'a ekle
echo "proc /opt/chroot_env/proc proc defaults 0 0" >> /etc/fstab
chroot’un Sınırlamaları
chroot güçlü bir araç ama bir güvenlik duvarı değil. Şu sınırlamaları aklınızda tutun:
- Root kullanıcı chroot’tan çıkabilir: Eğer chroot içinde root yetkisi varsa, chroot atlatılabilir. Bu yüzden chroot içinde kesinlikle root yetkisi vermemelisiniz.
- Kernel paylaşımı: chroot aynı kernel’i paylaşır. Kernel exploit’lerine karşı koruma sağlamaz.
- Network izolasyonu yok: chroot içindeki süreçler hala aynı network interface’leri kullanır.
- Namespace izolasyonu yok: Docker veya LXC gibi tam izolasyon sağlamaz.
Tam izolasyon için chroot yerine Linux Namespace’leri, cgroups veya container teknolojilerini (Docker, LXC, systemd-nspawn) değerlendirin.
chroot vs. Alternatifler: Hangisini Ne Zaman Kullanmalı?
- chroot kullanın: Basit SFTP kısıtlaması, düşük riskli kullanıcı izolasyonu, eski sistemlerle uyumluluk gerektiğinde
- systemd-nspawn kullanın: chroot’tan daha güçlü izolasyon istiyorsanız ama Docker kadar karmaşık bir şey istemiyorsanız
- Docker/LXC kullanın: Tam servis izolasyonu, mikro servis mimarileri, güvenlik kritik senaryolar için
- SELinux/AppArmor kullanın: Process bazlı kısıtlama, sistem geneli güvenlik politikası gerektiğinde
Bakım ve İzleme
chroot ortamları zamanla bakım gerektirir. Özellikle kütüphaneler güncellendiğinde chroot içindeki kopyaların da güncellenmesi gerekebilir:
#!/bin/bash
# chroot_check.sh - chroot ortamının sağlığını kontrol eder
CHROOT_DIR="/opt/chroot_env"
echo "=== chroot Ortam Kontrolu ==="
echo ""
# Dizin izinlerini kontrol et
echo "Dizin sahipligi:"
ls -la "$CHROOT_DIR" | head -5
echo ""
echo "Kütüphane versiyonlari:"
for lib in $(find "${CHROOT_DIR}/lib" -name "*.so*" -type f 2>/dev/null); do
BASENAME=$(basename "$lib")
SYSTEM_LIB=$(find /lib /lib64 /usr/lib -name "$BASENAME" 2>/dev/null | head -1)
if [ -n "$SYSTEM_LIB" ]; then
CHROOT_DATE=$(stat -c %Y "$lib")
SYSTEM_DATE=$(stat -c %Y "$SYSTEM_LIB")
if [ "$CHROOT_DATE" -lt "$SYSTEM_DATE" ]; then
echo "ESKI: $lib (sistem versiyonu daha yeni)"
fi
fi
done
echo ""
echo "Aktif chroot baglantilari:"
ls /proc/*/root 2>/dev/null | while read link; do
TARGET=$(readlink "$link" 2>/dev/null)
if [ "$TARGET" = "$CHROOT_DIR" ]; then
PID=$(echo "$link" | grep -o '[0-9]*')
echo "PID $PID chroot icinde"
fi
done
echo "=== Kontrol tamamlandi ==="
Sonuç
chroot, doğru kullanıldığında kullanıcı izolasyonu için hala en pratik ve etkili araçlardan biri. Özellikle SFTP tabanlı dosya erişimi kısıtlamalarında neredeyse standart bir yöntem haline geldi. Yapılandırması görece basit, overhead’i minimal ve neredeyse her Linux dağıtımında native olarak destekleniyor.
Ancak her araç gibi chroot da görevinin sınırlarını biliyor. Güvenlik açısından kritik senaryolarda chroot’u tek başına kullanmak yerine SELinux, AppArmor veya container teknolojileriyle desteklemenizi tavsiye ederim. chroot bir kapı kilidi gibidir; doğru kapıyı kilitler ama pencerelerden giren birini durduramaz.
Bu yazıdaki örnekleri production’a taşımadan önce mutlaka test ortamında deneyin. Özellikle sshd_config değişikliklerinden önce mevcut bir terminal oturumunu açık bırakın ki yapılandırma hatası durumunda sisteme erişiminizi kaybetmeyesiniz. Bir kez “kendimi dışarıda bıraktım” deneyimi yaşamış her sysadmin bu tavsiyenin ne kadar değerli olduğunu çok iyi bilir.