Hub Python Library documentation
Perde arkasındaki kum havuzları
Perde arkasındaki kum havuzları
Bu kılavuz, Sandboxes'ın iç işleyişini, neden bu şekilde tasarlandığını ve sınırlarını açıklar. Yalnızca sandboxes kullanmak istiyorsanız Sandboxes kılavuzu yeterlidir; mekanizmayı anlamak, güven modelini değerlendirmek veya bir sorunu gidermek istiyorsanız okumaya devam edin.
Sandbox API deneyseldir. API'si ve davranışı haber verilmeksizin değişebilir.
“sandbox service” adında bir hizmet yoktur
Anlaşılan ilk şey, özel bir sandbox backend'inin bulunmadığıdır. Sandbox, yalnızca HTTP konuşan tek bir küçük statik sbx-server binary'sini çalıştıran bir HF Job (VM)'dir. İstemci, bu sunucuyla Jobs proxy'si üzerinden (Job'un açığa çıkardığı *.hf.jobs URL'si) iletişim kurar. Geri kalan her şey — kimlik doğrulama, keşif, birçok sandbox'ı tek bir Job'a paketleme — mevcut Jobs yapı taşlarından (etiketler, ortam değişkenleri ve sırlar) inşa edilir.
Bu “yeni altyapı yok” tasarımı, bir sandbox’ın herhangi bir Docker görüntüsünde çalışmasının ve Jobs’un faturalandırma, donanım türleri ve ad alanı izinlerini ücretsiz olarak devralmasının nedenidir.
Sunucuyu başlatma
İş başlatıldığında, İş'in komutu, sbx-server ikilisini alır, çalıştırılabilir hale getirir ve onu exec ile çalıştıran küçük bir /bin/sh -c betigidir. İkili, sıfır çalışma zamanı bağımlılığına sahip ~640KB'lık statik bir musl derlemesidir; bu nedenle herhangi bir x86_64 Linux görüntüsünde çalışır.
Vurgulanmaya değer birkaç karar:
- Yükleme, mount yedeği ile. Hızlı yol, ikili dosyayı HF CDN'den
wgetveyacurlile indirir (her yaygın temel imaj bunlardan birini içerir), bu da hızlı ve ücretsizdir. Güvenlik ağı olarak, sunucunun Hub deposu da her işe bir hacim olarak bağlanır: imajda newgetne decurlvarsa, betik ikili dosyayı o mount'tan kopyalar. Mount şeffaftır — gerçekten okunmadıkça hiçbir maliyeti yoktur — ancak okuma, soğuk başlatmaya ~2-3 sn ekler, bu yüzden varsayılan değildir. İmajdaki tek zorunlu gereksinim/bin/sh'tir. - El yapımı HTTP/1.1 sunucusu, framework yok. Canlı çıktı akışı, her parçacık üretildikçe boşaltılmasını gerektirir. Yaygın minimal Rust HTTP sunucuları (ör.
tiny_http), parçalı yanıtları yanıt tamamlanana kadar tamponlar; bu da akışı bozar. Bu nedenle sunucu HTTP/1.1'i elle uygular:execiçin NDJSON olay akışları, dosyalar için ham gövdeler, parçacık başına açık bir boşaltma. - 49983 portu. Sunucu, yaygın geliştirme portlarının (3000, 8000, 8080, …) kendi kodunuz için boş kalmasını sağlamak amacıyla bilinçli olarak nadir kullanılan bir portta dinler.
Sunucu, github.com/huggingface/sandbox-server adresinde açık kaynaklıdır.
Kimlik doğrulama durum dışıdır
Bir sandbox'u koruyan iki bağımsız katman vardır:
- Proxy kapısı. Jobs proxy'si, yalnızca işin ad alanına (namespace) okuma erişimine sahip bir HF token'ı taşıyan istekleri iletir. İnternetin rastgele bir üyesi bu URL'ye erişemez.
- Uygulama kapısı.
sbx-server,/healthdışındaki her istekteX-Sandbox-Tokenbaşlığını ayrıca denetler. Bu, derinlemesine savunmadır: vekile erişebilen salt okunur bir ad alanı üyesi bile komut çalıştıramaz.
Sandbox belirteci saklanmaz, türetilir:
nonce = random 128-bit hex # stored in the job label "hf-sandbox-nonce" token = HMAC-SHA256(key=your_hf_token, msg="hf-sandbox:" + nonce)
Nonce herkese açıktır ve HMAC anahtarı HF token'ınızdır; bu nedenle o token'a sahip herhangi bir makine sandbox token'ını yeniden hesaplayabilir — yeniden bağlanmanın durumdan bağımsız (stateless) olmasını sağlayan tam olarak budur. Bu aynı zamanda, token'ın çağırana yönelik bir kimlik doğrulaması değil, kimlik bilginizden türetilmiş bir yetkinlik (capability) olduğu anlamına gelir: sunucu, çağıranın kim olduğunu değil, token'ı bildiğini doğrular.
Her sandbox işi, keşif için iki kararlı etiket taşır — hf-sandbox=1 (tümünde) ve hf-sandbox-mode=dedicated veya hf-sandbox-mode=pool — böylece bunları sunucu tarafında listeleyebilir veya filtreleyebilirsiniz, örn. hf jobs ps --label hf-sandbox=1.
Token, bir Job secret'i aracılığıyla sunucuya iletilir. İstemci, etiketteki herkese açık nonce'tan bunu gerektiğinde yeniden türetir. Bunun bazı güzel sonuçları vardır:
- Stateless yeniden bağlanma.
Sandbox.connect(id), aynı HF token'ına sahip herhangi bir makineden çalışır — nonce'u etiketten okuyun, token'ı yeniden hesaplayın. Yerel dosya yok, kopyalanacak durum yok. - HF jetonu, ortam değişkeni veya iş sırrı olarak sandbox'a geçirilmez (bunun için
forward_hf_token=Trueile açıkça izin vermedikçe). Kimlik bilgilerinizin erişilemez kalacağına dair kesin bir garanti değildir: sandbox portunda dinleyen süreç, imajın başlattığı ilk süreçtir; bu nedenle güvensiz bir imaj, istemcinin gönderdiği istekleri — bunlarınAuthorizationbaşlığı dahil olmak üzere — gözlemleyebilir. Sandbox'tan erişilebilen kimlik bilgilerini, sandbox'a potansiyel olarak açık olarak değerlendirin.
Token kapsamı
Her Job için bir adet nonce oluşturulduğundan, türetilen token bir job kimlik bilgisi olarak işlev görür. Ayrılmış modda job, sandbox'tur; bu nedenle ikisi aynıdır. Havuz modunda ise job, host'tur ve bir host birçok sandbox barındırır — bu yüzden havuzlanmış bir sandbox, kendine ait ikinci ve daha dar kapsamlı bir kimlik bilgisi alır:
| kimlik bilgisi | nasıl türetildi | yetkilendirir |
|---|---|---|
| özel kum havuzu belirteci | İşin etiketinden HMAC(hf_token, nonce) | o kum havuzu (ki asıl işin kendisi) |
| havuz ana makine belirteci | HMAC(hf_token, nonce), ana işin etiketinden | pool yönetimi: o host üzerinde sandbox'lar oluşturma, listeleme ve silme, token'larını kurtarma |
| toplanmış sandbox belirteci | host sunucu tarafından her sandbox için oluşturulan rastgele 256 bit | o tek kum havuzu — bir kardeş değil, havuz değil |
İstemci dar olanı otomatik olarak kullanır: pool.create() bunu oluşturma yanıtında alır, Sandbox.connect("<host>.<id>") onu host belirteciyle geri kazanır ve proxy_headers hostun belirteci yerine kum havuzunun belirteciyi verir (HF bearer'ı okuduğunuz anda çözümler, böylece uzun ömürlü bir tutamaç bayat bir belirteç dağıtmaz) — bu başlıklar genellikle bir tarayıcıda veya WebSocket istemcisinde sonlanır, bu nedenle yalnızca bir kum havuzuna erişim sağlamalı ve başka hiçbir şeye erişim vermemelidir.
Bir sızıntı için bunun anlamı: havuzlanmış bir sandbox belirteci o sandbox’u tehlikeye atar. Host belirteci ise host’u tehlikeye atar — üzerindeki tüm sandbox’lar (mevcut ve gelecekteki) ve yönetim yolları dahil — bu nedenle onu havuzun yönetici kimlik bilgisi olarak ele alın. Namespace üyeleriniz farklı bir HF belirtecine sahiptir ve sizin belirtecinizi türetemez, ancak bir belirtecin yanlış yere iletilebileceği durumlar için Bilinen kısıtlamalar bölümüne bakın.
İstemci, havuzlanmış işlemler için boş olmayan, sandbox kapsamına sahip bir jeton gerektirir ve böyle bir jeton sağlamayan ana bilgisayarları reddeder. Asla ana bilgisayar yönetimi kimlik bilgisinin yerini almaz. Bu API'yi kullanmadan önce istemciyi yükseltin ve eski havuz ana bilgisayarlarını yeniden başlatın.
Özel kum havuzları ( Sandbox.create )
Düz model: kum havuzu başına bir Job. Job gerçek bir sanal makinedir, bu da en güçlü yalıtımı (VM düzeyinde) sağlar, GPU dahil herhangi bir donanım türünü destekler ve birbirine güvenmeyen kodlar için doğru seçimdir. API yolları /v1/* altında bulunur ve dosya yolları konteyner dosya sisteminde mutlaktır. kill() yalnızca Job'u iptal eder.
Ayrı bir sandbox'ın size sağladığı sınır, Job ile onun dışındaki her şey arasındadır. VM içinde, kodunuz ve sbx-server aynı konteynerde root olarak çalışır: sbx-server, sizin için çalıştırdığı komutu sandbox'lamaz, yalnızca onu HTTP üzerinden açığa çıkarır. Bu nedenle, güvendiğiniz bir kod ayrı bir sandbox'ta çalıştırıldıktan sonra, o VM'yi — kontrol düzlemi dahil olmak üzere — o koda ait olarak kabul edin: sunucuyu öldürebilir veya değiştirebilir ve o sandbox'ta sonrasında yaptığınız her şey onun insafına kalmış olur. Güven sınırları arasında bir sandbox'ı yeniden kullanmak yerine, her güvensiz iş yükü için ayrı bir sandbox kullanın ve işiniz bitince kill() ile sonlandırın.
Maliyet şemasında açıkça görünüyor: her sandbox tam ~6s'lik bir VM soğuk başlatma maliyeti öder ve tüm bir makine için fatura kesilir. Tek bir sandbox veya GPU iş yükü için bu tam olarak istediğiniz şeydir. 100–1000 kısa süreli CPU görevi için ise bu israfçıdır — havuzlar (pools) tam da bunun içindir.
Havuzlar: Bir Job içinde birçok sandbox ( SandboxPool )
Pools, tek bir güven sınırı içindeki iş yükleri içindir. Havuzlanmış bir sandbox, kendi VM'si değil, paylaşılan bir VM içindeki bir uid + Landlock kuralları kümesidir ve ana makinesi, tüm sandbox'larının iletişim kurduğu ayrıcalıklı bir kontrol düzlemi çalıştırır. Havuzları, kendi kodunuzu düşük maliyetle dağıtmak için kullanın. Karşılıklı güvensiz iş yükleri için — diğer sandbox'larınızın dosyalarını okumasına izin vermeyeceğiniz her şey için — Sandbox.create() kullanın; bu, her iş yüküne kendi VM'sini verir. Belirli eksiklikler için Bilinen kısıtlamalar bölümüne bakın.
Tipik bir RL rollout veya araç çalıştırma kum havuzu, birkaç saniye için birkaç MB RAM ve bir çekirdek gerektirir. Her biri için 2 vCPU'lu bir sanal makine ödemek ve 6 saniyelik bir soğuk başlatma tetiklemek — ve üstelik 1000 VM'lik bir zamanlama patlamasına neden olmak — yanlış bir takastır. Bu nedenle SandboxPool, bir Job'u bir ana bilgisayar olarak çalıştırır ve içinde birçok kum havuzunu çoklayıcı (multiplex) olarak yönetir.
Bir havuzlanmış sandbox, iç içe geçmiş bir sanal makine veya konteyner değildir. Klasik Unix çok kullanıcılı ilkesidir:
- a özel uid (≥ 20000),
- o uid'ye ait, özel
0700bir ev, - komutları,
execile o uid altında, temizlenmiş bir ortamda (env_clear, böylece ana makinenin gizli bilgileri asla sızdırılmaz),NO_NEW_PRIVS, işlem başına rlimits ve kum havuzu başına Landlock kuralları seti ile çalıştırılır.
Dolayısıyla bir sandbox oluşturmak mkdir + chown + build ruleset ≈ 1ms sunucu tarafı — ikinci bir VM açılışı yok. İstemci tarafında görülen tek gecikme, proxy gidiş-dönüşüdür.
Bir havuzlanmış sandbox’un genel kimliği <host_job_id>.<local_id> olduğundan, connect/exec/kill adanmış olanlarda olduğu gibi durum bağımsız çalışır. Havuzlanmış bir sandbox üzerinde kill() çağrısı, ana makineye bir DELETE gönderir (bir yeri boşaltır); ana makine çalışmaya devam eder.
Havuzda izolasyon: uid + Landlock
Bu, havuz tasarımının özüdür; bu nedenle, neyin ve neyin yalıtılmadığı konusunda kesin olmak önemlidir.
Standart bir Job, yalnızca 0..65535 aralığındaki uid'leri eşleyen bir kullanıcı ad alanı içinde, seccomp filtresi etkin ve CAP_SYS_ADMIN / CAP_NET_ADMIN / CAP_NET_RAW yetkileri olmadan root olarak çalışır. Bu durum, yaygın ağır ağırlıklı yalıtım araçlarını dışlar: iç içe ad alanları, yeni bağlamalar ve cgroup devri yoktur (unshare, mount, /sys/fs/cgroup/... dizinine yazma işlemleri başarısız olur). Çekirdeğin sunduğu ise Landlock'tur (ABI 6); bu, herhangi bir ayrıcalıksız sürecin kendini ve alt süreçlerini kısıtlayabilmesini sağlayan bir Linux Güvenlik Modülüdür — tam da her kum havuzu için gereken sınır. Sunucu, her kum havuzu için bir kurallar kümesi oluşturur; exec alt süreci, komutu çalıştırmadan önce kum havuzu uid/gid değerlerine düşer ve NO_NEW_PRIVS, landlock_restrict_self ile rlimit'leri uygular.
Farklı uid'lerin (keyfi erişim denetimi) Landlock ile birleştirilmesi, şunları sağlamak üzere tasarlanmış ve test edilmiştir:
- ✅ A, başka bir sürecin
environdeğerlerini okuyamaz; bu da kum havuzları arasında HF ve kum havuzu belirteçlerine doğrudan erişimi engeller. - ✅ A, B'nin süreçlerini
SIGKILL/ptraceile durduramaz veya belleklerini okuyamaz, B'yesetuidyapamaz ya da B'nin0700ana dizinini okuyamaz. - ✅
/tmpve/dev/shmerişimi reddedilir — her kum havuzu, kendi ana dizinine (Landlock ile) kısıtlanmıştır (TMPDIR,$HOMEiçindeye işaret eder). - ✅ A, bir TCP portuna
bindedemez, bu nedenle sandboxlar arası bir localhost hizmeti yoktur (gidenconnectizinli kalmaya devam eder, bu yüzden internet çalışır). - ✅ Kumdanlar arası soyut unix soketleri engellenir (
LANDLOCK_SCOPED_ABSTRACT_UNIX_SOCKET; yalnızca uid izolasyonu bunları engellemez).
Bu kontroller iş yükünü kısıtlar. Kök kontrol düzlemi ayrı bir güven sınırı olarak kalır: host modundaki dosya işlemleri sembolik bağlantıları reddeder, soket vekili soket inode'unu sabitler ve akran uid'sini kontrol eder, ayrıca özel rotalar host modunda kullanılamaz. Kalan paylaşılan kanallar Bilinen kısıtlamalar bölümünde açıklanmıştır.
Bunun bir sanal makinenin yerini tutmamasının nedeni. Landlock ve uid izolasyonu, aynı güven sınırındaki iş yükleri için tasarlanmıştır. Havuzlanmış kum havuzları bir çekirdeği, bir sanal makineyi ve bir kontrol düzlemini paylaştığı için, kum havuzu içi her saldırıdan koruma garanti edilmez; kaynaklar ve bazı süreç listesi meta verileri de paylaşılmaya devam eder. Karşılıklı olarak güvensiz kodlar için veya GPU için, her kum havuzuna kendi sanal makinesini veren Sandbox.create() kullanın.
Bir havuzdaki model dosyası
Birleştirilmiş bir sandbox’ın tek yazılabilir alanı, Landlock ile sınırlandırılmış ev dizini olduğundan (bu aynı zamanda varsayılan çalışma dizinidir), dosya API’si tüm yolları bu ev dizinine kökler: files.write("data/in.txt", ...) $HOME/data/in.txt konumuna yazar, baştaki / ev dizinine göre göreli olarak yorumlanır ve .. ile bu dizinin dışına çıkılamaz. API üzerinden yazılan dosyalar, sandbox’ın kendi kodunun bunları okuyabilmesi için sandbox’ın uid’sine chown edilir. Bu, sandbox içindeki kodun erişebildiği şeylerle tam olarak örtüşen, “sandbox’a köklenmiş dosya sistemi” modelini sağlar — ve konteyner dosya sisteminde yolların mutlak olduğu adanmış sandbox’lardan farklıdır.
Yollar sözlüksel olarak normalize edilir, ardından her bileşende sembolik bağlantı reddi ile açık bir ana dizin betiğine göre çözümlenir. Dosya API'si, aynı ana dizin içindeki bağlantılar dahil olmak üzere sembolik bağlantıları izlemez; sandbox kodu bunları yine de kendi Landlock kuralları altında kullanabilir.
Pools'un yetkili bir yerel durumu yoktur
Bir havuz, bilinçli olarak yerel bir yapılandırma dosyası değildir. Bir havuz, hepsi hf-sandbox-pool=<id> etiketini paylaşan çalışan host İşleri kümesidir. Bu, havuzların sandbox API'sinin geri kalanıyla tutarlı kalmasını sağlar (her şey etiketlerden keşfedilebilir ve herhangi bir makineden yeniden bağlanılabilir) ve bir havuzun, son hostu ortadan kalktığında var olmaktan çıktığı anlamına gelir.
- Bir host, havuzun yapılandırmasını (image, flavor,
sandboxes_per_host, boşta kalma zaman aşımı) iş ortam değişkenlerinde taşır — etiketler yalnızca filtreleme için kullanılır. Bir istemcinin yinelenmiş bir host başlatması gerektiğinde, bu yapılandırmayı çalışan bir hosttan (inspect_job) geri okur; böylece havuzdaki tüm hostlar merkezi bir kayıt olmadan tutarlı kalır. - Env ve secrets her sandbox için geçerlidir ve oluşturulma sırasında iletilir — asla havuz düzeyinde değil. Havuzlanmış bir sandbox’ın ortamı, sandbox’ın yaşam süresi boyunca ana sunucunun belleğinde tutulur (çalıştırdığınız her komuta yeniden uygulanır); diske asla yazılmaz ve hiçbir Job’un metadata’sında asla görünmez. Havuzlanmış sandbox’lar için şifreli-secrets kanalı yoktur —
envkullanın ve bu değerleri “diskte değil, ama şifreli de değil” olarak değerlendirin. Şifreli depoya ihtiyaç duyan değerler için, ayrılmış bir sandbox’ınsecretsalanını kullanın. - Kapasite sunucu tarafından belirlenir. Bir ana bilgisayar,
sandboxes_per_hostsınırını aşan oluşturma isteklerini reddeder ({"rejected": N}yanıtı verir); istemci, taşan kısımları başka bir ana bilgisayara yerleştirir veya bir kopya başlatır. Bu sayede birden fazla süreç aynı havuza eşzamanlı olarak oluşturma yaptığında bile yerleştirme işlemi tam olarak korunur. - Boşta atma iki kademelidir. Her kum havuzu, kendi
idle_timeoutsüresince pasif kaldığında atılır (hâlâ çalışan bir süreci yoksa); bir ana bilgisayar, ana bilgisayar boşta kalma zaman aşımında kum havuzu içermediğinde kendini kapatır — bu, tüm istemciler kaybolursa bile bir faturalama güvencesidir.
En iyi çaba (best-effort) önbelleği, create --pool komutunun hızlı çalışmasını sağlar
Yetkili bir yerel durum olmaması doğruluk açısından harika olsa da gecikme maliyeti taşır. Soğuk bir hf sandbox create --pool <id> (yeni bir CLI süreci) aksi takdirde bir sandbox oluşturmadan önce her şeyi ağ üzerinden yeniden keşfetmek zorunda kalırdı: ad alanını taramak için list_jobs → URL ve nonce'ını yeniden oluşturmak için her host'u inspect_job ile denetleme → her birinin ne kadar dolu olduğunu görmek için GET /v1/sandboxes → son olarak oluşturmak için POST. Her çağrıda, saf bir yük olarak birkaç gidiş-dönüş.
$HF_HOME/sandbox/pools/<context>/<pool-id>.json konumundaki en iyi çaba (best-effort) önbelleği bunu ortadan kaldırır. Herhangi bir oluşturma/isınma (create/warm) işleminden sonra, bir süreç havuz yapılandırmasını ve her ana bilgisayar için vekil (proxy) URL'sini, kimlik doğrulama nonce değerini ve son görülen boş slotları kaydeder. Bir sonraki süreç, ana bilgisayar taşıma katmanını (host transport) doğrudan dosyadan yeniden oluşturur (HTTP olmadan) ve doğrudan POST isteğine geçer.
<context>, kaydın yazıldığı uç noktanın, kimlik bilgisinin ve ad alanının bir özeti olarak işlev görür — kimlik bilgisi bir parmak izi olarak; token'ınızın kendisi asla önbelleğe yazılmaz. Hem dizin adı hem de dosya bu özeti taşır ve üç öğenin tamamıyla eşleşmeyen bir okuma basit bir önbellek kaçışıdır; böylece makinenin başka bir kullanıcısı, başka bir uç nokta veya connect(pool, namespace="other-org"), başka bir şey için önbelleğe alınmış host'lar yerine soğuk yolu alır. Dosyalar 0600, dizinler 0700 olarak oluşturulur.
Önbelleğin güvenilir olduğu ve olmadığı durumlar:
- Kapasite konusunda yetkili değildir. İş içi sunucu yetkili olmaya devam eder, bu nedenle eski bir
livesayısı yalnızca boşa giden bir istek maliyeti yaratır, asla yanlış paketlenmiş bir ana makineye yol açmaz. - Host'un nerede barındığı konusunda güvenilir değildir. Önbelleğe alınmış bir URL, yalnızca aynı girdinin adını taşıdığı işin HTTPS jobs-proxy URL'si olması durumunda kullanılır; bu nedenle bir önbellek dosyası, HF bearer ve sandbox token'larınızın gönderileceği hedefi seçemez; başka bir şeyi adlandıran bir girdi dosyadan düşürülür. 15 dakikadan sonra bir girdi tek başına da geçerli sayılmaz:
inspect_job, taşıma oluşturulmadan önce işin hâlâ çalıştığını, bu havuz için hâlâ etiketlendiğini ve hâlâ o URL'de olduğunu doğrulamalıdır. - Şekli nedeniyle güvenilir değil. Tipler ve aralıklar okuma sırasında kontrol edilir, bu nedenle elle düzenlenmiş, kısaltılmış veya string tabanlı bir dosya,
create()işleminin ortasında bir hata yerine bir önbellek kaçağı olarak ele alınır. - Kendini onarma. Kaybolan önbelleğe alınmış bir ana makine, ilk başarısız istekle düşürülür ve dosyadan budanır; oluşturma işlemi şeffaf şekilde etiket keşfine geri döner.
- Eşzamanlılık güvenli. Yazma işlemleri bir dosya kilidi altında (anahtar olarak
job_idkullanılarak) birleştirilir ve atomik olarak taahhüt edilir; böylece paralelcreatesüreçleri birbirinin üzerine yazmaz ve okuyucular asla yarı yazılmış bir dosya görmez. - Atılabilir. Silerseniz bir önbellek kaçışı (cache miss) oluşur: soğuk yol (cold path) çalışır ve her şey yine de sorunsuz çalışır. Hiçbir zaman makineler arasında paylaşılmaz.
İki noktaya dikkat edin. $HF_HOME değerini hassas olarak ele alın: bir kayıt, yine de yeniden kullanılabilir bir ana bilgisayar URL'si ve bu URL'den türetilen herkese açık nonce'tan oluşur; farklı bir kimlik bilgisiyle yazılmış bir dosya yok sayılırken, sizin kimlik bilginizle yazılmış bir dosya, yukarıdaki 15 dakikalık pencere için geçerli sayılır. Ayrıca ad alanı (namespace) anahtarın bir parçası olduğu için, açık bir namespace= değeriyle önbelleğe alınmış bir havuz, yalnızca aynı namespace= değeri iletildiğinde yeniden bulunur — hf sandbox create --pool <id> komutu, havuzun oluşturulduğu --namespace değerini ister; aksi takdirde soğuk yolu (cold path) izler ve kendi ad alanınızda arar.
Bilinen kısıtlamalar
Pools, tek bir güven sınırı içindeki iş yükleri içindir. Güvenmediğiniz kod için ayrılmış kum havuzları kullanın. Aşağıdaki kontroller belirli riskleri azaltır; havuzlanmış kum havuzlarını ayrı sanal makinelere dönüştürmez.
Bir bakışta tehdit modeli
| Actor | Ayrılmış | Havuz |
|---|---|---|
| Anonim internet kullanıcısı | Jobs vekili, namespace okuma erişimine sahip bir HF jetonu gerektirir. | Aynı. |
| Okuma erişimine sahip namespace üyesi | Vekil sunucuya ve genel sağlık kontrolüne erişilebilir, ancak API işlemleri için kum havuzu belirteci gereklidir. | Aynı. |
| İşler oluşturabilen ad alanı üyesi | Bir kullanıcının jetonunu, onun nonce değerinden türetilemez. | Kopya havuz etiketlerini kopyalayabilir, ancak varsayılan kabul, İşler API’sinin başlatıcısını kontrol eder. adopt_hosts="namespace" diğer oluşturuculara güvenmeyi seçer. |
| Sandbox'ta çalışan kod | VM içindeki sunucuyla kök dizini paylaşır; bu VM'yi güven sınırları arasında yeniden kullanmayın. | uid ve Landlock ile sınırlandırılmıştır, ancak çekirdeği, sanal makineyi ve ayrıcalıklı kontrol düzlemini paylaşır. |
| Müşteriniz | HF ve özel kum havuzu kimlik bilgilerini tutar. | Ana bilgisayar yönetim kimlik bilgilerini ve kum havuzu başına ayrı yetenekleri içerir. |
Yalıtım ve kaynak boşlukları
- Host keşfi, onaylama (attestation) değildir. Varsayılan
adopt_hosts="own"başlatıcıyı, görüntüyü, flavor'ı, komutu ve maruz bırakılan URL'yi kontrol eder. Çalışan ikiliyi onaylamaz veya değiştirilebilir bir görüntüyü güvenilir kılmaz.adopt_hosts="namespace"değerini yalnızca güvendiğiniz namespace üyeleriyle kullanın. - Host kimlik bilgileri güçlü kalmaya devam eder. Havuzu yönetir ve her kum havuzunun jetonunu geri alır. Bu istemci tarafından eksik kapsamlı jetonların yerine asla geçirilmez. Bu sürüm tarafından başlatılan hostlar, kapsamlı yollarda bunları reddeden sbx-server 0.7.0 sürümünü çalıştırır; eski istemciler tarafından başlatılan hostlar ise geri dönüştürülene kadar sunucularını (ve host-jeton uyumluluğunu) korur.
- Paylaşılan kanallar korunur. Giden TCP, kontrol sunucusuna döngü içi erişim, UDP, çekirdek IPC ve okunabilir süreç listesi meta verileri yalıtılmaz. Sistem dizinleri ve seçili cihaz düğümleri erişilebilir kalmaya devam eder. GPU havuzu yalıtımı test edilmemiştir; GPU için ayrılmış modu kullanın.
- Sınırlar, toplam kota değildir. İşlem başına rlimit'ler ve sınırlı çıktı kuyrukları, kaynak amplifikasyonunu azaltır. CPU paylarını, toplam belleği, disk alanını, inode'ları veya ağ kapasitesini sandbox'lar arasında bölmezler. Dizin sayfalama, yanıtları sınırlar ancak dizini yine de sunucuda oluşturur. API dosya yazmaları bir disk kotası değildir ve özel dosyalara yönelik dedicated-mode yazmaları bloklanabilir.
- Kısıtlama açıkça zayıflatılabilir. Host modu varsayılan olarak Landlock ABI 6 gerektirir ve başarısız bir kurallar kümesini reddeder.
SBX_MIN_LANDLOCK_ABIdeğerini düşürmek veya sunucunun--allow-unconfinedgeliştirme bayrağını kullanmak daha az garanti kabul eder; etkin ABI ve özellikler için kimliği doğrulanmış/healthuç noktasını inceleyin. - Proxy bağlantıları yalnızca bir kez kimlik doğrulanır. İlk istekten sonra, proxy, EOF'a kadar baytları o arka uca kopyalar. O bağlantıdaki sonraki HTTP istekleri bağımsız olarak kimlik doğrulanmaz veya yönlendirilmez. WebSocket/SSE uyumluluğu, üst akış bağlantı yeniden kullanımına karşı güvenlik sağlamaz.
Yaşam döngüsü ve kimlik bilgileri
- Ayrıştırılmış torunlar, süreç sonlandırmasından veya zaman aşımından sonra hayatta kalabilir. Her ikisi de süreç grubuna sinyal gönderir;
setsid()çağıran bir torun bu gruptan kaçar. Tüm iş yükünü sonlandırmak için havuzdaki kum havuzunu silin veya ayrılmış Job'ı sonlandırın. max_hostsen iyi çaba (best-effort) esasına dayanır. Farklı istemciler aynı ana bilgisayarları sayabilir ve her ikisi de daha fazla kaynak tahsis edebilir. Sert bir ortak sınır için arka uç kabulü veya idempotensi (tekrarlanabilirlik) gereklidir.- Teardown başarısız olabilir. Başarısız host iptalleri cache kayıtlarını yükseltir ve korur.
close(), devam eden oluşturmalar için bekleme süresini sınırlar; bu bekleme süresini aşan bir oluşturma, faturalanabilir bir Job bırakabilir. Çalışan kaynakları dengelemek için Jobs API'sini veya CLI'ı kullanın. - Bearer rotation, sandbox yeteneklerini döndürmez. Proxy kimlik doğrulaması, istek başına geçerli HF jetonunu çözer; ancak durumdan bağımsız yeniden bağlanma, tam olarak orijinal bearer değerinden bir host jetonu türetir. Bu değeri döndürmek, mevcut host'lara yeniden bağlanmayı engelleyebilir.
- Yerel önbellek, 15 dakika boyunca güvenilir girdi olarak kalır. URL'si ve güvenlik bağlamı kontrol edilir ancak bütünlük MAC'i yoktur;
$HF_HOME'i güvensiz kodun yazmalarından koruyun. - Özet sabitlemesi (digest pin) imzalı bir menşe kanıtı değildir. İstemci, belirli bir sunucu ikilisini doğrular. Bu sabitlemeyi yayınlamak ve güncellemek hâlâ sürüm adımlarıdır; iş akışının manifesti kriptografik bir onay değildir. Açıkça belirtilen
SBX_ALLOW_UNVERIFIED_SERVER=1kaçış yolu, yalnızca her iki özet aracı da eksik olduğunda doğrulamayı atlar.
Kimlik doğrulamasız /health yalnızca canlılık ve protokolü açığa çıkarır. Ayrıntılı meta veriler için ana bilgisayar kimlik bilgisi gereklidir. Sandbox kimlikleri ve jetonlar çekirdek rastgele kaynağını gerektirir; UID yeniden kullanımı, doğrulanmış süreç ve ana dizin temizliğine göre ilerler.
Performans
Tüm sayılar, istemci bir dizüstü bilgisayarda ve tüm trafiğin Jobs proxy'si üzerinden aktığı koşullarda, gerçek HF Jobs üzerinde cpu-basic ile karşılaştırılarak ölçülmüştür.
Özel kum havuzu:
| metrik | value |
|---|---|
soğuk başlatma (create() döndürür, sunucu yanıt verir) | ~5,8s medyan |
run() gidiş-dönüş | p50 ~110ms (proxy RTT alt sınırı ~105ms; istemci ek maliyeti ≈ 0) |
| dosya aktarımı (paralel aralıklı, >8 MiB) | ~340 MiB/s indirme, ~441 MiB/s yükleme |
Havuz (paylaşılan/host modu):
| N kum havuzu | hostlar (50/host) | provision + tümünü oluştur | tümünde çalıştır | tümünü öldür | toplam |
|---|---|---|---|---|---|
| 100 | 2 | 6.1s | 1.5s | 0.6s | 8.2s |
| 1000 | 20 | 7.4s | 4.2s | 4.2s | 15.8s |
1000 sandbox oluşturuldu, çalıştırıldı ve ~16 sn içinde sonlandırıldı; maliyetleri, hepsine yayılmış tek bir host soğuk başlatma (~6 sn) ile yaklaşık $0.0009 (20 × cpu-basic) iken, sandbox başına bir Job için ~$0.06 ve 1000 VM zamanlama patlaması gerektirirdi. Sunucu tarafındaki oluşturma/çalıştırma/silme işlemlerinin her biri ~1 ms sürer; bütçenin tamamı ağ gidiş-dönüş süresidir.
Tasarım kararları, özet
| karar | neden |
|---|---|
| Jobs üzerine inşa edin, yeni servis yok | faturalama, donanım ve izinleri devralır; herhangi bir görüntüde çalışır |
| Başlangıçta indirilen statik Rust ikili dosyası | Python/pip yok; pip tabanlı bir başlangıç için 30–90 sn'ye kıyasla ~6 sn soğuk başlatma |
| El yapımı HTTP/1.1 | minimal frameworkler tamponlu parçalı yanıtları işler ve canlı yayını bozar (doğrulandı) |
| Durumsuz HMAC kimlik doğrulama | her yerden yeniden bağlanın; HF token'ının kendisi yerine türetilmiş bir token (iş başına kapsamlandırılmış — bkz. Token kapsamı) |
run(), sıfır olmayan çıkış durumunda hata fırlatır (check=False ile bu davranış devre dışı bırakılır) | “kod çalıştır, hatayı gör” döngüleri için en iyi DX (E2B tarzı) |
istemci tarafı temizleme yerine idle_timeout bekçi süreci | kalıcı kum havuzları bir özelliktir; sızanlar yine de sonlanır |
| Pools = uid + Landlock, sunucu yetkili kapasite, yerel durum yok | hızlı aynı-kullanıcı dağıtımı; eşzamanlılık altında doğru; her yerde yeniden bağlanabilir |