Seccomp a Kubernetes: 7 dolog, amiről tudni érdemes az elejétől fogva

Megjegyzés fordítás.: Bemutatjuk a brit ASOS.com cég idősebb alkalmazásbiztonsági mérnökének írásának fordítását. Ezzel kezdi el a publikációk sorozatát, amely a Kubernetes biztonságának javításáról szól a seccomp használatával. Ha a bevezetés tetszik az olvasóknak, követni fogjuk a szerzőt, és folytatjuk a témához kapcsolódó jövőbeli anyagaival.

Seccomp a Kubernetes: 7 dolog, amiről tudni érdemes az elejétől fogva

Ez a cikk az első egy sorozatból, amely arról szól, hogyan lehet seccomp profilokat létrehozni a SecDevOps szellemében, varázslat és bűbáj nélkül. Az első részben az alapokról és a seccomp Kubernetes-ben történő megvalósításának belső részleteiről fogok beszélni.

A Kubernetes ökoszisztéma elegendő változatosságot kínál a konténerek biztonságának és elszigetelésének biztosítására. A cikk a Secure Computing Mode-al foglalkozik, amelyet szintén ismernek seccomp. A lényeg a konténerek által végrehajtható rendszerhívások szűrése.

Miért fontos ez? A konténer csak egy folyamat, amelyet egy adott gépen futtatnak. Ez az alkalmazásokkal együtt használja a magot. Ha a konténerek bármilyen rendszerhívást végrehajthatnának, hamarosan a kártékony programok kihasználhatnák ezt, hogy megkerüljék a konténerek elszigeteltségét, és hatással legyenek más alkalmazásokra: információkat szerezhetnének meg, megváltoztathatnák a rendszerbeállításokat, stb.

A seccomp profilok meghatározzák, hogy mely rendszerhívásoknak kell engedélyezettnek vagy tiltottaknak lennie. A konténer futási környezete aktiválja őket a futtatás során, hogy a mag ellenőrizhesse a végrehajtásukat. Az ilyen profilok alkalmazása lehetővé teszi a támadási felület korlátozását és a kár minimalizálását, ha bármely program a konténeren belül (tehát a függőségeid, vagy azok függőségei) olyan dolgokat kezd el végezni, amiket nem engedélyeztek neki.

Az alapok megértése

A seccomp alapprofil három elemet tartalmaz: defaultAction, architectures SysWOW64 archMap, ennek eredményeként a lekérdezések olyan formát öltenek, mint a fent említett. syscalls:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "sched_yield",
                "futex",
                "write",
                "mmap",
                "exit_group",
                "madvise",
                "rt_sigprocmask",
                "getpid",
                "gettid",
                "tgkill",
                "rt_sigaction",
                "read",
                "getpgrp"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(medium-basic-seccomp.json)

defaultAction meghatározza a szabványos rendszerek hívási sorsát, amelyet nem határoztak meg a szakaszban syscalls. Az egyszerűsítés érdekében összpontosítsunk a két fő jelentésre, amelyet használni fogunk:

  • SCMP_ACT_ERRNO — leállítja a rendszerhívás végrehajtását,
  • SCMP_ACT_ALLOW — engedélyezi.

A részben architectures a célarchitektúrák vannak felsorolva. Ez fontos, mert a kernel szintjén alkalmazott szűrő a rendszerhívások azonosítóitól függ, nem pedig a neveiktől, amelyek a profilban vannak megadva. A konténer futtatási környezete ezeket az azonosítókat összehasonlítja. A lényeg az, hogy a rendszerhívások teljesen eltérő azonosítókkal rendelkezhetnek attól függően, hogy a rendszer architektúrája milyen. Például a rendszerhívás recvfrom (amelyet információk szerzésére használnak a socket-től) ID = 64 a x64 rendszereken és ID = 517 a x86 rendszereken. Itt megtalálhatja az összes rendszerhívás listáját az x86-x64 architektúrákhoz.

A szakaszban syscalls minden rendszerhívás szerepel, és meg van határozva, hogy mit kell velük tenni. Például létrehozhatunk egy fehér listát, ha beállítjuk defaultAction Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata SCMP_ACT_ERRNO, és a hívásoknak a szakaszban syscalls hozzárendelhetjük SCMP_ACT_ALLOW. Ezzel csak azok a hívások engedélyezettek, amelyek a szakaszban vannak megadva, és minden más tilos. A fekete lista esetén cserélje meg az értékeket syscalls, és az akciókat fordítva. defaultAction Most néhány szót kell mondani a kevésbé nyilvánvaló részletekről. Vegye figyelembe, hogy az alábbi ajánlások abból adódnak, hogy Ön üzleti alkalmazások sorozatát fejleszti a Kubernetesben, és fontos az alacsonyabb jogosultságokkal való működés.

