Blogg

Tillitsfeilslutningen: Hvordan vår flerleietaker Docker-oppsett lekket data (og hvordan vi fikset det)

Lær hvordan ett teams naive Docker-oppsett førte til et kryssleietaker-datalekkasje og den lagdelte isolasjonsstrategien som forhindret det.

Sammendrag

Docker-containere er ikke isolert som standard – de deler vertskjernen, og uten bevisst konfigurasjon kan leietakere forstyrre hverandre. Denne artikkelen går gjennom et reelt scenario der en flerleietaker-hostingleverandør oppdaget at kundecontainere kunne få tilgang til hverandres databaser på grunn av delt nettverk og svake sikkerhetsstandardinnstillinger. Vi viser trinn-for-trinn-endringene som fikset bruddet: per-leietaker-brukerdefinerte nettverk, ikke-root-brukere, fjernede kapabiliteter, skrivebeskyttede filsystemer og seccomp-profiler. En vanlig antakelse er at containere iboende gir sterk isolasjon; vi utfordrer dette ved å forklare hvorfor VM-er fortsatt tilbyr en hardere grense og når man bør vurdere en hybrid tilnærming. Konklusjonen understreker at isolasjon er en lagdelt øvelse, ikke en enkelt avkrysningsboks.

Hendelsen: Når containere snakker for mye

Du har satt opp Docker på en enkelt vert for å kjøre flere kunde-nettsteder. Hver kunde har sin egen container – et pent, isolert miljø, ikke sant? Det trodde vi. Helt til en rutinemessig sikkerhetsrevisjon avslørte at Kunde A sin container leste MySQL-socketen til Kunde B sin container på samme vert. De delte det standard bridge-nettverket. Verre var det at containerne kjørte som root, så en angriper som kompromitterte én, kunne tukle med vertens Docker-socket eller en annen containers filsystem. Bruddet var ikke en sofistikert utnyttelse; det var grunnleggende feilkonfigurasjon. Data lekket. Tilliten forsvant.

Feilscenarioet er ikke uvanlig. Mange team antar at Dockers navnerom og cgroups automatisk skiller leietakere, men de undervurderer hvor mange rømningsveier som forblir åpne som standard. Standard bridge-nettverk gir ingen nettverksisolasjon mellom containere. Å kjøre som root gir containeren mer makt enn nødvendig. Og uten eksplisitte ressursgrenser kan en bråkete nabo sulte andre for CPU eller minne.

Trinn 1: Slutt å dele et enkelt nettverk

Vår første fiks var å gi hver leietaker sitt eget brukerdefinerte Docker-nettverk. Dette forhindrer containere fra å nå hverandre med mindre du eksplisitt kobler dem sammen. Vi laget et skript som for hver leietaker spinner opp et dedikert nettverk og fester applikasjonscontaineren til det. Databasecontaineren lever i samme leietakernettverk, men vi la også til et internt nettverk kun for kommunikasjon innad i leietakeren. Ikke mer kryssleietaker-snoking.

Vi isolerte også databasene ved å kjøre dem i separate containere på samme leietakernettverk, med separate datavolumer. Dette sikret at selv om en angriper brøt seg inn i app-containeren, kunne de ikke sniffe databasetrafikk fra en annen leietaker.

For en dypere gjennomgang av nettverksisolasjonsstrategier, se En praktisk Docker-isolasjonssikkerhetssjekkliste for flerleietaker-hosting.

Trinn 2: Fjern unødvendige privilegier

Som standard kjører Docker-containere med et begrenset sett med Linux-kapabiliteter, men de har fortsatt mer enn de fleste applikasjoner trenger. Våre containere kjørte som root, noe som tillot prosesser inne i containeren å utføre handlinger som å montere filsystemer eller endre kjerne parametere. Vi byttet til å kjøre applikasjonen som en ikke-root-bruker inne i containeren (ved å bruke USER-direktivet i Dockerfile) og fjernet alle kapabiliteter unntatt de som er absolutt nødvendige. For en typisk webapp kan det være bare NET_BIND_SERVICE (for binding til porter under 1024) og CHOWN (for å skrive til kataloger). Vi la også til --security-opt no-new-privileges for å forhindre privilegieeskalering.

Dette trinnet alene eliminerte mange vanlige container-escape-vektorer. En angriper som kompromitterer webserveren kan ikke installere pakker, endre systembinærfiler eller få tilgang til vertens Docker-socket fordi prosessen mangler CAP_SYS_ADMIN- eller CAP_DAC_OVERRIDE-kapabilitetene.

Trinn 3: Lås ned filsystemet

Skrivbare filsystemer er en vanlig angrepsflate. Vi gjorde rotfilsystemet skrivebeskyttet (--read-only) for alle containere, og monterte deretter midlertidige filsystemer (tmpfs) for kataloger som trenger skrivetilgang, som /tmp og applikasjonens cache-katalog. Dette forhindrer en angriper fra å endre applikasjonskode eller lagre ondsinnede binærfiler.

I tillegg brukte vi Dockers --mount-alternativ for å bind-monte sensitive kataloger som Docker-socket kun når det er absolutt nødvendig – og aldri på produksjonscontainere. Prinsippet: hvis containeren ikke trenger å skrive til en sti, gjør den skrivebeskyttet.

Trinn 4: Bruk Seccomp- og AppArmor-profiler

Standard seccomp-profiler blokkerer allerede mange farlige systemkall, men vi tilpasset dem ytterligere for å hviteliste kun de systemkallene applikasjonen vår faktisk trenger. Dette er en avveining fordi det krever profilering av applikasjonen. En enklere tilnærming er å bruke Dockers standard seccomp-profil og deretter legge til --security-opt seccomp=sti/til/profil.json hvis du trenger strengere regler. På samme måte kan AppArmor-profiler begrense containerprosesser til spesifikke filstier og kapabiliteter. Vi aktiverte AppArmor og brukte en tilpasset profil som begrenset tilgangen til kun applikasjonens datakataloger.

For en omfattende guide om disse herdingsstegene, se Herdning av Docker-containere for flerleietaker-hosting: En trinn-for-trinn-isolasjonsguide.

Det kontrare synet: Noen ganger trenger du VM-er

Uansett hvor hardet, deler containere vertens kjerne. En kjernesårbarhet kan bryte all isolasjon på en gang. Det er derfor mange sikkerhetsbevisste plattformer kjører containere inne i lette VM-er – hver leietaker får sin egen kjerne. Dette legger til overhead, men gir en maskinvaregrense som containere alene ikke kan. Hvis leietakerne dine håndterer kredittkortdata eller helsejournaler, kan en hybrid tilnærming (containere inne i VM-er) være det riktige valget. Ikke anta at containerisolasjon er tilstrekkelig for trusselen din; evaluer sensitiviteten til dataene og regulatoriske krav.

For en dypere sammenligning av isolasjonsnivåer, les Design av en flerleietaker Docker-arkitektur: Velg riktig isolasjonsnivå.

Konklusjon: Isolasjon er en stabel, ikke en bryter

Fiksen var ikke en enkelt endring – det var lagdeling: nettverksisolasjon, begrensede privilegier, skrivebeskyttede filsystemer og systemkallfiltrering. Selv da aksepterte vi at perfekt isolasjon er umulig med delt-kjerne-containere. For våre høyeste sikkerhetsleietakere flyttet vi dem til dedikerte verter. Lærdommen: stol ikke på noen standardinnstilling. Gjennomgå Docker-oppsettet ditt som om et brudd allerede har skjedd. Tiden for å låse ned er før lekkasjen, ikke etter.

Sources (5)