Säkerhet i containers

En container är en isolerad miljö där man kan köra en eller flera applikationer. Fördelen med en container är snabb uppstartstid, enkel att flytta till annan infrastruktur utan att ändra i applikationskoden och kan enkelt replikeras. Men hur är säkerheten i dessa containers och hur påverkar dem säkerheten i den underliggande infrastrukturen?

Det finns många olika typer av container-runtimes från olika företag eller organisationer. För att nämna några; Docker, CoreOS RKT, Azure, CloudFoundry, VMware Photon, Apcera, Singularity, Intel Clear Containers (numera Kata Containers).

Vilken typ av container man än kör så är de flesta ganska lika när det kommer till säkerhet. Kata containers är den enda av de ovan nämnda som har ett extra lager säkerhet i varje container i form av Intels VT-x med hårdvarustöd. Tanken med Kata är att containers är som lätta virtuella maskiner snarare än traditionella containers, men målet är att få dem lika snabba och lätta som containers.

Förutom säkerhet mellan container och dess nod så finns det säkerhetsaspekter när det kommer till nätverk, container-images, image-registry, resurser, uppdateringar av OS, container-runtime, roller och konfiguration. Det är med andra ord många delar att ta i beaktning när det gäller säkerhet.

Den här bloggposten kommer gå ytligt in på vilka delar man bör tänka på och även nämna ett antal verktyg som kan hjälpa till att lösa vissa av problemen som finns. Texten fokuserar på säkerhet i ett container-perspektiv snarare än container-nods (host) perspektiv.

Allmänt om säkerhet i virtuella miljöer

En container kan ses som en virtuell maskin när det kommer till säkerhet. Det gäller att minimera vad som behöver finnas, vilket är ännu enklare i en container än för en VM. I en container kan man ta bort väldigt mycket och se till att köra minimal Linux distribution som räcker för ändamålet. Det gäller även att se över vilka portar man vill exponera utåt. Se till att endast de nödvändiga portarna är öppna och stäng allt annat. Man behöver till exempel inte ha SSH-access mot containern eftersom det går att nå containern via CLI.

Det kanske finns onödiga tjänster som körs, stäng då ner dem. Se även till att ha uppdaterade verktyg i containern (t.ex. ruby, python, perl) och även distributionen som körs. Kör heller inte din applikation som root utan skapa en användare med färre rättigheter som exekverar applikationen. Om man måste köra som root bör root-användaren i containern mappas mot en icke-root användare på noden. Ett alternativ är att använda verktyg som AppArmor och Seccomp för begränsa eller tillåta åtkomst till vissa specifika delar, mer om det senare.

En container kan i vissa system köras i read-only mode, vilket skapar en extra nivå av säkerhet där det inte går att skriva över data i containern ifall någon försöker göra attacker på så vis. I Docker kan man använda sig av kernel-funktionen seccomp (Secure Computing Mode). Seccomp möjliggör att man kan skapa profiler som specificerar vilka systemanrop en applikation ska få göra. Man kan läsa mer om detta här: https://docs.docker.com/engine/security/seccomp/

Man kan även använda sig av AppArmor (Application Armor) som är en kernel-modul. För varje applikation kan man skapa en profil som dikterar regler för vad en applikation tillåts göra. Precis som för seccomp så finns det AppArmor default-profiler att använda. Default-profilen används alltid av Docker men är väldigt öppen för att vara så kompatibel som möjligt med de flesta applikationer. Med en AppArmor profile kan man skapa rättigheter för nätverk, IP-protokoll, fil-access, system-anrop etc. Exempel på profil för nginx finns här. https://docs.docker.com/engine/security/apparmor/#nginx-example-profile.

Medan seccomp riktar in sig på systemanrop så hanterar AppArmor fler lager av begränsningar samt olika nivåer av kontroll och audit-logs.

Eftersom containern delar nod med andra containers så är de utsatta för DoS (Denial of Service) där en eller flera containrar kan försöka svälta ut en annan container när det kommer till resurser. Något att vara beredd på, även om det är något som är mer upp till den som hanterar noden att ha kontroll över. Men kan begränsas på containernivå genom att hantera resurser effektivt.

 

CONTAINERS OCH SÄKERHET PÅ TECH DAYS

Vill du veta mer om devops, microservices, containers och hur de hänger ihop samt hur man bygger säkerhet för dem? Besök Tech Days i april där Magnus B. Persson från Cygate kommer att prata om just detta.

Läs mer om Tech Days

Säkerhet mellan containers

Säkerhet mellan containers som kör på samma nod är viktigt för att isolera respektive container från varandra (på servernivå). Speciellt i en delad miljö där flera användare har access att skapa och exekvera containers. Man brukar prata om ”container breakout” vilket egentligen innebär att man från en container får access till den underliggande noden, vilket i sin tur medför access till alla andra containers som körs på samma nod. De senaste buggarna som kunde nyttjas för det var Meltdown och Spectre. Nu berörde de mycket mer än bara containers, men de gjorde det möjligt att komma åt data utanför en container. Det går att göra det svårare att bryta sig ut från en container med hjälp av de verktyg som nämnts tidigare (AppArmor, Seccomp) men även att undvika att köra sin applikation som root.

Image och registry

En container bygger på en så kallad image. Images sparas i ett registry som man kan använda för att hämta färdiga images från. För exempelvis Docker brukar man utgå från en färdig image för en Linux distribution som exempelvis Alpine Linux, Ubuntu eller Debian. Men det finns även väldigt många images som kommer bundlade med färdiga applikationer så som nginx, apache, mysql, ruby, perl etc. Man kan bygga sin image baserat på en uppsjö av olika images från tredjepart. Problemet är dock hur man kan lita på att de images man baserar sina containrar på är utan malware eller andra sårbarheter. Tillförlitligheten är såklart större på officiella repository-sidor för applikationen man vill använda, men det registry man använder kan ju faktiskt vara hackat och images innehåller annat än förväntat.

