↓ Naar de hoofdinhoud gaan
Je containers vertrouwen - introductie
  1. Onze blog/

Je containers vertrouwen - introductie

Heb je je ooit afgevraagd of je die Docker-containerimage uit een tutorial of handleiding zomaar blindelings moet draaien? Kun je elke containerimage die je op het internet vindt vertrouwen? Wat als de image die je net hebt gepulld kwaadaardige code bevat? In deze post bespreek ik de risico’s van het blindelings draaien van eender welke containerimage van het internet, en waarom je misschien beter twee keer nadenkt voor je die net gevonden containerimage start.

Hoe werken containers?
#

Voor we ingaan op de risico’s van het draaien van willekeurige containerimages, bekijken we eerst hoe containers werken.

Voor er containers bestonden, gebruikte de cloud virtuele machines (VM) om workloads in de cloud te draaien. Een virtuele machine kun je zien als een virtuele computer op fysieke hardware, en dezelfde fysieke machine (host) kan meerdere virtuele machines draaien. Dat gebeurt door hardware te virtualiseren, en meestal draait er een volledig besturingssysteem (OS) in de VM. De software in de VM (guest) ziet de virtuele hardware en gedraagt zich alsof ze op fysieke hardware draait. Omdat elke VM zijn eigen virtuele hardware heeft, ontstaat er een goede isolatie tussen verschillende workloads. Een (groot) nadeel van VM’s is de aanzienlijke overhead: ze starten traag op en verbruiken veel middelen, zoals CPU en RAM.

Toen de cloud populairder werd, met hogere en meer dynamische belasting, werd duidelijk dat VM’s niet langer zouden volstaan. Wanneer de belasting van een applicatie plots stijgt, moeten er nieuwe VM’s opstarten. Het opstarten van een VM kan in het slechtste geval echter een paar minuten duren. Door die grote overhead moest er een nieuwe oplossing komen. Dat is het moment waarop containers werden geïntroduceerd!

Containers hebben veel minder overhead dan VM’s. Een container kan al in een paar seconden opstarten, met bijna de native prestaties van de fysieke hardware. In vergelijking met een VM gebruikt een container isolatietechnieken in software, in plaats van virtuele hardware te creëren. Meerdere containers delen dezelfde onderliggende kernel (en soms ook bibliotheken) van het host-OS.

In de figuur hieronder zie je het architecturale verschil tussen VM’s en containers. Zoals je ziet, heeft elke VM zijn eigen volledige besturingssysteem, wat overhead toevoegt. Containers daarentegen draaien rechtstreeks op het besturingssysteem van de host en delen de kernel ervan via een container runtime.

Architectuur van containers versus virtuele machines

Om een container te draaien, heb je eerst een containerimage nodig. Een containerimage bevat alle software en afhankelijkheden die nodig zijn om de gebundelde applicatie te draaien. Die bundels volgen doorgaans een industriestandaard, ontwikkeld door het Open Container Initiative (OCI). Met deze image start je een container, en een containerimage kan op meerdere OCI-compatibele runtimes draaien zonder opnieuw te compileren. Als een container runtime OCI-compatibel is, zou die OCI-compatibele containerimages moeten kunnen draaien. Een container runtime is verantwoordelijk voor alles wat nodig is om containers te draaien.

Het probleem met traditionele container runtimes
#

Zoals hierboven vermeld, delen traditionele container runtimes de onderliggende kernel van het besturingssysteem en de hardware. Er is geen isolatie op hardwareniveau. Als een applicatie in een container kwaadaardig gedrag vertoont, kan ze via een kwetsbaarheid uit de container ontsnappen (bv. CVE-2019-5736, CVE-2022-0185 en CVE-2022-0811) en toegang krijgen tot het onderliggende besturingssysteem van de host, andere containers, vertrouwelijke data, enzovoort. Dit kwaadaardige gedrag zie je in de figuur hieronder.

Kwaadaardige applicatie ontsnapt uit de container

Wanneer je een containerimage draait die je van het internet hebt gedownload, ken je niet altijd het interne gedrag ervan. De image kan kwaadaardige code bevatten. Het is ook mogelijk dat de image geen kwaadaardige code bevat op het moment dat je ze voor het eerst downloadt, maar dat een toekomstige update kwaadaardig gedrag introduceert zonder dat je het merkt. Controleer daarom als eerste voorzorgsmaatregel altijd of je de uitgever van een containerimage vertrouwt. Het kan ook dat een containerimage zelf geen kwaadaardig gedrag beoogt, maar dat een kwaadwillige actor een manier vindt om een publiek toegankelijke container aan te vallen en technieken voor privilege-escalatie gebruikt om uit de container te ontsnappen.

Oplossing: secure containers
#

Naast extra voorzichtig zijn met welke images je draait, is het in bepaalde beveiligingsgevoelige omgevingen soms nodig om de garantie te hebben dat een containerimage geen schade kan aanrichten door kwaadaardig gedrag. Dat is makkelijker gezegd dan gedaan, want het vereist een betere isolatie tussen de container, de host en andere draaiende containers, wat op zijn beurt extra overhead veroorzaakt.

Secure containers proberen dit op te lossen met minimale overhead. Ze bereiken een betere isolatie en behouden toch de voordelen van traditionele containers, zoals korte opstarttijden, portabiliteit, enzovoort. Een secure container doet dit door elke container in een eigen lichtgewicht VM te verpakken, toepasselijk een microVM genoemd, zoals je ziet in de figuur hieronder. Een microVM is een afgeslankte versie van een gewone VM, waarbij een lichtgewicht en geoptimaliseerd guest-OS wordt gebruikt in plaats van een volwaardig OS. Een microVM beperkt de overhead van een traditionele VM, zoals opstarttijd, CPU-gebruik, geheugengebruik, enzovoort. Virtuele hardware isoleert de workloads beter, zoals de figuur hieronder toont: wanneer een aanvaller met succes uit de container ontsnapt, zit die nog altijd vast in de geïsoleerde omgeving van de microVM. Idealiter zijn secure container runtimes ook OCI-compatibel, zodat ze als drop-in vervanging voor de huidige container runtimes kunnen dienen. Een secure container op basis van een microVM combineert het beste van twee werelden: de veelzijdigheid van containers en de beveiliging van VM’s.

Kwaadaardige applicatie zit vast in een geïsoleerde microVM-container

Conclusie
#

Na het lezen van dit artikel hoop ik dat je de risico’s begrijpt van het draaien van “onbetrouwbare” containerimages, en dat je extra voorzichtig bent wanneer je de uitgever van de image niet kent of vertrouwt. We hebben het gehad over de mogelijkheid van kwaadaardige code in containerimages en over een oplossing om de schade door kwaadaardige containers te beperken. Secure containers kunnen de beveiliging van je deployment aanzienlijk verbeteren zonder al te veel overhead. In een volgende post ga ik dieper in op wat een secure container runtime is en hoe die werkt. Ik analyseer ook de overhead van een secure container runtime, zodat je kunt bepalen of die (minimale) overhead in jouw use case aanvaardbaar is om de beveiliging van je omgeving te verbeteren.