Blog
Hvilke kunder har faktisk brug for deres egen VM? En trinbaseret Docker-isoleringsplan
VM til hver kunde er overdrevet. Her er hvordan du beslutter, hvor meget isolation hver lejer har brug for – og automatiserer beslutningen.
Resumé
Agenturer går ofte i panik, når en kunde spørger, hvor virkelig isoleret deres data er fra andre lejere. Docker's namespaces og cgroups giver dig reel isolation, men de er ikke det samme som en hardware-grænse. I stedet for at køre hver kunde på en VM—eller værre, behandle alle kunder ens—skal du opbygge et lille sæt af isolationstrin og matche hver kunde til et trin baseret på datafølsomhed, tillid og overholdelse. En låst container (non-root, fjernede capabilities, seccomp, read-only rod) dækker de fleste sider; regulerede eller fjendtlige arbejdsbelastninger får en VM eller en container-i-VM-hybrid. Dette indlæg giver en gentagelig beslutningsproces, en sammenligningstabel og et ærligt kig på, hvornår mere isolation er overkill.
Er du på det punkt i et salgsopkald, hvor den nye kunde siger “vi er i sundhedssektoren, vis mig, at vores data er isoleret fra dine andre kunder”, og du hellere vil tale om noget andet?
Dette er agenturproblemet: ikke én perfekt implementering, men den samme pålidelige implementering gentaget på tværs af et dusin kunder med forskellige budgetter, risikoprofiler og overholdelseskrav. Her er den ærlige version. Docker-isolation er reel, men den er specifik. Namespaces giver hver container sin egen visning af processer, netværk og filsystem; cgroups begrænser CPU, hukommelse og disk I/O, så lejere ikke kan sulte hinanden. Det, det ikke giver dig, er en hardware-væg mellem containeren og host-kernen. Hvis en angriber undslipper containeren, er de inde i den eneste kerne, du har. Resten af denne artikel forvandler den ubehagelige kendsgerning til en gentagelig beslutning: klassificér hver kunde efter datafølsomhed og tillid, anvend en baseline-hærdningsprofil, og ræk kun efter en VM, når omkostningen ved et brud er højere end omkostningen ved VM'en.
Vent, er containere ikke allerede isolerede?
Docker kører på Linux-namespaces og cgroups, og de ord gør et reelt stykke arbejde. Namespaces adskiller proces-ID'er, netværksstakke, monteringspunkter og brugere, så en proces i én container ikke kan se processtabellen for en anden. Cgroups sætter grænser: giv en container 0,5 CPU, 512 MB hukommelse og en fast blok-I/O-vægt, og det er præcis, hvad den får. En løbsk loop i én lejer bliver droslet ned i stedet for at tage naboen med ned. Hvis du ikke har konfigureret grænser, har du sprunget det mest basale over, som cgroups er til for.
Tag en simpel PHP-app i container A. Den ser sit eget filsystem, sin egen netværksgrænseflade, sin egen PID 1. Container B har det samme, men en anden visning. Det er namespaces. Gå nu væk og spring hukommelsesgrænsen over: container A kan fylde værtens RAM og få container B til at gå i sneglefart. Det er det, cgroups skal forhindre. Men to containere kan være isolerede fra hinanden via namespaces og stadig dele værtens kerne, hvilket er den del, hver container-escape-historie handler om. Et exploit, der når kernen, kan potentielt nå alle lejere på den vært.
“Docker er isoleret” er en halvrigtig sætning. Den præcise version er “Docker isolerer med namespaces og cgroups, og en kernel-sårbarhed er sprængradius.” Før du stoler på, at en lejer kører upålidelig kode, så sid et minut med den tanke. Svaret er ikke “brug aldrig containere”—det er den nemme panik. Svaret er et trinsystem.
Så hvorfor har nogle kunder brug for mere end namespaces?
Det ærlige svar er, at isolation ikke er en kontakt, det er et spektrum. I den ene ende har du en fuldt delt container, hvor alle reelt er i én app. I den anden ende har du en separat VM pr. lejer med sin egen kerne. Det meste agenturarbejde lever i det ubehagelige midterfelt, og midten er ikke et binært valg mellem “Docker er fint” og “kør en VM for alle.”
Det, der skubber en kunde til højre, er ikke deres størrelse. Det er fire spørgsmål:
- Opbevarer de regulerede data? Sundhedsjournaler, betalingskortoplysninger, alt hvad en tilsynsmyndighed vil kalde følsomt.
- Har et brud på deres lejer en realistisk vej til en anden lejer? Hvis de kan køre vilkårlig kode, så ja.
- Stoler du på koden og de mennesker, der implementerer den? En kunde, der hyrer den billigste freelancer, er ikke samme tillidsniveau som en kunde, hvis udviklerteam du kender.
- Siger deres kontrakt “dedikeret,” “isoleret” eller “privat”? Hvis den gør, har du allerede lovet et trin; den eneste opgave nu er at vælge det rigtige.
Hvis du ikke kan besvare de spørgsmål endnu, så placér kunden i et baseline-trin og skriv antagelserne ned. Det er ikke en sikkerhedsrevision; det er en sundhedstjek, du gentager ved hver onboarding.
Hvordan beslutter jeg pr. kunde uden at køre en sikkerhedsrevision hver gang?
Lav en lille tabel og hold dig til den. Du behøver ikke en matrix med fyrre celler. Fire trin dækker næsten enhver kunde, et agentur ser.
| Kundens position | Hvad adskiller dem faktisk | Brug når |
|---|---|---|
| Trin 1: Delt app/container | Kun applikationslogik | Interne værktøjer, lavrisikodata, projekter, hvor alle eksplicit er i ét loginsystem |
| Trin 2: Samme vært, separate containere | Namespaces og cgroups | De fleste marketingssider, kontaktformularer, ingen følsomme data |
| Trin 3: Låst container | Trin 2 + non-root, fjernede capabilities, seccomp, read-only rod, netværkssegmentering | E-handel, PII, brugerdefineret kode, du ikke fuldt ud stoler på |
| Trin 4: VM pr. lejer | Hypervisor og en separat kerne | Sundhed, finans, overholdelsespapirarbejde, upålidelig kode, støjende naboer |
Her er hvordan det fungerer i praksis. En bagerkunde med en kontaktformular og et Instagram-link går til Trin 2: én container på en delt vært, standard Docker-netværk, ressourcebegrænsninger, arbejde udført. En netbutik, der gemmer kundenavne, adresser og betalingsomdirigeringer, går til Trin 3: samme delte vært, men containeren kører som en non-root-bruger, har ingen ekstra kernecapabilities, bruger en seccomp-profil og eksponerer kun port 443. En medicinsk indtagelsesportal, der gemmer beskyttede sundhedsoplysninger, går til Trin 4: en VM pr. lejer, fordi omkostningen ved et brud ikke er “vi rydder op” men “vi kan ikke vise kunden, at vi tog dem alvorligt.”
Hele tricket er, at du ikke gentænker arkitekturen for hver kunde. Du vælger en række fra en tabel, I allerede er blevet enige om. Sådan kan et fem-personers agentur køre hundrede sider uden hundrede separate sikkerhedsbesættelser. Det betyder også, at den næste kunde ikke får et svar, der afhænger af, hvilket teammedlem der tog telefonen. For den dybere arkitekturdebat bag de valg dækker denne guide til design af multi-tenant-isolationsniveauer afvejningerne mere detaljeret.
Hvordan ser en låst container faktisk ud?
Lad os holde op med at sige “låst ned” og blive konkrete. Dette er, hvad Trin 3 betyder for en typisk WordPress- eller PHP-kunde.
Først skal du ændre brugeren. De fleste officielle images kører stadig som root som standard; i din Dockerfile skal du oprette en non-root-bruger og køre appen som den bruger. Det fjerner med det samme den mest almindelige måde, hvorpå en container-kompromittering bliver en vært-kompromittering. For det andet skal du fjerne de capabilities, du ikke har brug for. Kør med --cap-drop ALL og tilføj kun én tilbage, normalt NET_BIND_SERVICE, så appen kan lytte på port 80. Alene det er en større ændring, end de fleste forventer. For det tredje skal du gøre rodfilsystemet skrivebeskyttet med --read-only og montere skrivbare mapper (uploads, database-data-mappen) som volumes eller tmpfs. For det fjerde skal du anvende en seccomp-profil og, hvis din vært understøtter det, AppArmor eller SELinux. Til sidst skal du placere containeren på et dedikeret Docker-netværk og eksponere kun de porte, der faktisk skal kunne nås.
Lad os gennemgå et WordPress-eksempel. Basisimagen kører sandsynligvis som root, så du tilføjer et useradd-trin og en USER-direktiv. Du kører containeren med en hukommelsesgrænse og en CPU-grænse, så et udbrud af plugin-trafik ikke skader naboen. Du monterer /var/www/html/wp-content/uploads som en skrivbar volume. Du sætter --read-only. Du forbinder den til et netværk, der ikke har noget --privileged-flag i nærheden. Resultatet er en container, der plejede at være “et WordPress-site” og nu er “et WordPress-site, der tilfældigvis er mere låst ned end de fleste virtuelle private servere.”
Hvis det føles skrøbeligt at gøre alt det manuelt, er der en lettere mellemvej: Docker's Enhanced Container Isolation, som bruger user namespace-isolation og en sikker container-runtime. Det er en legitim genvej, men det er ikke et frikort til at springe non-root eller capability-fjernelse over. Lejeren har stadig brug for et fornuftigt image. Forskellen er, at den kerne-vendte angrebsflade bliver mindre, uden at du bliver seccomp-ekspert fra den ene dag til den anden. Hvis du vil have den nøjagtige sekvens for en enkelt lejer, gør trin-for-trin-guiden til isolation-hærdning dette afsnit til copy-paste-kommandoer.
Hvornår stopper jeg med at lægge lag og giver dem bare en VM?
Her er den kontrære del: mere isolation er ikke automatisk bedre. VM'er giver dig isolation på hardwareniveau, en separat kerne og en meget mindre angrebsflade, hvis gæstekernen falder. Det er præcis, hvad sundheds- og finansklienter forventer, når de siger “vi vil være isolerede.” Men hver VM tilføjer patching-, backup- og beregningsomkostninger, og det multiplicerer arbejdet med at holde en flåde opdateret. Hvis du laver en VM for hver kunde, fordi én kunde engang sagde, at Docker skræmte dem, har du købt sikkerhedsteater med rigtige penge.
En VM er det rigtige svar, når risikoen pr. lejer er højere end de operationelle omkostninger ved en VM pr. lejer. Det betyder regulerede data, skriftlige overholdelseskrav, upålidelig tredjepartskode eller en kunde, der har brug for at få en støjende nabo fjernet. Det er også det rigtige svar, når kundens kontrakt bogstaveligt talt lover et dedikeret miljø, fordi “container” ikke er det, de forestiller sig, når de skriver under på “dedikeret.”
Men en VM undskylder ikke en sjusket container. En almindelig fælde er at placere kunden i en VM og derefter springe hærdningen over, fordi “VM'en beskytter dem.” VM'en beskytter værten mod lejeren, ikke lejeren mod sit eget dårlige image. Du vil stadig have non-root, fjernede capabilities og seccomp inde i den VM. Hybridtilgangen—containere inde i en VM—er ofte det søde punkt: VM'en giver grænsen til overholdelsessamtaler, og containeren giver dig den implementeringsarbejdsgang, du allerede kender. Der er en længere version af den debat i Skal hver lejer have sin egen VM?, men det korte svar er, at VM'en er til kontrakten, ikke til frygten.
Hvordan gør jeg dette gentageligt på tværs af hver kunde?
Du gør det gentageligt ved at gøre trinsystemet til en skabelon, ikke en hukommelse. Hold en mappe med Compose-filer, én pr. trin: tier2-baseline, tier3-locked, tier4-vm-hybrid. Når en ny kunde dukker op, skal du kopiere skabelonen, ændre miljøvariablerne, og du kender allerede isolationsformen, før du har skrevet en linje ny infrastruktur.
Skriv derefter beslutningen ned. Ikke en 400-siders sikkerhedsrapport, men et kort afsnit i kundens repository: hvilke data de opbevarer, hvilket trin de er på, hvorfor, og hvad der ville flytte dem op et trin. Det afsnit er mere værd end hundrede firewall-regler, fordi det er det, du kan vise den næste revisor eller den næste bekymrede kunde. Det forhindrer dig også i at skulle huske, hvorfor bageren fik Trin 2 og e-handelsbutikken fik Trin 3, efter det oprindelige salgsopkald er falmet.
Automatisér de kedelige kontroller. Lad din CI scanne hvert kundeimage og fejle en build, hvis det kører som root, hvis det har alle capabilities, eller hvis det forsøger at publicere en anden port end dem, trinnet tillader. Intet af det er eksotisk; det handler bare om at sikre, at skabelonen ikke utilsigtet bliver brudt af en velmenende udvikler. Hvis du alligevel bygger den omkringliggende hosting-arbejdsgang, dækker produktionsklar Docker-hostingstrategier-artiklen den del, der kommer efter, at containerne er defineret.
Intet af dette er glamourøst. Ingen blogpost vil få “lejerisolation” til at lyde så spændende som et greenfield-arkitekturdiagram. Men det er forskellen mellem et agentur, der svarer “hvor isolerede er vi?” med fingrene krydsede “helt” og et, der kan vise et trin, en konfiguration og en grund. Containere er ikke en magisk mur. VM'er er ikke en magisk kugle. Et trinsystem er bare en beslutning, du skriver ned og genbruger—og for et agentur er gentagelighed hele spillet.

