Blog

Hangi Müşteriler Gerçekten Kendi VM'ine İhtiyaç Duyar? Katmanlı Bir Docker İzolasyon Planı

Her müşteri için VM abartıdır. Her kiracının ne kadar izolasyona ihtiyacı olduğuna nasıl karar vereceğinizi ve kararı nasıl otomatikleştireceğinizi burada bulabilirsiniz.

Özet

Ajanslar, bir müşteri verilerinin diğer kiracılardan ne kadar gerçekten izole olduğunu sorduğunda genellikle paniğe kapılır. Docker'ın ad alanları ve cgroup'ları size gerçek izolasyon sağlar, ancak bunlar bir donanım sınırı ile aynı şey değildir. Her müşteriyi bir VM'de çalıştırmak yerine—veya daha kötüsü, her müşteriye aynı şekilde davranmak yerine—küçük bir izolasyon katmanı seti oluşturun ve her müşteriyi veri hassasiyeti, güven ve uyumluluğa göre bir katmanla eşleştirin. Kilitli bir kapsayıcı (root olmayan, yetenekleri düşürülmüş, seccomp, salt okunur kök) çoğu siteyi kapsar; düzenlemeye tabi veya düşmanca iş yükleri bir VM veya VM içinde kapsayıcı melezi alır. Bu yazı, tekrarlanabilir bir karar akışı, bir karşılaştırma tablosu ve daha fazla izolasyonun ne zaman aşırı olduğuna dair dürüst bir bakış sunar.

Bir satış görüşmesinde yeni müşterinin “biz sağlık sektörüyüz, verilerimizin diğer müşterilerinizden izole olduğunu gösterin” dediği ve başka bir şey hakkında konuşmayı tercih ettiğiniz noktada mısınız?

Bu, ajans sorunudur: tek bir mükemmel dağıtım değil, farklı bütçelere, risk profillerine ve uyumluluk taleplerine sahip bir düzine müşteri arasında tekrarlanan aynı güvenilir dağıtımdır. İşte dürüst versiyonu. Docker izolasyonu gerçektir, ancak spesifiktir. Ad alanları her kapsayıcıya kendi süreç, ağ ve dosya sistemi görünümünü verir; cgroup'lar CPU, bellek ve disk I/O'sunu sınırlar, böylece kiracılar birbirlerini aç bırakamaz. Bunun size sağlamadığı şey, kapsayıcı ile ana bilgisayar çekirdeği arasında bir donanım duvarıdır. Bir saldırgan kapsayıcıdan kaçarsa, sahip olduğunuz tek çekirdeğin içindedir. Bu makalenin geri kalanı bu rahatsız edici gerçeği tekrarlanabilir bir karara dönüştürür: her müşteriyi veri hassasiyeti ve güvenine göre sınıflandırın, temel bir sağlamlaştırma profili uygulayın ve yalnızca bir ihlalin maliyeti VM maliyetinden yüksek olduğunda bir VM'e başvurun.

Bekle, kapsayıcılar zaten izole değil mi?

Docker, Linux ad alanları ve cgroup'lar üzerinde çalışır ve bu kelimeler gerçek iş yapıyor. Ad alanları, süreç kimliklerini, ağ yığınlarını, bağlama noktalarını ve kullanıcıları ayırır, böylece bir kapsayıcıdaki bir süreç diğerinin süreç tablosunu göremez. Cgroup'lar sınırlar belirler: bir kapsayıcıya 0,5 CPU, 512 MB bellek ve sabit bir blok I/O ağırlığı verin, tam olarak aldığı budur. Bir kiracıdaki başıboş döngü, komşuyu devirmek yerine kısılır. Sınırlar yapılandırmadıysanız, cgroup'ların en temel amacını atlamışsınızdır.

Kapsayıcı A'da basit bir PHP uygulaması düşünün. Kendi dosya sistemini, kendi ağ arayüzünü, kendi PID 1'ini görür. Kapsayıcı B aynı şeye sahiptir, ancak farklı bir görünüm. Bu ad alanlarıdır. Şimdi uzaklaşın ve bellek sınırını atlayın: kapsayıcı A, ana bilgisayarın RAM'ini doldurabilir ve kapsayıcı B'nin yavaşlamasına neden olabilir. Cgroup'lar tam da bunu önlemek için vardır. Ancak iki kapsayıcı, ad alanları tarafından birbirinden izole edilebilir ve yine de ana bilgisayar çekirdeğini paylaşabilir; bu, her kapsayıcı kaçış hikayesinin konusudur. Çekirdeğe ulaşan bir istismar, o ana bilgisayardaki her kiracıya potansiyel olarak ulaşabilir.