1. AllowPrivilegeEscalation=false

securityContext

A a konténernek van egy paramétere AllowPrivilegeEscalation . Ha ezértékre van állítva, a konténerek a beállított ( hamis) bitnek megfelelően indulnakonno_new_priv . Ennek a paraméternek a jelentése nyilvánvaló a nevéből: nem engedi, hogy a konténer új folyamatokat indítson olyan jogosultságokkal, amelyek nagyobbak, mint a sajátjai.Ennek a paraméternek a mellékhatása, ha be van állítva

(alapértelmezett érték), hogy a konténer futtatási környezete a seccomp profilt a folyamat indítása során alkalmazza. Így minden rendszerhívás, amely a futtatási környezet belső folyamatait igényli (például felhasználói/csoportazonosítók beállítása, bizonyos képességek eltávolítása), engedélyezve kell hogy legyen a profilban. igaz A konténernek, amely egy egyszerű

echo hi , a következő engedélyekre lesz szüksége:, a következő engedélyekre lesz szükség:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "brk",
                "capget",
                "capset",
                "chdir",
                "close",
                "execve",
                "exit_group",
                "fstat",
                "fstatfs",
                "futex",
                "getdents64",
                "getppid",
                "lstat",
                "mprotect",
                "nanosleep",
                "newfstatat",
                "openat",
                "prctl",
                "read",
                "rt_sigaction",
                "statfs",
                "setgid",
                "setgroups",
                "setuid",
                "stat",
                "uname",
                "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(hi-pod-seccomp.json)

… ezek helyett:

{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "brk",
                "close",
                "execve",
                "exit_group",
                "futex",
                "mprotect",
                "nanosleep",
                "stat",
                "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}

(hi-container-seccomp.json)

De mégis, miért jelent ez problémát? Személy szerint kerülném a következő rendszerhívások fehérlistára helyezését (ha nincs rá valódi szükség): capset, set_tid_address, setgid, setgroups és setuid. A valódi nehézség abban áll, hogy amikor engedélyezed azokat a folyamatokat, amelyeket teljes mértékben nem tudsz ellenőrizni, a profilokat a konténer futtatási környezetének megvalósításához kötöd. Más szóval, előfordulhat, hogy miután frissítetted a konténer futtatási környezetét (akár te, akár valószínűbb, hogy a felhőszolgáltató), a konténerek hirtelen megállnak.

1. Tanács: Futtass konténereket a következő beállítással: AllowPrivilegeEscalation=false. Ez csökkenti a seccomp profilok méretét, és érzékenyebbé teszi őket a konténer futtatási környezetének változásaival szemben.

2. Seccomp profilok beállítása konténer szinten

A seccomp profil beállítható pod szinten:

annotations:
  seccomp.security.alpha.kubernetes.io/pod: "localhost/profile.json"

… vagy konténer szinten:

annotations:
  container.security.alpha.kubernetes.io/: "localhost/profile.json"

Kérlek, vedd figyelembe, hogy a fenti szintaxis megváltozik, amikor a Kubernetes seccomp GA lesz (ez az esemény már a következő Kubernetes kiadásban — 1.18 — várható).

Kevesen tudják, hogy a Kubernetes-ben mindig is volt egy hiba, ami miatt a seccomp profilokat alkalmazták pause-konténerre. A végrehajtási környezet részben kompenzálja ezt a hiányosságot, azonban ez a konténer továbbra is a pod-okban marad, mivel az infrastruktúrájuk beállításához használják.

A probléma az, hogy ez a konténer mindig a következővel indul: AllowPrivilegeEscalation=true, ami az 1. pontban említett problémákhoz vezet, és ezt megváltoztatni nem lehet.

Seccomp profilok alkalmazásával konténer szinten elkerülheted ezt a csapdát, és olyan profilt hozhatsz létre, amely a konkrét konténerhez van 'hangolva'. Ezt addig kell tenni, amíg a fejlesztők meg nem javítják a hibát, és egy új verzió (lehet, hogy 1.18?) elérhetővé nem válik mindenki számára.

2. tipp: Állíts be seccomp profilokat konténer szinten.

Gyakorlati értelemben ez a szabály általában egy általános válasz a következő kérdésre: 'Miért működik a seccomp profilom a docker run, de miért nem működik a Kubernetes klaszterben történő telepítés után?'.

3. Használj runtime/defaultot csak végső esetben

A Kubernetes-ben két beépített profil lehetőség létezik: runtime/default és docker/default. Mindkettőt a konténer végrehajtási környezete valósítja meg, nem a Kubernetes. Ezért eltérhetnek attól függően, hogy milyen végrehajtási környezetet használnak és annak verzióját.

Más szavakkal, ha a konténer végrehajtási környezetet vált, hozzáférhet egy másik rendszerhívás-csoporthoz, amelyet használhat vagy nem használhat. A legtöbb végrehajtási környezet a Docker megvalósítást használja.Ha ezt a profilt szeretnéd használni, győződj meg róla, hogy megfelel neked.

A profil docker/default Kubernetes 1.11 óta elavultnak számít, ezért kerüld a használatát.

A véleményem szerint a profil runtime/default kiválóan alkalmas a célokra, amelyekért létrehozták: védeni a felhasználókat a parancs futtatásával járó kockázatoktól docker run a gépeiken. Azonban ha üzleti alkalmazásokról van szó, amelyek Kubernetes klaszterekben futnak, bátran állíthatom, hogy ez a profil túl nyitott, és a fejlesztőknek a saját alkalmazásaikra (vagy alkalmazástípusokra) szabott profilok létrehozására kellene összpontosítaniuk.

3. tipp: Hozz létre seccomp profilokat konkrét alkalmazásokhoz. Ha ez nem lehetséges, foglalkozz az alkalmazástípusokhoz tartozó profilokkal, például hozz létre egy kiterjesztett profilt, amely tartalmazza az összes web-API-t, ami a Golang alkalmazásban található. Csak végső esetben használd a runtime/default-ot.

A jövőbeli publikációkban arról mesélek, hogyan lehet seccomp profilokat létrehozni SecDevOps szellemben, automatizálni és tesztelni őket a pipeline-okban. Más szavakkal, nem marad mentség, miért ne lehetne váltani az adott alkalmazásokhoz készült profilokra.

4. Az Unconfined NEM lehetőség

A az első Kubernetes biztonsági audit során kiderült, hogy alapértelmezés szerint a seccomp ki van kapcsolva. Ez azt jelenti, hogy ha nem állítja be a PodSecurityPolicy-t, amely bekapcsolja azt a klaszterben, minden pod, amelyhez nem lett seccomp profil meghatározva, az seccomp=unconfined.

módban fog futni. Ilyen módban működni azt jelenti, hogy elveszik egy egész izolációs réteg, amely védi a klasztert. Az ilyen megközelítést a biztonsági szakemberek nem ajánlják.

4. tanács: Egyetlen konténer sem működhet a klaszterben seccomp=unconfined, különösen production környezetekben.

5. „Audit mód”

Ez a pont nem egyedi a Kubernetes számára, de mégis beleesik abba a kategóriába, hogy „amit jó tudni már a kezdetekkor”.

Hagyományosan a seccomp profilok létrehozása mindig is nehéz feladat volt, és jelentős mértékben próbálkozások és hibák módszerén alapult. Az a helyzet, hogy a felhasználóknak egyszerűen nincs lehetőségük ellenőrizni őket production környezetben anélkül, hogy „megbuktatnák” az alkalmazást.

A Linux 4.14-es kernel megjelenésével lehetőség nyílt arra, hogy a profil részeit audit módban fussanak, rögzítve a syslog-ba az összes rendszerhívás információját, de nem blokkolva azokat. Ezt a módot a SCMT_ACT_LOG:

SCMP_ACT_LOG: a seccomp nem befolyásolja a hívást intéző szál működését, ha az nem esik egyetlen szűrőszabály alá sem, viszont a rendszerhívás információja bejegyzésre kerül a naplóba.

Íme egy tipikus stratégia ennek a lehetőségnek a használatához:

  1. Engedélyezze azokat a rendszerhívásokat, amelyek szükségesek.
  2. Blokkolja azokat a rendszerhívásokat, amelyekről tudja, hogy nem lesznek hasznosak.
  3. Minden további hívás információját naplózza.

Egy egyszerű példa a következőképpen néz ki:

{
    "defaultAction": "SCMP_ACT_LOG",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "arch_prctl",
                "sched_yield",
                "futex",
                "write",
                "mmap",
                "exit_group",
                "madvise",
                "rt_sigprocmask",
                "getpid",
                "gettid",
                "tgkill",
                "rt_sigaction",
                "read",
                "getpgrp"
            ],
            "action": "SCMP_ACT_ALLOW"
        },
        {
            "names": [
                "add_key",
                "keyctl",
                "ptrace"
            ],
            "action": "SCMP_ACT_ERRNO"
        }
    ]
}

