Servis Hesabı Oluşturma: Shell’siz Sistem Kullanıcısı

Bir Linux sunucusunda uygulama deploy ettiğinizde, o uygulamanın hangi kullanıcı kimliğiyle çalışacağı sorusu aklınıza geldi mi hiç? “Root ile çalıştırsak ne olur?” diye düşünebilirsiniz, ama bu yaklaşım hem güvenlik açısından hem de best practice açısından tam bir felaket tarifi. İşte tam bu noktada servis hesapları devreye giriyor. Bu yazıda, shell’siz sistem kullanıcısı oluşturmanın neden önemli olduğunu, nasıl yapıldığını ve gerçek dünya senaryolarında nasıl kullanıldığını detaylıca ele alacağız.

Servis Hesabı Nedir, Neden Gereklidir?

Linux sistemlerde kullanıcılar iki temel kategoriye ayrılır: gerçek insanlar için oluşturulan normal kullanıcılar ve servisler, daemon’lar ve uygulamalar için oluşturulan sistem kullanıcıları. Servis hesapları bu ikinci kategoriye girer.

Bir web sunucusu düşünün. Nginx veya Apache, sisteminizde belirli dosyalara okuma, belirli portlara bağlanma ve log dosyalarına yazma erişimine ihtiyaç duyar. Ama bu sürecin /etc/shadow dosyasını okumasına, SSH ile bağlanmasına veya başka dizinlere erişmesine gerek yok. İşte servis hesabının temel mantığı bu: en az yetki prensibi (principle of least privilege).

Servis hesaplarının sağladığı avantajlar şunlardır:

  • İzolasyon: Bir servis ele geçirilse bile saldırgan sınırlı yetkilerle sıkışıp kalır
  • Denetlenebilirlik: Hangi servisin hangi dosyaya eriştiğini auditd gibi araçlarla takip edebilirsiniz
  • Temiz log yönetimi: Her servis kendi kullanıcısıyla çalışınca logları ayırt etmek kolaylaşır
  • Güvenlik politikası uyumu: PCI-DSS, ISO 27001 gibi standartlar bu tür ayrımı zorunlu kılar

Shell’siz Kullanıcı Kavramı

Normal bir kullanıcı sisteme login olduğunda bash, zsh veya başka bir shell çalışır. Servis hesapları için bu duruma gerek yok, dahası bu durum güvenlik riski oluşturur. Shell’siz kullanıcı oluşturduğunuzda, o kullanıcı adına sisteme interaktif olarak giriş yapılamaz.

Linux’ta bu amaçla iki özel shell kullanılır:

  • /bin/false: Kullanıcı login denemesinde komut çalıştırmadan oturumu kapatır, false (1) dönüş kodu üretir
  • /bin/nologin veya /usr/sbin/nologin: Login girişiminde “This account is currently not available” mesajı gösterir ve oturumu kapatır

İkisi arasındaki pratik fark: nologin daha açıklayıcı bir mesaj verir ve özellikle SSH brute-force saldırılarında saldırgana “bu hesap çalışmıyor” mesajı iletir. Çoğu durumda nologin tercih edilir.

useradd ile Temel Servis Hesabı Oluşturma

En yaygın yöntem useradd komutunu kullanmaktır. Temel sözdizimi şöyle:

# En basit servis hesabı oluşturma
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp

# Kısa parametrelerle aynı işlem
sudo useradd -r -M -s /usr/sbin/nologin myapp

Kullanılan parametrelerin açıklaması:

  • –system (-r): Kullanıcıyı sistem kullanıcısı olarak işaretler, UID’yi 1-999 arasından atar (dağıtıma göre değişir)
  • –no-create-home (-M): Home dizini oluşturmaz
  • –shell (-s): Kullanıcının shell’ini belirtir, biz nologin atıyoruz

Oluşturulan kullanıcıyı doğrulamak için:

# Kullanıcı bilgilerini kontrol et
id myapp
grep myapp /etc/passwd

# Beklenen çıktı örneği:
# myapp:x:995:995::/home/myapp:/usr/sbin/nologin

Gerçek Dünya Senaryosu 1: Uygulama Servisi için Hesap