“Docker izole eder” yarım doğru bir cümledir. Doğru versiyonu “Docker, ad alanları ve cgroup'larla izole eder ve bir çekirdek güvenlik açığı patlama yarıçapıdır.” Bir kiracıya güvenilmeyen kod çalıştırmasına izin vermeden önce, bu düşünceyle bir dakika oturun. Cevap “asla kapsayıcı kullanmayın” değil—bu kolay panik. Cevap bir katman sistemidir.

Peki neden bazı müşteriler ad alanlarından daha fazlasına ihtiyaç duyar?

Dürüst cevap, izolasyonun bir anahtar olmadığı, bir spektrum olduğudur. Bir uçta herkesin etkili bir şekilde tek bir uygulama içinde olduğu tamamen paylaşılan bir kapsayıcınız var. Diğer uçta, her kiracı için kendi çekirdeğine sahip ayrı bir VM var. Ajans işlerinin çoğu rahatsız edici ortada yaşar ve orta, “Docker yeterli” ile “herkes için VM çalıştır” arasında ikili bir seçim değildir.

Bir müşteriyi sağa iten şey boyutu değildir. Dört sorudur:

  • Düzenlemeye tabi veri depoluyorlar mı? Sağlık kayıtları, ödeme kartı bilgileri, bir düzenleyicinin hassas diyeceği her şey.
  • Kiracılarındaki bir ihlalin başka bir kiracıya gerçekçi bir yolu var mı? Rastgele kod çalıştırabiliyorlarsa, evet.
  • Koda ve onu dağıtan insanlara güveniyor musunuz? En ucuz serbest çalışanı işe alan müşteri, geliştirici ekibini tanıdığınız müşteriyle aynı güven düzeyinde değildir.
  • Sözleşmeleri “adanmış”, “izole” veya “özel” mi diyor? Öyleyse, zaten bir katman sözü verdiniz; şimdi tek iş doğru olanı seçmek.

Bu soruları henüz cevaplayamıyorsanız, müşteriyi temel bir katmana koyun ve varsayımları yazın. Bu bir güvenlik denetimi değil; her katılımda tekrarladığınız bir akıl sağlığı kontrolü.

Her seferinde güvenlik denetimi yapmadan müşteri başına nasıl karar veririm?

Küçük bir tablo yapın ve ona bağlı kalın. Kırk hücreli bir matrise ihtiyacınız yok. Dört katman, bir ajansın gördüğü neredeyse her müşteriyi kapsayacaktır.

Müşteri KonumuOnları gerçekten ayıran nedir?Ne zaman kullanılır?
Katman 1: Paylaşılan uygulama/kapsayıcıYalnızca uygulama mantığıDahili araçlar, düşük riskli veriler, herkesin açıkça tek bir giriş sisteminde olduğu projeler
Katman 2: Aynı sunucu, ayrı kapsayıcılarAd alanları ve cgroup'larÇoğu pazarlama sitesi, iletişim formları, hassas veri yok
Katman 3: Kilitli kapsayıcıKatman 2 + root olmayan, düşürülmüş yetenekler, seccomp, salt okunur kök, ağ bölümlendirmeE-ticaret, PII, tam olarak güvenmediğiniz özel kod
Katman 4: Kiracı başına VMHypervisor ve ayrı bir çekirdekSağlık, finans, uyumluluk evrak işleri, güvenilmeyen kod, gürültülü komşular

İşte pratikte böyle çalışıyor. İletişim formu ve Instagram bağlantısı olan bir fırın müşterisi Katman 2'ye gider: paylaşılan bir sunucuda tek kapsayıcı, varsayılan Docker ağı, kaynak sınırları, iş tamam. Müşteri adlarını, adreslerini ve ödeme yönlendirmelerini saklayan bir çevrimiçi mağaza Katman 3'e gider: aynı paylaşılan sunucu, ancak kapsayıcı root olmayan bir kullanıcı olarak çalışır, ek çekirdek yeteneklerine sahip değildir, bir seccomp profili kullanır ve yalnızca 443 numaralı bağlantı noktasını açığa çıkarır. Korumalı sağlık bilgilerini saklayan bir tıbbi kabul portalı Katman 4'e gider: kiracı başına bir VM, çünkü bir ihlalin maliyeti “bunu temizleriz” değil, “müşteriye onları ciddiye aldığımızı gösteremeyiz”.