(medium-mixed-seccomp.json)

De ne felejtsd el, hogy blokkolnod kell minden hívást, amiről tudható, hogy nem fog használatban lenni, és amelyek potenciálisan kárt okozhatnak a klaszterben. Jó alapot nyújt az hivatalos Docker dokumentáció. Részletesen magyarázza el, hogy mely rendszerszintek vannak letiltva az alapértelmezett profilban és miért.

De van egy csapda. Bár SCMT_ACT_LOG a Linux kernel támogatja 2017 óta, a Kubernetes ökoszisztémában csak viszonylag nemrégiben lépett be. Ezért ennek a módszernek a használatához 4.14-es Linux kernel és nem alacsonyabb runC verzió szükséges v1.0.0-rc9.

5. tipp: A teszteléshez készített audit módú profil létrehozható a fekete és fehér listák kombinálásával, míg minden kivételt naplózni kell.

6. Használj fehér listákat

A fehér listák kialakítása további erőfeszítéseket igényel, mivel minden hívást azonosítani kell, amelyre szüksége lehet az alkalmazásnak, azonban ez a megközelítés jelentősen növeli a biztonságot:

Határozottan ajánlott a fehér listák alapján történő megközelítést használni, mivel ez egyszerűbb és megbízhatóbb. A fekete listát minden alkalommal frissíteni kell, amikor egy potenciálisan veszélyes rendszerszint hívást (vagy veszélyes zászlót/paramétert, ha a fekete listán vannak) adnak hozzá. Ezen kívül gyakran meg lehet változtatni a paraméter megjelenését anélkül, hogy annak lényegét megváltoztatnánk, ezzel megkerülve a fekete lista korlátozásait.

Go programokhoz kifejlesztettem egy speciális eszközt, amely kíséri az alkalmazást, és összegyűjti az összes hívást, amelyet futás közben végeztek. Például az alábbi alkalmazás esetében:

package main

import "fmt"

func main() {
	fmt.Println("teszt")
}

… futtatjuk a gosystract-ot így nézett ki:

go install https://github.com/pjbgf/gosystract
gosystract --template='{{- range . }}{{printf "%s", .Name}}{{- end}}' application-path

… és a következő eredményt kapjuk:

"sched_yield",
"futex",
"write",
"mmap",
"exit_group",
"madvise",
"rt_sigprocmask",
"getpid",
"gettid",
"tgkill",
"rt_sigaction",
"read",
"getpgrp",
"arch_prctl",

Ez csak egy példa — a részletek az eszközkészletről később következnek.

6. Tanács: Csak azokat a hívásokat engedélyezze, amelyek valóban szükségesek, és blokkolja az összes többit.

7. Helyezze el a helyes alapokat (vagy készüljön fel a váratlan viselkedésre)

A kernel figyelemmel kíséri a profil betartását, függetlenül attól, hogy mit írt bele. Még ha nem is egészen olyan, amilyet szeretett volna. Például, ha blokkolja a hívások hozzáférését, mint például exit vagy exit_group, a konténer nem tudja megfelelően kilépni, és még egy egyszerű parancs is, mint például , a következő engedélyekre lesz szüksége: megváratja azthatározatlan ideig. Ennek következtében magas CPU terhelést kap a klaszterben:

Seccomp a Kubernetes: 7 dolog, amiről tudni érdemes az elejétől fogva

Ilyen esetekben hasznos lehet az strace — megmutatja, hol lehet a probléma:

Seccomp a Kubernetes: 7 dolog, amiről tudni érdemes az elejétől fogva
sudo strace -c -p 9331

Győződjön meg arról, hogy a profilok tartalmazzák az összes rendszerhívást, amelyek az alkalmazás működése alatt szükségesek.

7. Tanács: Figyelmesnek kell lennie a részletekre, és ellenőrizze, hogy minden szükséges rendszerhívás belekerült a fehérlistába.

Ez a cikksorozat első része a seccomp használatáról a Kubernetesben a SecDevOps szellemében a végéhez közelít. A következő részekben arról fogunk beszélni, hogy miért fontos, és hogyan lehet automatizálni a folyamatot.

Fejlesztési eszközök, amelyek Kubernetesben futnak

Olvasson további információkat a blogunkban:

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster