Yazılara geri dön
Yazı

systemd-nspawn ve seccomp ile Güvensiz Komutları Test Etme

systemd-nspawn ve özel seccomp profilleri kullanarak güvenilmeyen betikleri izole ortamda güvenli şekilde çalıştırın. Linux komut satırı sandboxing rehberi.

Linuxsystemdseccompsandboxingsystemd-nspawn

Sistemde tam güvenmediğim betikleri test veya hata ayıklamam gerektiği sık olur — belki bir kamusal repodan, bir同事的 gist'inden veya sorun giderme sırasında bulduğum bir şeyden. Üretim ortamında ya da hatta iş istasyonunda doğrudan çalıştırmak riskli. İşte burada systemd-nspawn ve seccomp profillerinin birleşimi işe yarar. Bu, işlemin yapabileceği sistem çağrılarını kısıtlayarak güvenilmeyen kodu sanal makine başlatmadan etkili bir şekilde sandbox'lemeyi sağlayan hafif, izole bir ortam oluşturmama olanak tanır.

systemd-nspawn ile Sandboxing Neden Kullanılır

systemd-nspawn, konteynerler veya sanal makineler kıyasla hafiftir. Mevcut çekirdek isim alanlarını kullanır ancak sistemd yöneticisi üzerinden sıkı kontrol sağlar. Minimal overhead ile izole bir dosya sisteminde bir kabuk çalıştırabilir veya komut çalıştırabilirim. Seccomp (güvenli işlem modu) filtresiyle birleştirildiğinde, ptrace, mount veya fork/clone kombinasyonu gibi ayrıcalık yükseltmesi veya konteyner kaçışı yol açabilecek tehlikeli sistem çağrılarını engelleyebilirim.

İş akışımda, /var/lib/container/ altında minimal bir Debian veya Ubuntu temel imajı tutar ve bu imajı geçici test ortamları için kök dosya sistemi olarak kullanırım. Böylece ana sistemimi kirletmez ve sadece dizini silerek her şeyi sıfırlayabilirim.

Temel İmagin Oluşturulması

Öncelikle minimal bir dosya sistemi oluştururum. Debian tabanlı sistemler için debootstrap kullanırım:

sudo debootstrap --arch=amd64 bookworm /var/lib/container/testbox http://deb.debian.org/debian

Tamamlandıktan sonra, kök şifresini ayarlamak veya bir kullanıcı eklemek için chroot'a girebilirim:

sudo chroot /var/lib/container/testbox
passwd
adduser testuser
exit

Artık önyüklenebilir-ish bir dizin ağacım var. Bir kabuk ve temel komutları çalıştırmak için tam bir init sistemine ihtiyacım yok.

Özel seccomp Profili Oluşturma

seccomp, çekirdek seviyesinde sistem çağrılarını filtreler. JSON formatında bir politika tanımlarım ve bu política izin verilen, engellenen veya bir hata tetikleyen çağrıları belirtirim. Güvenilmeyen betikleri test ederken, strict bir varsayılanla başlarım: her şeyi engellerim, ardından sadece gerekenleri izne veririm.

Basit Bash veya Python betiklerini çalıştırmak için kullandığım minimal profil şu şekildedir:

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "archMap": [
    {"architecture": "SCMP_ARCH_X86_64", "subArchitectures": ["SCMP_ARCH_X86", "SCMP_ARCH_X32"]}
  ],
  "syscalls": [
    {"name": "read", "action": "SCMP_ACT_ALLOW"},
    {"name": "write", "action": "SCMP_ACT_ALLOW"},
    {"name": "openat", "action": "SCMP_ACT_ALLOW"},
    {"name": "close", "action": "SCMP_ACT_ALLOW"},
    {"name": "fstat", "action": "SCMP_ACT_ALLOW"},
    {"name": "mmap", "action": "SCMP_ACT_ALLOW"},
    {"name": "mprotect", "action": "SCMP_ACT_ALLOW"},
    {"name": "munmap", "action": "SCMP_ACT_ALLOW"},
    {"name": "brk", "action": "SCMP_ACT_ALLOW"},
    {"name": "exit", "action": "SCMP_ACT_ALLOW"},
    {"name": "exit_group", "action": "SCMP_ACT_ALLOW"},
    {"name": "rt_sigaction", "action": "SCMP_ACT_ALLOW"},
    {"name": "rt_sigprocmask", "action": "SCMP_ACT_ALLOW"},
    {"name": "ioctl", "action": "SCMP_ACT_ALLOW"},
    {"name": "getdents64", "action": "SCMP_ACT_ALLOW"},
    {"name": "getrandom", "action": "SCMP_ACT_ALLOW"}
  ]
}

