Yazılara geri dön
Yazı

systemd-nspawn ve seccomp ile Tehlikeli Komutları İzolasyon Altına Alma

systemd-nspawn ile özel seccomp profili kullanarak riskli sistem çağrılarını engelleyin ve güvenilmeyen komutları minimal bir konteynerde güvenli şekilde test edin.

Linuxsystemd-nspawnseccompcontainer securitysandboxing

Güvenilmeyen bir şey çalıştırmam gerektiğinde — internetten bir komut dosyası, kontrol edilmemiş bir kaynaktan gelen ikili dosya veya laboratuvarda bir öğrenci ödevi — bu şeyin ana sistemime dokunmasını istemiyorum. Tam sanal makineler ağır olur; sadece süreç izolasyonu ihtiyacım varsa Docker aşırı olabilir. İşte burada systemd-nspawn parlar. Hafif, systemd içinde yer alır ve neredeyse hiç overhead olmadan bir konteyner çalıştırmanıza olanak tanır. Dar bir seccomp profiliyle birleştirildiğinde, ptrace, mount veya ham I/O gibi tehlikeli sistem çağrılarını engelleyebilir ve süreci etkili bir şekilde sandbox’leyebilirsiniz.

Bu deseni AUR’dan paketleri test ederken veya derleme betiklerini değerlendirirken sık sık kullanıyorum. Tek kullanımlık bir sanal makineye atmak yerine, debootstrap ile minimal bir Debian veya Ubuntu konteyneri oluştururum, seccomp filtresi uygularım ve komutu içünde çalıştırırım. Eğer kötü bir şey yapmaya çalışırsa, çekirdek onu hemen öldürür — ana sisteme zarar vermez.

İlk olarak minimal bir konteyner oluşturmalıyım. Küçük ayak izi için Debian’ı tercih ederim:

# debootstrap --variant=minbase stable /var/lib/container/test http://deb.debian.org/debian

Bu komut yaklaşık 100 MB’lık bir temelsiz sistem verir. Fazla hizmet yok, sadece bir kabuk ve temel araçlar. Daha sonra şu komutla ona girebilirim:

# systemd-nspawn -D /var/lib/container/test

Artık konteyner içinde root olarak çalışıyorum. Ancak konteyner içinde root hâlâ root demektir — konteyner tehlikeli sistem çağrısına sahipse, yine de zarar verebilir. İşte burada seccomp devreye girer.

seccomp (güvenli işlem modu), bir sürecin hangi sistem çağrılarını yapabileceğini filtrelemeye izin verir. Sadece gerekenlere izin veren ve diğer her şeyi engelleyen bir profil tanımlayabilirim. Genellikle varsayılan olarak tüm çağrıları reddetmeye başlarım ve ardından read, write, exit ve brk gibi temel çağrılar için istisna eklerim.

Güvenilmeyen ikili dosyaları test ederken kullandığım minimal seccomp profili şu şekildedir:

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86"
  ],
  "syscalls": [
    {
      "name": "read",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "write",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "exit",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "exit_group",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "brk",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "mmap",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "mprotect",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "munmap",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "openat",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "close",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "fstat",
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "name": "getdents64",
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

Bu profili /etc/systemd/nspawn/test.seccomp olarak kaydederim. Daha sonra profil zorunlu kılınarak konteyneri şöyle başlatırım:

# systemd-nspawn -D /var/lib/container/test --seccomp-profile=/etc/systemd/nspawn/test.seccomp

Artık konteyner içinde bir süreç ptrace, mount, /dev/mem üzerindeki open veya CLONE_NEWUSER bayrağıyla clone gibi bir sistem çağrısı yapmaya çalışırsa, çekirdek varsayılan olarak EPERM hatası döndürür ve çağrı başarısız olur. Süreç çökebilir ama ana sistemimiz güvende kalır.

Bu kolayca test edilebilir. Konteyner içinde şu komutu çalıştırabilirim:

# ptrace(PTRACE_TRACEME, 0, NULL, NULL)

Bir segmentation fault veya hata alırım — program hatalı değil, sadece çekirdek bu sistem çağrısını engellediğinden. İşte bu tam da amaç.

Bir uyarı: bir kabuk gibi betik çalıştıran şeyler daha fazla sistem çağrısı gerektiriyorsa, profili buna göre ayarlamam gerekir. Genellikle man seccomp.filter’tan varsayılan profiliyle başlarım veya iyi çalıştığını bildiğim bir komutun strace -f çıktısından bir profil çıkarırım, ardından onu daraltırım.

İpucu: Konteyner içinde önce strace -f -e trace=all <command> komutunu çalıştırarak aslında hangi sistem çağrılarının ihtiyaç duyduğunu görürüm. Daha sonra izin listesini buna göre oluştururum.

Auditd ile /etc/passwd izleme hakkında önceki yazımda da belirttiğim gibi, savunma derinliği önemlidir. Burada seccomp ilk savunma hattı — kötü çağrı gerçekleşecek bile engellenir. Loglama ve tepki beklemek zorunda kalınmaz; çekirdek onu doğrudan önler.

Bu kurulum iki dakikada hazırlanır ve praktisch hiç overhead eklemez. Laboratuvar, CI pipeline veya sadece meraklı test gibi güvenilmeyen kod değerlendirmesi yapıyorsanız, bunu denemenizi öneririm. Bu tür sessiz araçlar, kötü bir gün yaşamanızı önler.


Kapak görseli: personalgraphic.official · CC0 (Openverse / kamu malı) · https://www.flickr.com/photos/198895458@N04/53097628210