Seccomp Kubernetesis: 7 asja, mida pead teadma algusest peale

Märge. tõlge: tutvustame teie tähelepanu Briti ettevõtte ASOS.com rakenduste turbeinseneri artikli tõlkele. Sellega alustab ta väljaannete sarja, mis on pühendatud Kubernetese turvalisuse parandamisele seccompi kasutamise kaudu. Kui sissejuhatus lugejatele meeldib, siis jälgime autorit ja jätkame tema tulevaste selleteemaliste materjalidega.

Seccomp Kubernetesis: 7 asja, mida pead teadma algusest peale

See artikkel on esimene postituste seeriast, kuidas luua SecDevOpsi vaimus seccompi profiile ilma maagiat ja nõidust kasutamata. XNUMX. osas käsitlen Kuberneteses seccompi juurutamise põhitõdesid ja sisemisi üksikasju.

Kubernetese ökosüsteem pakub laia valikut võimalusi konteinerite kinnitamiseks ja isoleerimiseks. Artikkel räägib turvalisest andmetöötlusrežiimist, mida tuntakse ka kui seccomp. Selle olemus on täitmiseks saadaolevate süsteemikutsete filtreerimine konteinerite kaupa.

Miks see oluline on? Konteiner on lihtsalt protsess, mis töötab konkreetses masinas. Ja see kasutab kernelit nagu teisedki rakendused. Kui konteinerid saaksid teha mis tahes süsteemikõnesid, kasutaks pahavara seda varsti ära, et konteineri isolatsioonist mööda minna ja mõjutada teisi rakendusi: pealtkuulada teavet, muuta süsteemi sätteid jne.

seccompi profiilid määravad, millised süsteemikutsed tuleks lubada või keelata. Konteiner käitusaeg aktiveerib need käivitamisel, et kernel saaks nende täitmist jälgida. Selliste profiilide kasutamine võimaldab piirata rünnakuvektorit ja vähendada kahju, kui mõni konteineris olev programm (st teie sõltuvused või nende sõltuvused) hakkab tegema midagi, mida tal pole lubatud teha.

Põhitõdede juurde jõudmine

Seccompi põhiprofiil sisaldab kolme elementi: defaultAction, architectures (Või archMap) Ja 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 määrab kõigi jaotises täpsustamata süsteemikutsete vaikesaatuse syscalls. Asjade lihtsustamiseks keskendume kahele põhiväärtusele, mida kasutatakse:

  • SCMP_ACT_ERRNO — blokeerib süsteemikõne sooritamise,
  • SCMP_ACT_ALLOW - võimaldab.

Jaotises architectures sihtarhitektuurid on loetletud. See on oluline, kuna kerneli tasemel rakendatav filter ise sõltub süsteemikõne identifikaatoritest, mitte nende profiilis määratud nimedest. Konteineri käitusaeg sobitab need enne kasutamist identifikaatoritega. Idee seisneb selles, et süsteemikõnedel võivad olenevalt süsteemi arhitektuurist olla täiesti erinevad ID-d. Näiteks süsteemikõne recvfrom (kasutatakse pesast teabe vastuvõtmiseks) on x64 süsteemides ID = 64 ja x517 puhul ID = 86. see on leiate kõigi x86-x64 arhitektuuride süsteemikutsete loendi.

Jaotises syscalls loetleb kõik süsteemikõned ja määrab, mida nendega teha. Näiteks saate seadistamise abil luua valge nimekirja defaultAction edasi SCMP_ACT_ERRNO, ja kõned jaotises syscalls määrama SCMP_ACT_ALLOW. Seega lubate ainult jaotises määratud kõnesid syscallsja keelake kõik teised. Musta nimekirja puhul peaksite väärtusi muutma defaultAction ja tegevused vastupidiseks.

Nüüd peaksime ütlema paar sõna nüansside kohta, mis pole nii ilmsed. Pange tähele, et alltoodud soovitused eeldavad, et juurutate Kubernetesis ärirakendusi ja soovite, et need töötaksid võimalikult väheste õigustega.

1. AllowPrivilegeEscalation=false

В securityContext konteineril on parameeter AllowPrivilegeEscalation. Kui see on sisse installitud false, konteinerid algavad tähega (on) natuke no_new_priv. Selle parameetri tähendus on nimest ilmne: see ei lase konteineril käivitada uusi protsesse, millel on rohkem õigusi kui tal endal on.

Selle valiku seadistamise kõrvalmõju true (vaikimisi) on see, et konteineri käitusaeg rakendab seccomp-profiili käivitusprotsessi alguses. Seega peavad profiilis olema lubatud kõik süsteemikutsed, mis on vajalikud sisemiste käitusprotsesside käivitamiseks (nt kasutaja/grupi ID-de määramine, teatud võimaluste väljalangemine).

Konteinerisse, mis teeb tühiseid asju echo hi, on vaja järgmisi õigusi:

{
    "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)

...nende asemel:

{
    "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)

Aga jällegi, miks see probleem on? Isiklikult väldiksin järgmiste süsteemikõnede lisamist valgesse nimekirja (välja arvatud juhul, kui nende järele on reaalne vajadus): capset, set_tid_address, setgid, setgroups и setuid. Tõeline väljakutse seisneb aga selles, et lubades protsesse, mille üle teil absoluutselt kontrolli ei ole, seote profiilid konteineri käitusaja juurutamisega. Teisisõnu, ühel päeval võite avastada, et pärast konteineri käituskeskkonna värskendamist (kas teie või suurema tõenäosusega pilveteenuse pakkuja poolt) lõpetavad konteinerite äkitselt töötamise.

Näpunäide nr 1: Käivitage konteinerid AllowPrivilegeEscaltion=false. See vähendab seccompi profiilide suurust ja muudab need konteineri käituskeskkonna muutuste suhtes vähem tundlikuks.

2. Seccomp-profiilide seadistamine konteineri tasemel

seccomp-profiili saab seadistada podi tasemel:

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

...või konteineri tasemel:

annotations:
  container.security.alpha.kubernetes.io/<container-name>: "localhost/profile.json"

Pange tähele, et ülaltoodud süntaks muutub Kubernetes seccomp muutub GA-ks (seda sündmust on oodata Kubernetese järgmises väljaandes - 1.18 - umbes tõlge).

Vähesed teavad, et Kubernetes on alati olnud vigamille tõttu rakendati seccomp-profiile pausi konteiner. Käituskeskkond kompenseerib selle puuduse osaliselt, kuid see konteiner ei kao kaustadest, kuna seda kasutatakse nende infrastruktuuri konfigureerimiseks.

Probleem on selles, et see konteiner algab alati AllowPrivilegeEscalation=true, mis toob kaasa lõikes 1 välja toodud probleemid, ja seda ei saa muuta.

Kasutades seccompi profiile konteineri tasemel, väldite seda lõksu ja saate luua profiili, mis on kohandatud konkreetse konteineri jaoks. Seda tuleb teha seni, kuni arendajad vea parandavad ja uus versioon (võib-olla 1.18?) muutub kõigile kättesaadavaks.

Näpunäide nr 2: määrake seccompi profiilid konteineri tasemel.

Praktilises mõttes on see reegel tavaliselt universaalne vastus küsimusele: „Miks minu seccompi profiil töötab docker runkuid ei tööta pärast Kubernetese klastris juurutamist?

3. Kasutage käitusaega/vaikeseadet ainult viimase abinõuna

Kubernetesil on sisseehitatud profiilide jaoks kaks võimalust: runtime/default и docker/default. Mõlemat rakendab konteineri käituskeskkond, mitte Kubernetes. Seetõttu võivad need olenevalt kasutatavast käituskeskkonnast ja selle versioonist erineda.

Teisisõnu, käitusaja muutumise tulemusena võib konteineril olla juurdepääs erinevale süsteemikõnede komplektile, mida ta võib kasutada, kuid ei pruugi kasutada. Enamik käitusaegu kasutab Dockeri juurutamine. Kui soovite seda profiili kasutada, veenduge, et see sobib teile.

Profiil docker/default on alates Kubernetes 1.11-st aegunud, seega vältige selle kasutamist.

Minu arvates profiil runtime/default sobib suurepäraselt otstarbeks, milleks see loodi: kasutajate kaitsmine käsu täitmisega seotud riskide eest docker run nende autode peal. Kui aga rääkida Kubernetese klastritel töötavatest ärirakendustest, siis julgeksin väita, et selline profiil on liiga avatud ja arendajad peaksid keskenduma oma rakenduste (või rakenduste tüüpide) profiilide loomisele.

Näpunäide nr 3: looge konkreetsete rakenduste jaoks seccomp-profiilid. Kui see pole võimalik, looge rakendusetüüpidele profiilid, näiteks looge täiustatud profiil, mis sisaldab kõiki Golangi rakenduse veebi API-sid. Kasutage käitusaega/vaikeseadet ainult viimase abinõuna.

Järgmistes postitustes käsitlen seda, kuidas luua SecDevOpsist inspireeritud seccomp-profiile, neid automatiseerida ja katsetada. Teisisõnu, teil pole vabandust, et mitte minna üle rakendusepõhistele profiilidele.

4. Unconfined EI OLE valik.

Kohta esimene Kubernetese turvaaudit selgus, et vaikimisi seccomp keelatud. See tähendab, et kui te ei määra PodSecurityPolicy, mis lubab selle klastris, töötavad kõik kaustad, mille jaoks seccompi profiil pole määratletud seccomp=unconfined.

Selles režiimis töötamine tähendab, et kaob terve isolatsioonikiht, mis kaitseb klastrit. Turvaeksperdid seda lähenemist ei soovita.

Näpunäide nr 4: klastris ei tohiks ükski konteiner sisse töötada seccomp=unconfined, eriti tootmiskeskkondades.

5. "Auditeerimisrežiim"

See punkt ei ole Kubernetese jaoks ainulaadne, kuid kuulub siiski kategooriasse "asjad, mida peaksite enne alustamist teadma".

Nagu juhtub, on seccompi profiilide loomine alati olnud keeruline ja tugineb suuresti katse-eksituse meetodile. Fakt on see, et kasutajatel pole lihtsalt võimalust neid tootmiskeskkondades testida, ilma et nad riskiksid rakenduse "kukkumisega".

Pärast Linuxi kerneli 4.14 väljaandmist sai võimalikuks profiili osade käivitamine auditirežiimis, salvestades info kõigi süsteemikutsete kohta syslogi, kuid neid blokeerimata. Selle režiimi saate aktiveerida parameetri abil SCMT_ACT_LOG:

SCMP_ACT_LOG: seccomp ei mõjuta süsteemikutset tegevat lõime, kui see ei vasta ühelegi filtri reeglile, kuid teave süsteemikõne kohta logitakse.

Siin on tüüpiline strateegia selle funktsiooni kasutamiseks.

  1. Lubage vajalikud süsteemikõned.
  2. Blokeerige süsteemist tulevad kõned, millest teate, et neist pole kasu.
  3. Salvestage logisse teave kõigi teiste kõnede kohta.

Lihtsustatud näide näeb välja selline:

{
    "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)

Kuid pidage meeles, et peate blokeerima kõik kõned, mida teate, et neid ei kasutata ja mis võivad klastrit kahjustada. Heaks aluseks nimekirja koostamisel on ametlik Dockeri dokumentatsioon. See selgitab üksikasjalikult, millised süsteemikõned on vaikeprofiilis blokeeritud ja miks.

Siiski on üks konks. Kuigi SCMT_ACT_LOG Linuxi kernel toetab alates 2017. aasta lõpust, kuid see sisenes Kubernetese ökosüsteemi alles suhteliselt hiljuti. Seetõttu vajate selle meetodi kasutamiseks Linuxi kerneli 4.14 ja runC versiooni, mis ei ole vanem v1.0.0-rc9.

Näpunäide nr 5: Tootmisprotsessis testimiseks saab luua auditirežiimi profiili mustade ja valgete loendite kombineerimisega ning kõik erandid logida.

6. Kasutage valgeid loendeid

Valge nimekirja lisamine nõuab täiendavaid jõupingutusi, kuna peate tuvastama kõik kõned, mida rakendus võib vajada, kuid see lähenemisviis parandab oluliselt turvalisust:

Soovitatav on kasutada valge nimekirja meetodit, kuna see on lihtsam ja usaldusväärsem. Musta nimekirja tuleb värskendada alati, kui lisatakse potentsiaalselt ohtlik süsteemikutse (või ohtlik lipp/valik, kui see on mustas nimekirjas). Lisaks on sageli võimalik muuta parameetri esitust ilma selle olemust muutmata ja sellega musta nimekirja piirangutest mööda minna.

Go rakenduste jaoks töötasin välja spetsiaalse tööriista, mis on rakendusega kaasas ja kogub kõik täitmise ajal tehtud kõned. Näiteks järgmise rakenduse jaoks:

package main

import "fmt"

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

... paneme käima gosystract nii:

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

... ja saame järgmise tulemuse:

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

Praegu on see vaid näide – lisateavet tööriistade kohta järgneb.

Näpunäide nr 6: lubage ainult need kõned, mida tõesti vajate, ja blokeerige kõik teised.

7. Pange õige alus (või valmistuge ootamatuks käitumiseks)

Kernel jõustab profiili olenemata sellest, mida te sellesse kirjutate. Isegi kui see pole just see, mida sa tahtsid. Näiteks kui blokeerite juurdepääsu kõnedele nagu exit või exit_group, ei saa konteiner korralikult välja lülituda ja isegi lihtne käsk nagu echo hi riputage ta üleso määramata ajaks. Selle tulemusel kasutate klastris suurt CPU kasutust:

Seccomp Kubernetesis: 7 asja, mida pead teadma algusest peale

Sellistel juhtudel võib appi tulla utiliit strace - see näitab, milles probleem võib olla:

Seccomp Kubernetesis: 7 asja, mida pead teadma algusest peale
sudo strace -c -p 9331

Veenduge, et profiilid sisaldaksid kõiki süsteemikutseid, mida rakendus tööajal vajab.

Näpunäide nr 7: pöörake tähelepanu detailidele ja veenduge, et kõik vajalikud süsteemikõned oleksid lubatud loendis.

Sellega on esimene osa artiklite sarjast, mis käsitleb seccompi kasutamist Kubernetesis SecDevOpsi vaimus. Järgmistes osades räägime sellest, miks see oluline on ja kuidas protsessi automatiseerida.

PS tõlkijalt

Loe ka meie blogist:

Allikas: www.habr.com

Lisa kommentaar