Bu profili /etc/systemd/nspawn/seccomp-lockdown.json olarak kaydederim. defaultActionnin errno olarak ayarlanması, açıkça izin verilen olmayan tüm sistem çağrılarının bir hata (genellikle EPERM) döndürmesini ve süreçte güvenli olmayan bir şey yapmaya çalıştığında sonlanmasını sağlar.

Sandbox'ı Başlatma

Şimdi seccomp filtresi uygulanmış bir ad alanı içinde komut çalıştırabilirim:

sudo systemd-nspawn \
  --directory=/var/lib/container/testbox \
  --bind=/home/furkan/test-scripts:/mnt/tests \
  --seccomp-policy=/etc/systemd/nspawn/seccomp-lockdown.json \
  /usr/bin/bash

Bu komut, test betiklerimi /mnt/tests'te bağlayarak konteyner içinde bir kabuk açar. --bind baydı varsayılan olarak okuma-yazma olur; ancak sadece betikleri okumam gerekiyorsa genellikle --bind-ro kullanırım.

Tek bir betik çalıştırmak ve çıkış yapmak istersem şöyle yaparım:

sudo systemd-nspawn \
  --directory=/var/lib/container/testbox \
  --bind-ro=/home/furkan/test-scripts/script.sh:/mnt/script.sh \
  --seccomp-policy=/etc/systemd/nspawn/seccomp-lockdown.json \
  /bin/bash /mnt/script.sh

Bu Profil Ne Engeller (Ve Ne Engellemez)

Bu profil ile yaygın kaçış vektörleri engellenir:

  • ptrace — diğer süreçlere hata ayıklama yapma veya bağnma işlemini önler
  • CLONE_NEWNS veya CLONE_NEWUSER ile clone — isim alanı oluşturmayı durdurur
  • mount, umount2 — dosya sistemi müdahalesini engeller
  • kexec_load, init_module — çekirdek kodu yüklemeyi önler
  • openat ile tehlikeli yollar (yol filtrelemesiyle birlikteyse, seccomp tek başına yol filtrelemesi yapmaz)

Ancak seccomp varsayılan olarak bağımsız değişkenleri filtrelemez (yeni SCMP_CMP kurallarıyla hariç). Örneğin, openat sadece /tmp için izin vermek gibi bir şey yapamam. Daha sıkı kontrol için bu profili isim alanları, kullanıcı isim alanları veya Firejail gibi bir container çalışma zamanıyla birleştiririm. Ancak sadece dosyaları okumak, hesaplama yapmak ve çıktı yazmak gereken betikler için hızlı testte bu yeterli olur.

Pratik İpuçları ve Gotchas

  • Seccomp profilinizi önce güvenli bilinen bir programla test edin. strace -f kullanarak yaptığı sistem çağrılarını görün ve profili ona göre ayarlayın.
  • Bir betik hemen "Operation not permitted" ile başarısız olursa, seccomp denetim mesajları için /var/log/syslog veya journalctla bakın (denetim etkinse).
  • execve izni vermek gerekmedikçe izin vermeyin — bu, ikili zincirleme kapısını açar. İzin vermek zorundaysanız, bağ mounts ve execve bağımsız değişkeni filtrelemesi üzerinden spesifik çalıştırılabilir dosyaları izin listesine alın (daha yeni çekirdeklerde mevcut).
  • Temizliği unutmayın: testten sonra konteyner dizinini siler veya yeniden kullanım için bir anlık görüntü alırım.

Daha Fazla İzolasyon Gerektiğinde Ne Yapmalıyım

Daha derin izolasyon gerekiyorsa — ağ erişimi kontrolü, kullanıcı ID eşleme veya çok katmanlı savunma — Firejail veya Podman/Docker ile tam OCI konteyneri kullanırım. Ancak hızlı ve minimum kurulum gerektiren ad hoc komut satırı testleri için systemd-nspawn ve seccomp benim başıma gelen çözümür.

[systemd Slice kaynak izolasyonu](https://furkanikkan.com/urun/systemd-slice-ile-bellek-io-sinirlari-kaynak-izolasyon-kilavuzu-112) hakkında önceki yazımda da belirttiğim gibi, burada da aynı prensipler geçerli: tehdit modeline uygun doğru aracı kullanın. Burada seccomp performansla ilgili değil, güvensiz kod için saldırı yüzeyini sıfıra yakın levelsine indirmekle ilgilidir.

Düzenli olarak üçüncü taraf betiklerle çalışıyorsanız, bu yaklaşım sisteminizi tehlikeye atmadan onları test etmek için tekrarlanabilir, denetlenebilir bir yol sağlar. Doğru kod incelemesi veya CI'de sandboxing'in yerini tutmaz, ama ops katmanındaki güvenli bir ağdır olarak iş görür.


Kapak görseli: Unknown · CC0 (Openverse / kamu malı) · https://www.rawpixel.com/image/5904551/photo-image-background-public-domain-technology