chroot ile Kullanıcıyı Dizine Hapsetme

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.

Yorum yapın