Püf noktası, her müşteri için mimariyi yeniden düşünmemenizdir. Zaten üzerinde anlaştığınız bir tablodan bir satır seçiyorsunuz. Beş kişilik bir ajans, yüz ayrı güvenlik takıntısı olmadan yüz siteyi böyle yönetir. Ayrıca, bir sonraki müşterinin telefonu açan ekip üyesine bağlı bir cevap almaması anlamına gelir. Bu seçimlerin arkasındaki daha derin mimari tartışma için, çok kiracılı izolasyon seviyeleri tasarlama kılavuzu trade-off'ları daha ayrıntılı olarak ele alıyor.

Kilitli bir kapsayıcı gerçekte neye benzer?

“Kilitli” demeyi bırakalım ve somutlaşalım. Katman 3, tipik bir WordPress veya PHP müşterisi için budur.

Önce kullanıcıyı değiştirin. Çoğu resmi görüntü varsayılan olarak hala root olarak çalışır; Dockerfile'ınızda root olmayan bir kullanıcı oluşturun ve uygulamayı o kullanıcı olarak çalıştırın. Bu, bir kapsayıcı uzlaşmasının ana bilgisayar uzlaşmasına dönüşmesinin en yaygın yolunu hemen ortadan kaldırır. İkinci olarak, ihtiyacınız olmayan yetenekleri bırakın. --cap-drop ALL ile çalıştırın ve genellikle NET_BIND_SERVICE olan yalnızca birini geri ekleyin, böylece uygulama 80 numaralı bağlantı noktasını dinleyebilir. Tek başına bu, çoğu insanın beklediğinden daha büyük bir değişikliktir. Üçüncü olarak, kök dosya sistemini --read-only ile salt okunur yapın ve yazılabilir dizinleri (yüklemeler, veritabanı veri dizini) birimler veya tmpfs olarak bağlayın. Dördüncü olarak, bir seccomp profili ve ana bilgisayarınız destekliyorsa AppArmor veya SELinux uygulayın. Son olarak, kapsayıcıyı özel bir Docker ağına koyun ve yalnızca gerçekten erişilebilir olması gereken bağlantı noktalarını açığa çıkarın.

Bir WordPress örneğini inceleyelim. Temel görüntü muhtemelen root olarak çalışır, bu yüzden bir useradd adımı ve bir USER yönergesi eklersiniz. Kapsayıcıyı bir bellek sınırı ve bir CPU sınırıyla çalıştırırsınız, böylece bir eklenti trafiği patlaması komşuya zarar vermez. /var/www/html/wp-content/uploads dizinini yazılabilir bir birim olarak bağlarsınız. --read-only ayarlarsınız. Onu yakınında --privileged bayrağı olmayan bir ağa bağlarsınız. Sonuç, eskiden “bir WordPress sitesi” olan ve artık “çoğu sanal özel sunucudan daha kilitli bir WordPress sitesi” olan bir kapsayıcıdır.

Tüm bunları elle yapmak kırılgan geliyorsa, daha kolay bir orta yol var: Docker'ın kullanıcı ad alanı izolasyonu ve güvenli bir kapsayıcı çalışma zamanı kullanan Gelişmiş Kapsayıcı İzolasyonu. Bu meşru bir kısayol, ancak root olmayan veya yetenek düşürmeyi atlamak için ücretsiz bir geçiş değil. Kiracı hala makul bir görüntüye ihtiyaç duyar. Fark, bir gecede seccomp uzmanı olmadan çekirdeğe bakan saldırı yüzeyinin küçülmesidir. Tek bir kiracı için tam sırayı istiyorsanız, adım adım izolasyon sağlamlaştırma kılavuzu bu bölümü kopyala-yapıştır komutlarına dönüştürür.

Ne zaman katman eklemeyi bırakıp onlara bir VM veririm?

İşte karşıt görüş: daha fazla izolasyon otomatik olarak daha iyi değildir. VM'ler size donanım düzeyinde izolasyon, ayrı bir çekirdek ve misafir çekirdek düşerse çok daha küçük bir saldırı yüzeyi verir. Sağlık ve finans müşterilerinin “izole olmak istiyoruz” dediklerinde bekledikleri tam olarak budur. Ancak her VM, yama, yedekleme ve bilgi işlem maliyeti ekler ve bir filoyu güncel tutma işini çoğaltır. Bir müşteri size bir kez Docker'ın onları korkuttuğunu söylediği için her müşteriyi VM yaparsanız, gerçek parayla güvenlik tiyatrosu satın almışsınızdır.