Diyelim ki bir Java Spring Boot uygulamasını sisteme deploy ediyorsunuz. Uygulamanın /opt/myapp dizininde çalışması ve /var/log/myapp dizinine log yazması gerekiyor.

# 1. Önce grubu oluştur
sudo groupadd --system myapp

# 2. Kullanıcıyı oluştur ve gruba ata
sudo useradd 
  --system 
  --no-create-home 
  --shell /usr/sbin/nologin 
  --gid myapp 
  --comment "MyApp Service Account" 
  myapp

# 3. Uygulama dizinini oluştur ve sahipliği ata
sudo mkdir -p /opt/myapp
sudo chown myapp:myapp /opt/myapp
sudo chmod 750 /opt/myapp

# 4. Log dizinini oluştur
sudo mkdir -p /var/log/myapp
sudo chown myapp:myapp /var/log/myapp
sudo chmod 755 /var/log/myapp

Bu noktada systemd servis dosyasında bu kullanıcıyı nasıl kullanacağınıza bakalım:

# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Spring Boot Application
After=network.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/java -jar /opt/myapp/myapp.jar
Restart=on-failure
RestartSec=10

# Güvenlik kısıtlamaları
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/log/myapp

[Install]
WantedBy=multi-user.target
# Servisi etkinleştir ve başlat
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp

# Servisin hangi kullanıcıyla çalıştığını doğrula
ps aux | grep myapp

Gerçek Dünya Senaryosu 2: Veritabanı Yedekleme Servisi

Bir veritabanı yedekleme scripti için servis hesabı oluşturuyorsunuz. Bu hesabın veritabanı credential dosyasını okuyabilmesi ama başka hiçbir şeye erişememesi gerekiyor.

# Yedekleme servisi için hesap oluştur
sudo useradd 
  --system 
  --no-create-home 
  --shell /usr/sbin/nologin 
  --comment "Database Backup Service" 
  dbbackup

# Yedekleme dizinini hazırla
sudo mkdir -p /var/backups/database
sudo chown dbbackup:dbbackup /var/backups/database
sudo chmod 700 /var/backups/database

# Credential dosyasını oluştur ve kısıtla
sudo touch /etc/dbbackup.conf
sudo chown root:dbbackup /etc/dbbackup.conf
sudo chmod 640 /etc/dbbackup.conf

# Credential dosyasını doldur (örnek)
sudo bash -c 'cat > /etc/dbbackup.conf << EOF
DB_HOST=localhost
DB_PORT=5432
DB_USER=backup_user
DB_PASS=supersecretpassword
DB_NAME=production
EOF'

Bu yaklaşımla dbbackup kullanıcısı credential dosyasını okuyabilir ama başka kullanıcılar (root hariç) okuyamaz.

adduser ile Servis Hesabı (Debian/Ubuntu)

Debian tabanlı sistemlerde adduser komutu daha interaktif ve kullanıcı dostudur. --system parametresiyle servis hesabı oluşturabilirsiniz:

# Debian/Ubuntu'da servis hesabı oluşturma
sudo adduser 
  --system 
  --no-create-home 
  --disabled-password 
  --disabled-login 
  --group 
  --gecos "Monitoring Service" 
  monitoring

# Hesabı doğrula
getent passwd monitoring
getent group monitoring

adduser --system komutu otomatik olarak:

  • UID’yi SYS_UID_MIN ve SYS_UID_MAX aralığında atar (genellikle 100-999)
  • /bin/false shell’i atar
  • Aynı isimde grup oluşturur (–group ile)

Mevcut Kullanıcıyı Servis Hesabına Dönüştürme

Bazen yanlışlıkla normal kullanıcı olarak oluşturulan bir hesabı servis hesabına dönüştürmeniz gerekebilir. Bu durumda usermod komutunu kullanabilirsiniz:

# Mevcut kullanıcının shell'ini değiştir
sudo usermod --shell /usr/sbin/nologin existinguser

# Şifreyi devre dışı bırak (kilitle)
sudo passwd --lock existinguser

# Hesabın expire edilmesi (login'i tamamen engeller)
sudo usermod --expiredate 1 existinguser

# Değişiklikleri doğrula
grep existinguser /etc/passwd
passwd --status existinguser

/etc/passwd Satırının Anatomisi

