Master chroot: Enkel guide til Linux-isolasjon

Chroot-kommandoen gir deg muligheten til å isolere utviklings- og testmiljøer, og øker systemets sikkerhet. Vi skal se på den mest brukervennlige måten å bruke den på.

Hva innebærer en chroot?

Vurderingen av en kommando baseres på dens funksjonalitet kombinert med brukervennlighet. Hvis en funksjon er for vanskelig å bruke eller for tidkrevende, vil den reelle nytten være minimal. En funksjon som ikke blir brukt, har ingen verdi.

Erfaringer fra diskusjoner med Linux-brukere indikerer at chroot-kommandoen ofte oppfattes som komplisert og kjedelig å konfigurere. Det virker som om dette nyttige verktøyet ikke blir brukt i så stor grad som det burde.

Med chroot kan man etablere og kjøre programmer eller interaktive skall, som Bash, i et isolert filsystem. Dette hindrer programmet i å samhandle med det vanlige filsystemet. Alt i chroot-miljøet er innkapslet og begrenset. Ingenting i chroot-miljøet kan få tilgang utenfor den spesifikke rotkatalogen uten å eskalere til root-privilegier. Dette har gitt chroot-miljøet kallenavnet «chroot-fengsel». Begrepet «fengsel» skal ikke forveksles med FreeBSD sin jail-kommando, som etablerer et chroot-miljø som er mer sikkert enn et ordinært chroot-miljø.

Det finnes en enkel og effektiv måte å bruke chroot på, som vi skal utforske. Vi vil bruke standard Linux-kommandoer som fungerer på de fleste distribusjoner. Noen distribusjoner har egne verktøy for å sette opp chroot-miljøer, som debootstrap for Ubuntu, men vi vil her fokusere på en distribusjonsuavhengig tilnærming.

Når er det hensiktsmessig å bruke en chroot?

Et chroot-miljø gir en funksjonalitet som ligner på en virtuell maskin, men det er en lettere løsning. Det isolerte systemet krever ikke en hypervisor for installasjon og konfigurering, slik som VirtualBox eller Virtual Machine Manager. Det krever heller ikke en egen kjerne. Det isolerte systemet deler den eksisterende kjernen.

På mange måter er chroot-miljøer mer lik containere som LXC enn virtuelle maskiner. De er lette, raske å distribuere, og opprettelse og start kan automatiseres. Som med containere, er det vanlig å konfigurere dem ved å installere akkurat nok av operativsystemet for å oppnå det som er nødvendig. Hva som er «nødvendig» avhenger av hvordan du har tenkt å bruke chroot-miljøet.

Noen vanlige bruksområder inkluderer:

Programvareutvikling og produktverifisering: Utviklere lager programvare, og et verifiseringsteam (PV) tester den. Noen ganger oppdager PV feil som ikke kan reproduseres på utviklerens maskin. Utvikleren har gjerne installert mange verktøy og biblioteker som den gjennomsnittlige brukeren – og PV – ikke har. Ofte viser det seg at ny programvare som fungerer for utvikleren, men ikke for andre, benytter en ressurs på utviklerens maskin som ikke er inkludert i testversjonen av programvaren. chroot lar utvikleren ha et rent, isolert miljø på maskinen sin der de kan teste programvaren før den gis til PV. Det isolerte miljøet kan konfigureres med minimum avhengigheter som programvaren trenger.

Redusere utviklingsrisiko: Utviklere kan lage et dedikert utviklingsmiljø slik at ingenting som skjer der kan skade den faktiske datamaskinen.

Kjøre utdatert programvare: Noen ganger er det nødvendig å kjøre en eldre versjon av et program. Hvis den gamle programvaren har krav som kolliderer med din nåværende Linux-versjon, kan du bruke et chroot-miljø for å isolere den.

Gjenoppretting og filsystemoppgraderinger: Hvis en Linux-installasjon blir ubrukelig, kan du bruke chroot til å montere det skadde filsystemet til et monteringspunkt på en Live CD. Dette lar deg jobbe med det skadde systemet og prøve å reparere det som om det var normalt montert i root /. Dette innebærer at de forventede filbanene i det skadde systemet refereres korrekt fra rotkatalogen, og ikke fra Live CD-ens monteringspunkt. En lignende teknikk ble brukt i en artikkel som beskrev hvordan man migrerer et Linux-filsystem fra ext2 eller ext3 til ext4.

Isolere applikasjoner: Å kjøre en FTP-server eller en annen internettilkoblet tjeneste i et chroot-miljø begrenser skaden en ekstern angriper kan forårsake. Dette er et viktig tiltak for å forbedre systemsikkerheten.

Hvordan opprette et chroot-miljø

Vi trenger en mappe som skal fungere som rotkatalogen for chroot-miljøet. For å gjøre det enkelt å referere til denne mappen, lager vi en variabel og lagrer mappens navn i den. Her setter vi opp en variabel for å lagre stien til «testroot»-mappen. Det spiller ingen rolle om mappen ikke eksisterer ennå, vi skal lage den snart. Hvis mappen allerede finnes, bør den være tom.

chr=/home/dave/testroot

Hvis mappen ikke eksisterer, må vi opprette den. Dette gjøres med følgende kommando. Alternativet -p (parents) sørger for at eventuelle manglende overordnede mapper opprettes samtidig:

mkdir -p $chr

Nå trenger vi mapper for å lagre delene av operativsystemet som chroot-miljøet trenger. Vi skal sette opp et minimalt Linux-miljø som bruker Bash som interaktivt skall. Vi vil også inkludere touch, rm og ls-kommandoene. Dette vil gi oss tilgang til Bash sine innebygde kommandoer, samt touch, rm og ls. Vi kan dermed opprette, liste og fjerne filer, samt bruke Bash. I dette enkle eksemplet er det alt vi trenger.