Kiracı başına risk, kiracı başına bir VM'in operasyonel maliyetinden yüksek olduğunda bir VM doğru cevaptır. Bu, düzenlemeye tabi veri, yazılı uyumluluk gereksinimleri, güvenilmeyen üçüncü taraf kodu veya gürültülü bir komşunun kaldırılmasına ihtiyaç duyan bir müşteri anlamına gelir. Ayrıca, müşterinin sözleşmesi kelimenin tam anlamıyla adanmış bir ortam vaat ettiğinde de doğru cevaptır, çünkü “adanmış” imzalarken hayal ettikleri şey “kapsayıcı” değildir.

Ancak bir VM, özensiz bir kapsayıcıyı mazur göstermez. Yaygın bir tuzak, müşteriyi bir VM'e koymak ve sonra “VM onları korur” diye sağlamlaştırmayı atlamaktır. VM, ana bilgisayarı kiracıdan korur, kiracıyı kendi kötü imajından değil. Yine de o VM içinde root olmayan, düşürülmüş yetenekler ve seccomp istersiniz. Hibrit yaklaşım—bir VM içinde kapsayıcılar—genellikle en iyi noktadır: VM, uyumluluk görüşmeleri için sınırı sağlar ve kapsayıcı, zaten bildiğiniz dağıtım iş akışını verir. Bu tartışmanın daha uzun bir versiyonu Her Kiracı Kendi VM'ini Almalı mı? içinde, ancak kısa cevap VM'in korku için değil, sözleşme için olduğudur.

Bunu her müşteri için nasıl tekrarlanabilir hale getiririm?

Katman sistemini bir hafıza değil, bir şablon haline getirerek tekrarlanabilir hale getirirsiniz. Her katman için bir tane olmak üzere Compose dosyalarından oluşan bir dizin tutun: tier2-baseline, tier3-locked, tier4-vm-hybrid. Yeni bir müşteri geldiğinde, şablonu kopyalayın, ortam değişkenlerini değiştirin ve yeni bir altyapı satırı yazmadan izolasyon şeklini zaten bilirsiniz.

Sonra kararı yazın. 400 sayfalık bir güvenlik raporu değil, müşterinin deposunda kısa bir paragraf: hangi verileri sakladıkları, hangi katmanda oldukları, neden ve onları bir üst katmana taşıyacak şey. Bu paragraf, yüzlerce güvenlik duvarı kuralından daha değerlidir, çünkü bir sonraki denetçiye veya bir sonraki endişeli müşteriye gösterebileceğiniz şeydir. Ayrıca, orijinal satış görüşmesi solduktan sonra fırının neden Katman 2 ve e-ticaret mağazasının Katman 3 aldığını hatırlamak zorunda kalmanızı engeller.

Sıkıcı kontrolleri otomatikleştirin. CI'ınızın her müşteri görüntüsünü taramasını ve root olarak çalışıyorsa, tüm yeteneklere sahipse veya katmanın izin verdiği bağlantı noktaları dışında bir bağlantı noktası yayınlamaya çalışırsa bir derlemeyi başarısız kılmasını sağlayın. Bunların hiçbiri egzotik değil; sadece şablonun iyi niyetli bir geliştirici tarafından yanlışlıkla bozulmadığından emin olmak. Zaten çevreleyen barındırma iş akışını oluşturuyorsanız, üretime hazır Docker barındırma stratejileri makalesi kapsayıcılar tanımlandıktan sonra gelen kısmı kapsar.

Bunların hiçbiri göz alıcı değil. Hiçbir blog yazısı “kiracı izolasyonunu” yeni bir mimari diyagramı kadar heyecan verici gösteremez. Ancak bu, “ne kadar izoleyiz?” sorusuna parmaklar çapraz “tamamen” ile cevap veren bir ajans ile bir katman, bir yapılandırma ve bir neden gösterebilen bir ajans arasındaki farktır. Kapsayıcılar sihirli bir duvar değildir. VM'ler sihirli bir mermi değildir. Bir katman sistemi, yazdığınız ve yeniden kullandığınız bir karardır—ve bir ajans için tekrarlanabilirlik her şeydir.

Sources (5)