Det finns flera lösningar för att hantera det. Man kan köra ett eget registry och använda sig av exempelvis Dockers ”content trust” där varje image signeras med nycklar så att man kan garantera att de inte har blivit förändrade utifrån. Att nyttja content trust medför en mer komplex hantering av images när det kommer till både bygge och användning men skapar mycket större tillförlitlighet.

Att även använda TLS för krypterad överföring mellan registry-server och klient är också att föredra.

För att vara säker på att inga sårbarheter finns i en image så kan man använda vissa verktyg. CoreOS har ett verktyg vid namn Clair som används för att köra en statisk analys av en container. Docker har också släppt ett sårbarhets-verktyg som kallas Docker Security Scanning. Dockers verktyg går dock bara att använda på sitt registry i Dockers egna tjänst och kommer med en kostnad. Trend-micro har ett verktyg som kan användas på en container-nod och scannar igenom alla containers och noden efter sårbarheter. Så det finns en hel del verktyg som är skapade för att säkra upp images, containers och även container-noder mot malware, virus och andra sårbarheter.

Resursbegränsningar

Att skapa begränsningar i resurser för sina containrar kan vara bra för att inte låta dem skena iväg vid eventuella fel eller ifall en container blir kapad. Det kan skapa en ofrivillig DoS ifall en container har tillgång till för stora resurser och gör det svårt för andra containrar på noden att exekvera. Att ha koll på hur mycket en applikation nyttjar i minne, CPU och disk är bra för att sätta begränsningar.

Uppdateringar av container OS

Det kommer ofta patchar och säkerhetsuppdateringar till Linux distributioner. För att hantera det ska man inte uppdatera sitt OS som man gör på en VM eller dedikerad server, det vill säga inuti servern. För att uppdatera en container så bygger man om dess image. Låt säga att man bygger på Ubuntu:Latest så kommer man få en ny version vid bygge och sedan är det bara att redeploya sina containrar baserat på den nya imagen. Man bör inte köra ”latest” på sin bas-image utan hellre specificera vilken version man vill använda för att inte skapa problem som eventuellt medföljer vid större versionsförändringar.

Loggning

Vill man ha kontroll på vad som händer i sina containrar bör man ta hand om sina loggar. Att använda ett bra uppsamlingssystem som Splunk, Papertrail, Logstash etc och göra det möjligt att söka, sätta larm, överaka loggar gör det mer synligt ifall något suspekt händer i en container. Man kan då upptäcka fel på applikationen, attackförsök med mera.

Applikationskonfiguration

Konfiguration för att nå exempelvis en databas, ett API gränssnitt eller andra sorts konton behöver finnas tillgängligt för en applikation i en container. Men den sortens information vill man skydda. I Docker Swarm, Kubernetes och OpenShift finns det ”secrets” där man kan lagra information som en applikation, container eller Dockerfile behöver nå. Det man vill spara som secret skapas utanför containern och läggs in i krypterad format som sedan monteras upp i /run/secrets/<mysecret> som applikationen i containern kan läsa. Samma sak gäller för en Dockerfile där man kan säga till vilken secret man vill använda för att nå exempelvis en privat nyckel.

Ett annat vanligt sätt att hantera hemliga data är att sätta dem som miljövariabler för användaren av applikationen i containern. Det är ett sätt som Docker generellt hanterar.

Apcera löser det på ett annat sätt med sina pipe-lines där varje container får en egen unik användare och lösenord för till exempel MySQL som endast går att använda i den containern. En sådan lösning gör att det inte spelar någon roll ifall en container blir attackerad där användare och lösenord kommer ut eftersom de bara fungerar i just den unika containern.

Nätverk

Med Kubernetes och Docker Swarm kan man säkra upp kommunikation mellan olika tjänster, exempelvis en databas och en container så kan man sätta upp ett så kallat overlay-nätverk. I det nätet specificerar man vilken container som får nå databasen och då isolerar databasen från omvärlden. I Kubernetes som är ett containerhanteringssystem, finns det ännu en mekanism så kan man använda. Genom att placera containrar som behöver prata lokalt (t.ex. IPC/SHM) med varandra inom samma ”pod”. Där en ”pod” är en samling av containrar inom samma namespace.

Slutsats

Det finns många delar att ta hänsyn till när det kommer till säkerhet i containrar. Olika system har olika sätt att hantera det på. Men en fördel när det kommer till säkerhet i containrar är att man kan minimera attackytan till det extrema jämfört mot en VM eller dedikerad server. Använder man effektivt AppArmor eller Seccomp samt stänger ner allt onödigt får man en väldigt nerlåst container som hanterar det den ska och inget mer. I en VM eller dedikerad server kan det vara svårt eftersom den troligen kör andra processer som behöver andra typer av accesser.

Det finns färdiga verktyg att hantera både virus-scanning, sårbarhetsanalys samt att applicera hög pålitlighet för sina byggen. Att sätta upp ett eget registry för sina images skapar också en högre tillförlitlighet men kommer såklart med extra underhåll som pris.

Om man använder sig av ett automatiserad flöde för att bygga containers så kan man ha ett steg där man kör sårbarhetsanalys och virus-scanner på sin image innan man sätter den i drift.

Jag hoppas detta inlägg har gett lite tips och tricks på vad man ska tänka på och vad som finns att göra när det gäller säkerhet i container-världen. Nedan följer ett antal länkar för den som vill gräva ner sig djupare inom ämnet.

Länkar