Vi bruker en spennutvidelse for å liste opp mappene som skal opprettes:

mkdir -p $chr/{bin,lib,lib64}

Deretter flytter vi til den nye rotkatalogen vår.

cd $chr

La oss kopiere de nødvendige binærfilene fra din vanlige «/bin»-mappe til vår chroot «/bin»-mappe. Alternativet -v (verbose) gjør at cp gir tilbakemelding om hva den gjør mens den kopierer.

cp -v /bin/{bash,touch,ls,rm} $chr

Filene er nå kopiert:

Disse binærfilene har avhengigheter. Vi må finne ut hvilke de er og kopiere disse filene også til vårt miljø, ellers vil ikke bash, touch, rm og ls fungere. Vi må gjøre dette for hver enkelt kommando. Vi begynner med Bash. Kommandoen ldd lister opp avhengighetene.

ldd /bin/bash

Avhengighetene identifiseres og listes i terminalen:

Vi må kopiere disse filene til vårt nye miljø. Å kopiere dem en etter en vil være tidkrevende og feilutsatt.

Heldigvis kan vi automatisere dette delvis. Vi lister opp avhengighetene igjen og danner denne gangen en liste. Deretter går vi gjennom listen og kopierer filene.

Her bruker vi ldd for å liste opp avhengighetene og sender resultatet via en pipe til egrep. Å bruke egrep er det samme som å bruke grep med alternativet -E (utvidede regulære uttrykk). Alternativet -o (only matching) begrenser utdataene til de samsvarende delene av linjene. Vi ser etter samsvarende bibliotekfiler som ender på et tall [0-9].

list="$(ldd /bin/bash | egrep -o '/lib.*.[0-9]')"

Vi kan sjekke innholdet i listen ved hjelp av echo:

echo $list

Nå som vi har listen, kan vi gå gjennom den med en løkke og kopiere filene en etter en. Vi bruker variabelen i for å gå gjennom listen. For hvert element i listen kopierer vi filen til vår chroot-rotkatalog, som er verdien i $chr.

Alternativet -v (verbose) gjør at cp gir tilbakemelding for hver kopi. Alternativet –parents sørger for at eventuelle manglende overordnede mapper blir opprettet i chroot-miljøet.

for i in $list; do cp -v --parents "$i" "${chr}"; done

Her er resultatet:

Vi vil bruke denne teknikken til å finne avhengighetene for hver av de andre kommandoene. Vi bruker løkketeknikken til å utføre selve kopieringen. Det positive er at vi bare trenger å gjøre en liten endring i kommandoen som samler avhengighetene.

Vi kan hente kommandoen fra kommandohistorikken vår ved å trykke på piltast opp noen ganger og deretter gjøre endringene. Kommandoen for loop-kopiering trenger ikke endres.

Her har vi brukt piltast opp for å finne kommandoen, og endret den til å lese touch i stedet for bash.

list="$(ldd /bin/touch | egrep -o '/lib.*.[0-9]')"

Vi kan nå gjenta den samme loop-kommandoen som før:

for i in $list; do cp -v --parents "$i" "${chr}"; done

Og filene er kopiert:

Vi redigerer nå kommandoen for å finne avhengigheter til ls:

list="$(ldd /bin/ls | egrep -o '/lib.*.[0-9]')"

Igjen bruker vi den samme loop-kommandoen. Den bryr seg ikke om hvilke filer som er på listen. Den går blindt gjennom listen og kopierer filene for oss.

for i in $list; do cp -v --parents "$i" "${chr}"; done

Og avhengighetene for ls er kopiert over:

Vi redigerer kommandoen for siste gang, slik at den fungerer for rm:

list="$(ldd /bin/ls | egrep -o '/lib.*.[0-9]')"

Vi bruker loop-kopieringskommandoen for siste gang:

for i in $list; do cp -v --parents "$i" "${chr}"; done

De siste avhengighetene våre kopieres inn i chroot-miljøet. Vi er endelig klare til å bruke chroot-kommandoen. Denne kommandoen setter roten til chroot-miljøet, og spesifiserer hvilket program som skal kjøres som skallet.

sudo chroot $chr /bin/bash

Vårt chroot-miljø er nå aktivt. Terminalvinduet har endret seg, og det interaktive skallet er det som administreres av bash-skallet i vårt miljø.

Vi kan teste ut kommandoene vi har brakt inn i miljøet.

ls
ls /home/dave/Documents

ls-kommandoen fungerer som forventet når vi bruker den i miljøet. Når vi prøver å få tilgang til en mappe utenfor miljøet, feiler kommandoen.

Vi kan bruke touch for å lage en fil, ls for å liste den, og rm for å fjerne den.

touch sample_file.txt
ls
rm sample_file.txt
ls

Vi kan også bruke de innebygde kommandoene som Bash gir. Hvis du skriver hjelp på kommandolinjen, vil Bash liste dem for deg.

help

Bruk exit for å forlate chroot-miljøet:

exit

Hvis du ønsker å fjerne chroot-miljøet, kan du ganske enkelt slette det:

rm -r testroot/

Dette sletter rekursivt alle filene og mappene i chroot-miljøet.

Automatisering for enkelhet

Hvis du ser for deg at chroot-miljøer kan være nyttige for deg, men opplever dem som litt vanskelige å sette opp, husk at du alltid kan redusere arbeidsmengden og risikoen knyttet til repeterende oppgaver ved hjelp av aliaser, funksjoner og skript.