Linux servislerini root yetkisi olmadan çalıştırma
Servisleri root olarak çalıştırmak tam sistem erişimi riski doğurur. DynamicUser veya özel hesaplar kullanarak sistem güvenliğini en az yetki prensibi ile nasıl artıracağınızı öğrenin.
Neden her şeyi root olarak çalıştırmamalıyım
root kullanıcısı makine üzerinde her şeyi yapabilir: tüm dosyaları okuyabilir, her türlü ayarı değiştirebilir ve tüm sistemi silebilir. Bir servisi root olarak çalıştırdığınızda, bu yetkilerin tamamını ilgili servise devretmiş olursunuz. Serviste bir saldırganın istismar edebileceği bir hata varsa, saldırgan sadece servisi değil, root yetkilerini de ele geçirir; root ise tüm sunucu demektir. Servisi yetkisiz bir kullanıcı ile çalıştırmak, oluşabilecek zararı sınırlar. Kısıtlı bir hesapla çalışan servisteki bir hata, saldırgana yalnızca o hesabın erişebildiği alanları verir ki bu da neredeyse hiçbir şey olmalıdır.
Bu, en az yetki prensibidir: sistemin her bir parçasına işini yapması için gereken erişimi tam olarak verin, fazlasını değil. Bu, bir ihlalin etki alanını sınırlamak için uygulanan en etkili alışkanlıktır ve modern bir sunucuda bunu uygulamak size neredeyse hiçbir maliyet getirmez.
Her servis için özel bir hesap
Klasik yaklaşım, her servis için yalnızca o servisin dosyalarına sahip olan ve sisteme giriş yapamayan ayrı bir sistem kullanıcısı oluşturmaktır. Bir web uygulaması için sistem hesabı şu şekilde görünebilir:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvcHer bayrak önemlidir. --system, hesabı insan girişi için değil, bir servis hesabı olarak yapılandırır. --no-create-home, ihtiyaç duyulmayan bir ev dizini oluşturulmasını engeller. --shell /usr/sbin/nologin, bir saldırganın hesabı ele geçirmesi durumunda bile kabuk (shell) açmasını imkansız kılar. Hesap, yalnızca bir sürece ve ilgili dosyalara sahip olmak için var olur.
Ardından, bu kullanıcıya yalnızca ihtiyaç duyduğu dosyalar üzerinde yetki verin ve fazlasından kaçının:
sudo chown -R appsvc:appsvc /opt/myappArtık servis, yalnızca kendi dizinini okuyup yazabilir ve disk üzerinde başka hiçbir yere erişemez. Servis bir gün istismar edilirse, saldırganın değiştirebileceği dosyalar /opt/myapp ile sınırlı kalır; hesap herkesin okuyabileceği dosyaları okumaya devam edebilir ancak sistemin geri kalanını değiştiremez.
Servisi ilgili kullanıcı ile çalıştırması için systemd'yi yapılandırma
Hesap oluşturulduktan sonra, servisi bu hesapla çalıştırması için systemd'ye talimat verin. Unit dosyasında bu işlem tek bir satırla yapılır:
[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvcUser=appsvc ifadesi, sürecin root yerine ilgili hesabın kısıtlı yetkileriyle başlatılmasını sağlar. Bu, systemd altında bir uygulamayı çalıştırmanın standart ve güvenli yoludur; unit dosyası yazdığınız her servis için uygulanmalıdır. Ancak systemd yanlış süreci izliyorsa yetki kısıtlama (dropping privileges) işe yaramayacaktır. Bu nedenle, daemon sessizce kapandığı halde unit hala aktif görünüyorsa, sürecinizin başlama biçimine uygun Type= değerini seçtiğinizden emin olun.
DynamicUser ile kullanıcı hesabını tamamen atlayın
systemd bir adım daha ileri giderek, yalnızca servis çalışırken var olan geçici bir kullanıcı oluşturabilir. DynamicUser=yes ayarını yapılandırdığınızda, herhangi bir kullanıcı hesabını yönetmeniz gerekmez:
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myappBaşlangıçta systemd kullanılmayan bir kullanıcı kimliği atar; durdurulduğunda ise bu kimliği serbest bırakır. Servis ayrıca özel bir /tmp alanına, dosya sisteminin büyük bölümünün salt okunur bir görünümüne ve StateDirectory= tarafından oluşturulup servise teslim edilen /var/lib/myapp altında yazılabilir bir durum dizinine sahip olur. Ayrıcalıkların düşürülmesinin her servisin kendi başlatma betiğinin insafına bırakıldığı SysV init altında böyle bir şey mümkün değildi; bu eksiklik, dağıtımların neden ilk etapta systemd'ye geçtiğinin büyük bir kısmını oluşturmaktadır. Yalnızca kendi durum dizinine ihtiyaç duyan bağımsız bir servis için DynamicUser=yes, güçlü bir izolasyon sağlamanın en zahmetsiz yoludur çünkü bir saldırganın hedef alabileceği uzun ömürlü bir hesap bulunmaz.
Unit dosyalarını elle yazmak zahmetlidir ve güvenlik sıkılaştırma yönergelerini doğru ayarlamak işin en değerli kısmıdır. systemd servis ve zamanlayıcı kılavuzundaki oluşturucu, bu seçenekleri sizin yerinize doldurarak unit dosyasının ilk seferde doğru olmasını sağlar.
Bunun genel yapı içindeki yeri
En az yetki ilkesi tek bir katmandır ve diğerlerinin yerini almak yerine onlarla birlikte çalışır. Bir varsayılan olarak reddeden güvenlik duvarı, servise neyin ulaşabileceğini denetler; servisin yetkisiz bir kullanıcı olarak çalıştırılması, bir ihlal durumunda servisin neler yapabileceğini sınırlar ve sıkılaştırılmış SSH, saldırganları en başta sunucudan uzak tutar. Bunların hiçbiri tek başına yeterli değildir; ancak birlikte uygulandıklarında, bir servisteki hata tüm sunucunun ele geçirilmesine yol açmaz. Gizli verileri koruyan bir uygulama barındırmak, bu katmanların nerede bittiğini gösterir: kısıtlı bir hesap, ihlal edilmiş bir sürecin erişebileceklerini sınırlar; ancak Vaultwarden gibi kendi kendine barındırılan bir parola yöneticisi, yönetici anahtarını ve yedekleme dosyasını nasıl koruduğunuza bağlı olarak güvende kalır veya tehlikeye düşer; kullanıcı izolasyonu bu iki unsuru kapsamaz.
Devam etmeden önce, tüm sunucu için bir sıkılaştırma kontrol listesini gözden geçirin ve üzerinde çalışmak üzere kişiselleştirilmiş bir kopya oluşturun:
FAQ
Bir servisi neden root kullanıcısı ile çalıştırmamalıyım?
root kullanıcısı makine üzerinde her türlü işlemi yapabildiği için, root yetkileriyle çalışan ve istismar edilen bir servis, saldırgana sadece servisi değil tüm sunucuyu teslim eder. Servisi kısıtlı ve yetkisiz bir hesapla çalıştırmak, oluşabilecek zararı yalnızca o hesabın erişebildiği alanlarla sınırlar. root hesabını yalnızca yönetim işlemleri için ayırın ve sürekli çalışan her servisi kısıtlı bir kullanıcı ile çalıştırın.
Giriş yapamayan bir kullanıcıyı nasıl oluştururum?
sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME komutunu çalıştırın. nologin kabuğu, kimlik bilgileri çalınsa dahi hesabın etkileşimli bir oturum açmasını engeller; --system bu hesabı bir servis hesabı olarak işaretler ve --no-create-home ihtiyaç duyulmayan bir ev dizininin oluşturulmasını atlar. chown komutu ile yalnızca ilgili dosyaların sahipliğini bu kullanıcıya verin.
systemd DynamicUser nedir?
DynamicUser=yes, systemd'ye servis için yalnızca çalıştığı süre boyunca var olan geçici bir kullanıcı oluşturmasını söyler; böylece kalıcı bir hesap yönetmek zorunda kalmazsınız. Bu özellik ayrıca servise özel bir /tmp, büyük oranda salt okunur bir dosya sistemi görünümü ve yönetilen bir durum dizini sağlar. Kendi kendine yeten bir servisi, tek kullanımlık ve düşük yetkili bir kimlikle çalıştırmanın en zahmetsiz yoludur.
root olmayan bir kullanıcı ile çalıştırmak güvenlik duvarının yerini tutar mı?
Hayır. İkisi farklı şeyleri korur. Yetkisiz bir kullanıcı ile çalıştırmak, bir ihlal durumunda servisin yapabileceklerini sınırlar; güvenlik duvarı ise servise neyin ulaşabileceğini kısıtlar. Her katmanın diğerinin kapsayamadığı alanları koruması için, güçlendirilmiş SSH ile birlikte her ikisini de kullanın.
Servis kullanıcısı hangi dosyaların sahibi olmalıdır?
Yalnızca servisin gerçekten ihtiyaç duyduğu dosyaların; fazlasına gerek yoktur. Hesaba sadece kendi çalışma dizininin ve verilerinin sahipliğini verin, diğer her şeyin sahibi root olarak kalsın. Uygulama dizini için sudo chown -R svc-app:svc-app /opt/svc-app, /etc altındaki yapılandırma dosyaları için ise root sahipliğinde kalıp yalnızca servis tarafından okunabilir olması iyi bir yöntemdir. Amaç, süreç bir gün ele geçirilirse, değiştirilebilecek dosyaların sistemin geri kalanıyla değil, yalnızca kendi verileriyle sınırlı kalmasını sağlamaktır.