Blog
Her Kiracı Kendi VM'ine mi Sahip Olmalı?
Kiracı başına konteynerler, VM'ler ve hibrit kurulumlar arasında risk temelli bir karar çerçevesi ve her seçeneği savunulabilir kılan sağlamlaştırma adımlarıyla seçim yapın.
Özet
Çok kiracılı barındırma, kiracıların birbirlerine ne kadar erişebileceğini seçmek zorunda bırakır. Konteynerler, süreçleri ve kaynakları izole etmek için Linux ad alanlarını ve cgroup'ları kullanır, ancak ana çekirdeği paylaşırlar. Sanal makineler, hız ve operasyonel yük pahasına donanım düzeyinde bir sınır ekler. Hibrit bir yaklaşım—VM'ler içinde konteynerler—size her ikisini de verebilir, ancak yamanız gereken yüzeyi iki katına çıkarır. Bu makale sizi risk temelli bir karar, yan yana bir karşılaştırma ve bir VM içinde bile önemli olan Docker sağlamlaştırma adımları arasında yönlendirir. Sonunda, hangi izolasyon modelinin kiracılarınıza uyduğunu ve lansmandan önce neyi yapılandırmanız gerektiğini bileceksiniz.
Çok kiracılı uygulamanız neredeyse hazır. Müşteri başına bir yığın oluşturan bir Docker Compose dosyanız var ve hızlı. Sonra bir hosting şirketi işleten bir arkadaşınız sorar: 'Her kiracıya kendi VM'sini veriyor musunuz?' Donup kalırsınız. Bu soruyu planlamamıştınız. Bu makale, güvenlik ekibi olmadan bugün bu soruyu yanıtlamanın bir yolunu sunuyor. Bunu yalnız yapıyorsunuz, bu yüzden kararın gece 2'de savunulacak kadar basit olması gerekiyor.
'En iyi' modeli bulmaya çalışmayı bırakın. Bir kiracının kodu ana sunucunuzu ele geçirirse ne olacağını yazarak başlayın. Herhangi bir aracı seçmeden önce patlama yarıçapını tanımlayın. Bu alıştırma size herhangi bir kıyaslamadan daha fazlasını söyleyecektir.
Çekirdek, Tahliye Edemeyeceğiniz Oda Arkadaşıdır
Konteynerler verimlidir çünkü ana sunucu çekirdeğini paylaşırlar. Bu paylaşım tüm püf noktası ve tüm risktir. Linux ad alanları her konteynere süreçler, ağ ve dosya sistemi açısından kendi görünümünü verir. Kontrol grupları (cgroups), bir kiracının diğerlerini aç bırakamaması için CPU, bellek ve disk I/O sınırlamanızı sağlar. Ancak hiçbiri donanım duvarı oluşturmaz.
Bir konteyneri, gerçekten iyi sahte kimliğe sahip bir süreç olarak düşünün. Kendi makinesinde olduğuna inanır. Ancak çekirdek, ana sunucunuzda çalışan tek bir Linux kopyasıdır. Bir kiracı bir çekirdek açığını istismar ederse, ad alanları yalnızca meta veri haline gelir. Çekirdek işlevlerini çağırabilen bir saldırgan, aynı çekirdekteki diğer ad alanlarına ulaşabilir. Bu, sürekli duyduğunuz konteyner kaçışıdır.
Diyelim ki müşteri başına bir konteynerle küçük bir B2B aracı barındırıyorsunuz. Bir müşteri, uzaktan kod yürütme hatası olan şüpheli bir eklenti kurar. Varsayılan Docker ayarlarıyla bu süreç konteyner içinde root olarak çalışır. Konteynerdeki root hâlâ UID 0'dır ve kullanıcıları açıkça eşlemediğiniz sürece çekirdek bu UID'yi ana sunucu root'undan ayırt etmez. Saldırgan dışarı çıkmayı deneyebilir ve paylaşılan çekirdek onun hedefidir.
Arızanın dramatik olması gerekmez. Tek bir kiracının bellek sızıntısı, ana sunucuyu takas alanına iterek diğer tüm kiracıları yavaşlatabilir. Cgroup sınırları olmadan, yanlış davranan bir döngü kullanılabilirlik saldırısıdır. Onlarla birlikte, engellenen bir süreç ve bir uyarıdır.
Bu, konteynerlerin güvensiz olduğu anlamına mı gelir? Hayır. Çekirdeğe ortak bir güven bölgesi olarak davranmanız gerektiği anlamına gelir. Seçim yapmadan önce tek paragraflık bir risk beyanı yazın: 'Bir kiracının konteyneri ele geçirilirse, saldırgan şunlara erişebilir: [liste]. İşletme maliyeti şu olur: [tutar veya etki].' Bu paragraf sizi korkutuyorsa, paranoyak değilsiniz. Dürüstsünüz.
İzolasyon yelpazesine daha derin bir bakış için, paylaşılan konteynerlerden tamamen ayrı yığınlara kadar, çok kiracılı bir Docker mimarisi tasarlama rehberimize göz atın.
Üç Şekilde Dilimleyin (Dağıtımdan Önce Birini Seçin)
Çok kiracılı izolasyon için gerçekten üç mimari vardır. Her 'en iyi uygulama' bunların bir kombinasyonudur.
| Yaklaşım | İzolasyon bariyeri | En iyi ne zaman | En zor uyarı |
|---|---|---|---|
| Kiracı başına konteynerler | Çekirdek ad alanları + cgroup'lar | Çok sayıda küçük kiracı, kiracı başına düşük risk, yoğunluk gerekli | Bir çekirdek açığı o sunucudaki tüm kiracıları etkileyebilir |
| Kiracı başına bir VM | Hypervisor/donanım sanallaştırma | Düzenlenmiş veriler, düşmanca kiracılar, kiracı başına yüksek değer | Daha ağır, sağlanması daha yavaş, kiracı başına işletim sistemi yamalarsınız |
| VM'ler içinde konteynerler | Konteynerleştirilmiş iş yükleri etrafında VM sınırı | Yoğunluk artı gruplar arasında sert bir kabuk | Maliyetler ve operasyonel yük neredeyse iki katına çıkar |
Kiracı başına konteynerler. Çoğu SaaS kurucusu için varsayılan budur. Her kiracı kendi konteynerini veya küçük Compose yığınını alır. Sağlama anlıktır, görüntüler küçüktür, CI/CD basittir. Kaynak sınırları, gürültülü komşuların sunucuyu tüketmesini engeller. Ödünleşim, paylaşılan çekirdektir. İş yüklerini ayrıcalıklı olmayanlarda tutabiliyor ve ana sunucuyu düzenli olarak yamalıyorsanız, bu genellikle doğru ilk hamledir.
İki kiracıyı aynı konteynere koymayın. Bu, paylaşılan bir çekirdek artı paylaşılan bir çalışma zamanı artı paylaşılan bir dosya sistemidir. Bir kiracı bir süreç oluşturan bir dosya yüklerse, diğer kiracı zaten aynı süreç tablosundadır. Konteyner sizin izolasyon biriminizdir; konteyner başına bir kiracı yapın.
Peki veritabanı? Her kiracı aynı kimlik bilgileriyle tek bir MongoDB veya PostgreSQL örneğine bağlanıyorsa, zaten büyük bir paylaşılan bileşen eklemişsinizdir. Her kiracıya ayrı kimlik bilgileri ve ideal olarak ayrı bir veritabanı veya şema verin. Konteynerler uygulamayı izole eder; veritabanı genellikle bir saldırganın test edeceği ilk sızıntıdır.
Kiracı başına bir VM. Her kiracıya tam bir sanal makine verin. Hypervisor, bir çekirdek açığının ana sunucuya ulaşmak için geçmesi gereken donanım düzeyinde bir sınır ekler. Bu, düzenlenmiş ortamlar veya kiracıların güvenilmez olduğu durumlar için önemlidir. Maliyet, yoğunluk ve zamandır. Artık yalnızca konteynerleri değil, bir işletim sistemi filosunu yönetiyorsunuz. Her VM güncelleme, güvenlik aracıları ve izleme gerektirir. Tek bir kurucu için bu gerçek bir iştir.
Bu katmanda işe yarayan desenler: aynı temel görüntüden bir VM oluşturmak için altyapı-olarak-kod kullanın, canlı sistemleri yamamak yerine güncellemeleri yeni görüntülere gömün ve tanımadığınız iş yüklerini sonlandırın. VM'in yönetim bağlantı noktasını internete kapalı tutun.
VM'ler içinde konteynerler. Bu hibrit, yeni başlayan eğitimlerinde nadiren tartışılır. Her kiracının (veya küçük bir kiracı grubunun) etrafına küçük bir VM koyar ve o VM'in içinde konteynerleri çalıştırırsınız. VM, patlama yarıçapı kabıdır; konteynerler yalnızca dağıtılabilir birimlerdir. Bu size sanallaştırmanın keskin kenarını ve görüntülerin yeniden üretilebilirliğini verir. Daha pahalıdır, çünkü sanallaştırma ek yükü ve konteyner esnekliği için ödeme yaparsınız, ancak kiracılara tam olarak güvenemediğinizde en mantıklı uzun vadeli model olabilir.
Yaygın bir mikro-örnek: bir kiracı bir Node API ve bir arka plan çalışanı çalıştırır. Her iki süreci içeren tek bir büyük konteyner yerine, bir VM kullanın, ardından farklı kaynak sınırları olan, paylaşılan bir ağa sahip ve çalışan için doğrudan internet erişimi olmayan iki konteyner kullanın. VM sert kenarı sağlar; konteynerler yapıyı sağlar.
Hangisini seçmelisiniz? Tablo sizin kısa listeniz. Sonraki bölümler kararı somutlaştırıyor.
Konteynerleri Seçerseniz, Bu Altı Şeyi Yapın veya Hiç Uğraşmayın
Her konteynere potansiyel bir saldırgan gibi davranırsanız, kiracı başına konteynerler iyidir. Bu, iyi niyetli düşüncelerle değil, yapılandırmayla başlar.
0. Kimseye güvenmeden önce kaynakları sınırlayın. Cgroup'lar bir adalet mekanizması ve kullanılabilirlik savunmasıdır. Konteyner başına --memory ve --cpus ayarlayın. Bellek sızdıran bir kiracı kendi sınırına çarpmalı, sunucunuzunkine değil. Bu bir güvenlik sınırı değildir, ancak gürültülü bir komşu, tek satır kod olmadan yapılan bir saldırıdır. Pratik bir başlangıç: --memory 512m --cpus 0.5. Bir çalışan süreci için daha düşük başlayın ve ölçeklendirin.
1. Root olmayan bir kullanıcı olarak çalıştırın. Kesinlikle gerekmedikçe konteyner sürecinin UID 0 kullanmasına asla izin vermeyin. Dockerfile'da bir kullanıcı ayarlayın ve ek bir koruma olarak --user iletin. Ayrıcalıklı olmayan bir kullanıcı olarak çalışan bir istismarın çekirdeğe giden çok daha az yolu vardır. Dockerfile'ınızda bir kullanıcı oluşturun: RUN useradd -u 10001 app ve USER app. Zaman kazanmak için bunu atlamayın.
2. İhtiyacınız olmayan tüm yetenekleri bırakın. Linux yetenekleri root'un gücünü küçük parçalara böler. Çoğu web uygulaması neredeyse hiçbirine ihtiyaç duymaz. --cap-drop=ALL ile başlayın ve yalnızca bildiğiniz gerekli olanları geri ekleyin. CAP_SYS_ADMIN olmayan bir konteynerin ad alanı hileleri için kullanılması çok daha zordur. Uygulamanız ayrıcalıklı bir bağlantı noktasına bağlanmaya çalışırsa, NET_BIND_SERVICE vermek yerine yüksek bir bağlantı noktasında çalıştırın ve önüne bir proxy koyun.
3. Dosya sistemini salt okunur yapın. Uygulamanız kendi konteyner katmanına yazmamalıdır. Durum için bir tmpfs bağlayın. Diske yazamayan bir saldırganın kalıcılık yerleştirmesi çok daha zordur. Kök dosya sistemi salt okunur olduğunda, bir web kabuğu yazmaya çalışan ele geçirilmiş bir PHP uygulaması başarısız olur. Uygulamanızın gerçekten ihtiyaç duyduğu yazılabilir bir dizin için adlandırılmış bir birim bağlayabilirsiniz.
4. Seccomp ve AppArmor veya SELinux uygulayın. Bunlar riskli sistem çağrılarını çöp yığınına gönderir. Docker varsayılan bir seccomp profili ile gelir; onu kullanın. Başka bir katman için bir AppArmor profili ekleyin. Her sistem çağrısına hakim olmanıza gerek yok. Normal bir web çalışanının asla gerektirmediğini reddetmeniz gerekir. Asla --privileged ile çalıştırmayın. Bu bayrak, az önce kurduğunuz neredeyse tüm savunmaları devre dışı bırakır.
5. Ağı bölümlere ayırın. Her konteynere diğer her konteynere bir rota vermeyin. Varsayılan olarak reddedin, ardından yalnızca ihtiyacınız olan bağlantı noktalarını açın. Ele geçirilmiş bir veritabanı konteyneri yönetim panelinizi tarayamamalıdır. Kiracılar ayrı ağlardaysa, bir ağdaki ihlal yanal olarak yayılamaz.
Pratik bir başlangıç:
docker run --user 10001 --cap-drop=ALL --security-opt no-new-privileges --read-only --tmpfs /tmp:rw,size=64M --security-opt seccomp=default.json --memory 512m --cpus 0.5 myimage
Aynı bayrakları bir Compose dosyasına koyun ve tüm kiracılara uygulayın. Bu eksiksiz değil, ancak docker run'ın size kutudan çıktığı haliyle verdiğinden çok daha güçlü bir varsayılandır.
Daha derin bir anlatım için, çok kiracılı barındırmada Docker konteynerleri için adım adım sağlamlaştırma rehberimizi kullanın.
Docker'ın Gelişmiş Konteyner İzolasyonu Bilmeniz Gereken İstisnadır
Yönetilen bir Docker ortamında çalışıyorsanız, Docker'ın Gelişmiş Konteyner İzolasyonu'na (ECI) bakın. Perde arkasında kullanıcı ad alanı izolasyonu ve güvenli bir konteyner çalışma zamanı kullanır. Konteyner içindeki root, ana sunucudaki ayrıcalıklı olmayan bir kullanıcıya eşlenir, bu nedenle root olarak çalışan bir konteyner bile ana sunucu root ayrıcalıklarına sahip olmaz. Ayrıca varsayılan olarak tehlikeli yetenekleri ve sistem çağrılarını engeller. Bu, düz Docker'da birkaç bayrakla yeniden oluşturabileceğiniz bir şey değildir. Platformunuz destekliyorsa, açın. Root olmayan kullanıcılar ve kaynak sınırları ihtiyacını ortadan kaldırmaz, ancak risk matematiğini değiştirir.
Bunun bir kısmını Docker daemon'ında kullanıcı ad alanı yeniden eşleme (userns-remap) ile yaklaşık olarak elde edebilirsiniz. Bu, güvenli bir çalışma zamanı kadar eksiksiz değildir, ancak hiç yoktan iyidir. Kullanırsanız, güvenmeden önce UID eşlemesinin çalıştığını doğrulayın.
VM Yanılgısı: Sanal Makinelere Geçmek Sağlamlaştırma Değildir
İşte karşıt görüş, ve çoğu insanın atladığı kısım. Kiracı başına bir VM'e geçerseniz ve ardından normal konteynerlerinizi içine dağıtırsanız, konteyner güvenlik sorununuzu ortadan kaldırmış olmazsınız. Geniş bir kafes eklediniz. Konteyner kaçışı hâlâ çalışır; saldırgan ana sunucu yerine VM'e iner. Bu gerçek bir gelişmedir, ancak yine de altı adıma ihtiyacınız var.
Diğer tuzak, VM'in kendisinin güvenli olduğunu varsaymaktır. Zayıf bir SSH parolası, yamalanmamış temel paketler veya açık bir yönetim bağlantı noktası olan varsayılan bir görüntü bir hediyedir. Hypervisor sınırı yalnızca konuk sağlamlaştırılmış ve güncellenmişse önemlidir. Aksi takdirde, 'güvenli VM'iniz' güvenli hissettiğiniz ve kontrol etmeyi bıraktığınız için tehlikeye atmanın daha hızlı bir yoludur.
Bir VM'in size kazandırdığı şey, azaltılabilir patlama yarıçapıdır. Bir kiracının felaketi bir VM'de kalır. Size maliyeti ise zamanınızdır. Kiracı sayınız kadar işletim sistemi için sistem yöneticisi olursunuz. Bir ürün çıkaran tek bir kurucuysanız, bir filoyu yamamak ve izlemek için saatleriniz olup olmadığını sorun. Evet ise, kiracı başına VM doğru karar olabilir. Hayır ise, güçlü sağlamlaştırmaya sahip konteynerler daha dürüst olabilir.
Ayrıca hypervisor ana sunucunuzun kritik bir hedef olduğunu unutmayın. Ele geçirilmiş bir hypervisor tüm konukları görebilir. Yalnızca konukları değil, ana sunucuyu da yamalayın. VM sizi ana sunucu yamalamaktan muaf tutmaz; kaçırmanın bedelini artırır.
Hibrit hakkında bir uyarı: VM içindeki konteynerlerin size bedavaya 'iki güvenlik katmanı' sağladığını varsaymayın. VM bir sınır ekler; konteyner hâlâ root olmayan, yetenekler ve seccomp gerektirir. Aksi takdirde ilk katman yalnızca en zayıf konteyner kadar güçlüdür.
Tartışmayı On Dakikada Çözen Dört Soru
Soyut olarak optimize etmeyin. Kendinize bu dört soruyu sırayla sorun. Cevapları yazın.
1. Kiracımın neye erişimi var? Bir kiracı yalnızca kendi web uygulamasına ve veritabanına erişebiliyorsa, katı ağ kurallarına sahip kiracı başına konteynerler savunulabilir. Bir kiracının verileri düzenleniyorsa veya finansal açıdan hassassa, VM'lere doğru ilerleyin.
2. Bir kiracının tehlikeye girmesi bana ne kadara mal olur? Kaybedilen müşterileri, yasal riskleri ve güveni toplayın. Sayı, VM çalıştırma maliyetinden büyükse, parayı harcayın. Değilse, konteynerler rasyonel bir seçimdir.
3. Kaç kiracım var ve ne kadar ödüyorlar? Çok sayıda küçük abone: konteyner yoğunluğu önemlidir. Bir avuç büyük hesap: her birine bir VM verin ve buna göre faturalandırın. Size bir kahveden az ödeyen kiracıların her birinin yönetilmesi için bir işletim sistemi gerekmemelidir.
4. Bir programa göre yama yapabilir miyim? Konteynerler tek bir ana sunucu çekirdeğini paylaşır, bu nedenle ana sunucuyu yamamak herkesi korur. VM'ler yama hedeflerinizi çoğaltır. Güncellemeleri atlayacağınızı biliyorsanız, daha az hareketli parçaya ve daha sert varsayılanlara sahip mimariyi seçin.
Cevaplarınız kümelenir. İki veya daha fazla VM odaklı cevap, kiracı başına konteynerlere varsayılan olarak geçmemeniz gerektiği anlamına gelir. Üç veya daha fazla konteyner odaklı cevap, VM'lerin erken olduğu anlamına gelir. Sezgiye aykırı bir sonuç: hassas verilere erişimi olan düşük gelirli bir kiracı yine de VM'e ihtiyaç duyar, çünkü düzenleyici maliyetin ne kadar ödedikleriyle hiçbir ilgisi yoktur.
Güvenebileceğiniz En Azını Yayınlayın, Sonra Daha Fazla İzolasyon Kazanın
İlk mimariniz son mimariniz olmak zorunda değil. Gerçekten sürdürebileceğiniz en sıkı kurulumla başlayın, ardından kiracı tabanınız haklı çıkardıkça izolasyon ekleyin. Çoğu solo operatör için bu, root olmayan, sınırlandırılmış yeteneklere, salt okunur dosya sistemlerine, seccomp'a ve ağ bölümlemesine sahip kiracı başına konteynerler anlamına gelir. Düzenlenmiş veya yüksek değerli kiracılar için, içinde yalnızca bir paketleme katmanı olarak konteynerler bulunan kiracı başına bir VM'e doğrudan geçin.
Ne seçerseniz seçin, kararı yazın ve üç ayda bir tekrar gözden geçirin. İlk 'bu kiracıyı bir VM'e taşımalı mıyız?' sorusunu aldığınızda, bir cevabınız olacak ve bunu destekleyecek bir kontrol listeniz olacak. İzolasyon aslında şu anlama gelir: satın aldığınız bir teknoloji değil, yönettiğiniz bir ödünleşim.
Lansmandan önce, pratik Docker izolasyon güvenlik kontrol listemizi gözden geçirin—bu kararları, bir sayfayı müşteriye göstermeden önce doğrulayabileceğiniz bir listeye dönüştürür.