Oluşturduğunuz servis hesabını /etc/passwd dosyasında görmek, ne yaptığınızı anlamanızı kolaylaştırır:

# Dosyayı incele
grep myapp /etc/passwd
# Örnek çıktı:
# myapp:x:995:995:MyApp Service Account:/home/myapp:/usr/sbin/nologin

Bu satırdaki her alan sırasıyla şu anlama gelir:

  • myapp: Kullanıcı adı
  • x: Şifre alanı (gerçek şifre /etc/shadow’da, x placeholder)
  • 995: UID (User ID)
  • 995: GID (Group ID)
  • MyApp Service Account: GECOS alanı, açıklama
  • /home/myapp: Home dizini (servis hesaplarında genellikle /nonexistent veya boş)
  • /usr/sbin/nologin: Login shell

Sistem UID’leri için dağıtıma göre sınırlar değişir. Ubuntu’da /etc/adduser.conf dosyasında SYS_UID_MIN=100 ve SYS_UID_MAX=999 şeklinde tanımlıdır. CentOS/RHEL’de bu değerler /etc/login.defs dosyasından gelir.

Güvenlik Sertleştirme: PAM ve Hesap Kilitleme

Servis hesabı oluşturduktan sonra ekstra güvenlik adımları atabilirsiniz:

# Şifreyi tamamen kaldır (! ile kilitli durum)
sudo passwd --delete myapp
sudo passwd --lock myapp

# Durumu kontrol et
sudo passwd --status myapp
# Çıktı: myapp L 01/15/2024 0 99999 7 -1 (L = Locked)

# Hesabın login olamamasını /etc/security/access.conf ile de sağlayabilirsiniz
echo "-:myapp:ALL" | sudo tee -a /etc/security/access.conf

PAM konfigürasyonuyla ileri seviye kısıtlamalar için /etc/security/limits.conf dosyasına ekleme yapabilirsiniz:

sudo bash -c 'cat >> /etc/security/limits.conf << EOF
# myapp servis hesabı kısıtlamaları
myapp soft nofile 65536
myapp hard nofile 65536
myapp soft nproc 4096
myapp hard nproc 4096
EOF'

Gerçek Dünya Senaryosu 3: Nginx için Özel Servis Hesabı

Nginx normalde kendi www-data veya nginx kullanıcısını kullanır ama bazı durumlarda özelleştirilmiş bir kullanıcı hesabı gerekebilir. İşte birden fazla web uygulamasını izole etmek için örnek bir yaklaşım:

# Her uygulama için ayrı kullanıcı oluştur
for app in webapp1 webapp2 webapp3; do
    sudo groupadd --system $app
    sudo useradd 
        --system 
        --no-create-home 
        --shell /usr/sbin/nologin 
        --gid $app 
        --comment "${app} web service" 
        $app
    
    # Web dizinini oluştur
    sudo mkdir -p /var/www/$app
    sudo chown $app:$app /var/www/$app
    sudo chmod 755 /var/www/$app
    
    echo "Kullanıcı $app oluşturuldu: $(id $app)"
done

# Tüm web uygulama kullanıcılarını listele
grep -E "webapp[0-9]" /etc/passwd

Servis Hesabını Silme ve Temizlik

Bir servis artık kullanılmıyorsa, hesabı ve ilgili kaynakları temizlemek önemlidir:

# Önce servis çalışıyorsa durdur
sudo systemctl stop myapp
sudo systemctl disable myapp

# Kullanıcıya ait çalışan prosesleri kontrol et
ps aux | grep myapp

# Kullanıcıyı sil (home dizini yoksa -r parametresi sorun çıkarmaz)
sudo userdel myapp

# Grubu sil
sudo groupdel myapp

# Kalan dosyaları temizle
sudo find / -user myapp -o -group myapp 2>/dev/null
sudo rm -rf /opt/myapp /var/log/myapp

# Servis dosyasını sil
sudo rm /etc/systemd/system/myapp.service
sudo systemctl daemon-reload

Servis Hesaplarını Listeleme ve Denetleme

Sisteminizdeki tüm servis hesaplarını düzenli olarak denetlemek iyi bir alışkanlıktır:

# Sistem kullanıcılarını listele (UID < 1000)
awk -F: '$3 < 1000 {print $1, $3, $7}' /etc/passwd

# Shell'siz kullanıcıları bul
awk -F: '$7 ~ /nologin|false/ {print $1, $3, $7}' /etc/passwd

# Login shell'i olan kullanıcıları bul (bunlar gerçek login hesapları)
awk -F: '$7 !~ /nologin|false/ {print $1, $3, $7}' /etc/passwd

# Kullanıcıya ait dosyaları bul
sudo find /opt /var /etc -maxdepth 3 -user myapp 2>/dev/null

Ansible ile Servis Hesabı Otomasyonu

Birden fazla sunucuyu yönetiyorsanız, servis hesaplarını elle oluşturmak yerine Ansible ile otomatize edebilirsiniz:

# roles/service_accounts/tasks/main.yml
---
- name: Servis grubu oluştur
  ansible.builtin.group:
    name: "{{ item.name }}"
    system: true
    state: present
  loop: "{{ service_accounts }}"

- name: Servis kullanıcısı oluştur
  ansible.builtin.user:
    name: "{{ item.name }}"
    group: "{{ item.name }}"
    system: true
    shell: /usr/sbin/nologin
    create_home: false
    comment: "{{ item.comment }}"
    state: present
  loop: "{{ service_accounts }}"

- name: Uygulama dizinlerini oluştur
  ansible.builtin.file:
    path: "{{ item.app_dir }}"
    state: directory
    owner: "{{ item.name }}"
    group: "{{ item.name }}"
    mode: "0750"
  loop: "{{ service_accounts }}"
  when: item.app_dir is defined

Bu Ansible rolünü vars dosyanızda şöyle tanımlayabilirsiniz:

# vars/service_accounts.yml
service_accounts:
  - name: myapp
    comment: "MyApp Service Account"
    app_dir: /opt/myapp
  - name: monitoring
    comment: "Monitoring Agent"
    app_dir: /opt/monitoring
  - name: dbbackup
    comment: "Database Backup Service"

Sık Yapılan Hatalar

Servis hesabı oluştururken karşılaşılan yaygın hatalar ve çözümleri:

  • Home dizini oluşturmayı unutmak: Bazı uygulamalar home dizinine ihtiyaç duyar. Bu durumda --create-home ile bir dizin belirtin veya WorkingDirectory ile systemd’de çalışma dizini tanımlayın
  • Root ile çalıştırmak: “Geçici olarak root ile çalıştıralım” yaklaşımı genellikle kalıcı hale gelir. Bu alışkanlıktan kesinlikle kaçının
  • Çok geniş izin vermek: chmod 777 kestirmeciliği servis hesaplarını anlamsız kılar
  • Hesabı sisteme bağlı tutmak: Uygulama kaldırıldığında servis hesabını da silmeyi unutmayın
  • Shell kontrolü yapmamak: usermod ile shell değiştirdiğinizde /etc/passwd dosyasını kontrol etmeyi ihmal etmeyin

Sonuç

Servis hesapları, Linux güvenlik mimarisinin temel taşlarından biridir. “Sadece bir test ortamı” veya “geçici olarak root ile çalıştırırım” gibi düşünceler zamanla ciddi güvenlik açıklarına dönüşür. Shell’siz sistem kullanıcısı oluşturmak beş dakikalık bir işlemdir ama sağladığı güvenlik katmanı son derece değerlidir.

Özetlemek gerekirse: her servis kendi izole kullanıcısıyla çalışmalı, bu kullanıcıların sadece ihtiyaç duydukları kaynaklara erişimi olmalı ve login shell’leri mutlaka nologin veya false olarak ayarlanmalıdır. Ansible gibi konfigürasyon yönetim araçlarıyla bu süreçleri otomatize etmek, on sunucuyu yönetirken de yüz sunucuyu yönetirken de tutarlılığı sağlar.

Systemd servis dosyalarında User= ve Group= direktiflerini, NoNewPrivileges=true ve PrivateTmp=true gibi güvenlik seçenekleriyle birlikte kullanmak ise bu izolasyonu işletim sistemi seviyesinde de destekler. Servis hesapları konusunu bir alışkanlık haline getirdiğinizde, güvenlik açısından çok daha savunulabilir bir sistem mimarisi kurmuş olursunuz.

Yorum yapın