Seccomp in Kubernetes: 7 dinge wat jy van die begin af moet weet

Let wel. vertaal.: Ons bied aan u aandag die vertaling van 'n artikel deur 'n senior toepassingsekuriteitsingenieur by die Britse maatskappy ASOS.com. Daarmee begin hy 'n reeks publikasies wat toegewy is aan die verbetering van sekuriteit in Kubernetes deur die gebruik van seccomp. As lesers van die inleiding hou, sal ons die skrywer volg en voortgaan met sy toekomstige materiaal oor hierdie onderwerp.

Seccomp in Kubernetes: 7 dinge wat jy van die begin af moet weet

Hierdie artikel is die eerste in 'n reeks plasings oor hoe om seccomp-profiele in die gees van SecDevOps te skep, sonder om toorkuns en heksery te gebruik. In Deel XNUMX sal ek die basiese beginsels en interne besonderhede van die implementering van seccomp in Kubernetes dek.

Die Kubernetes-ekosisteem bied 'n wye verskeidenheid maniere om houers te beveilig en te isoleer. Die artikel handel oor Veilige Rekenaarmodus, ook bekend as sekkomp. Die essensie daarvan is om die stelseloproepe wat beskikbaar is vir uitvoering deur houers te filter.

Hoekom is dit belangrik? 'n Houer is net 'n proses wat op 'n spesifieke masjien loop. En dit gebruik die kern net soos ander toepassings. As houers enige stelseloproepe kon uitvoer, sal wanware baie gou hieruit voordeel trek om houerisolasie te omseil en ander toepassings te beïnvloed: onderskep inligting, verander stelselinstellings, ens.

seccomp-profiele definieer watter stelseloproepe toegelaat of gedeaktiveer moet word. Die houerlooptyd aktiveer hulle wanneer dit begin sodat die kern hul uitvoering kan monitor. Die gebruik van sulke profiele laat jou toe om die aanvalvektor te beperk en skade te verminder as enige program binne die houer (dit is jou afhanklikhede, of hul afhanklikhede) iets begin doen wat dit nie mag doen nie.

Om by die basiese beginsels uit te kom

Die basiese secomp-profiel sluit drie elemente in: defaultAction, architectures (Of archMap) En 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-basiese-secomp.json)

defaultAction bepaal die verstek lot van enige stelseloproep wat nie in die afdeling gespesifiseer is nie syscalls. Om dinge makliker te maak, kom ons fokus op die twee hoofwaardes wat gebruik sal word:

  • SCMP_ACT_ERRNO - blokkeer die uitvoering van 'n stelseloproep,
  • SCMP_ACT_ALLOW - toelaat.

In artikel architectures teikenargitekture word gelys. Dit is belangrik omdat die filter self, wat op kernvlak toegepas word, afhang van stelseloproepidentifiseerders, en nie van hul name wat in die profiel gespesifiseer is nie. Die houer se looptyd sal hulle pas by identifiseerders voor gebruik. Die idee is dat stelseloproepe heeltemal verskillende ID's kan hê, afhangende van die stelselargitektuur. Byvoorbeeld, stelsel oproep recvfrom (word gebruik om inligting vanaf die sok te ontvang) het ID = 64 op x64-stelsels en ID = 517 op x86. Hier jy kan 'n lys vind van alle stelseloproepe vir x86-x64-argitekture.

In die afdeling syscalls lys alle stelseloproepe en spesifiseer wat om daarmee te doen. Byvoorbeeld, jy kan 'n witlys skep deur te stel defaultAction op SCMP_ACT_ERRNO, en oproepe in die afdeling syscalls toewys SCMP_ACT_ALLOW. U laat dus slegs oproepe toe wat in die afdeling gespesifiseer is syscalls, en verbied alle ander. Vir die swartlys moet jy die waardes verander defaultAction en optrede teenoor die teenoorgestelde.

Nou moet ons 'n paar woorde sê oor nuanses wat nie so duidelik is nie. Neem asseblief kennis dat die aanbevelings hieronder aanvaar dat u 'n reeks besigheidstoepassings op Kubernetes ontplooi en u wil hê dat hulle met die minste moontlike voorregte moet loop.

1. AllowPrivilegeEscalation=onwaar

В securityContext houer het 'n parameter AllowPrivilegeEscalation. As dit geïnstalleer is in false, houers sal begin met (on) bietjie no_new_priv. Die betekenis van hierdie parameter is duidelik uit die naam: dit verhoed dat die houer nuwe prosesse met meer voorregte begin as wat dit self het.

'n Newe-effek van hierdie opsie word ingestel op true (verstek) is dat die houerlooptyd die seccomp-profiel heel aan die begin van die opstartproses toepas. Dus, alle stelseloproepe wat nodig is om interne looptydprosesse uit te voer (bv. die opstel van gebruiker-/groep-ID's, die weglating van sekere vermoëns) moet in die profiel geaktiveer word.

Na 'n houer wat onbenullige dinge doen echo hi, sal die volgende toestemmings vereis word:

{
    "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-secomp.json)

... in plaas van hierdie:

{
    "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-houer-secomp.json)

Maar weereens, hoekom is dit 'n probleem? Persoonlik sal ek vermy om die volgende stelseloproepe te witlys (tensy daar 'n werklike behoefte daaraan is): capset, set_tid_address, setgid, setgroups и setuid. Die werklike uitdaging is egter dat deur prosesse toe te laat waaroor jy absoluut geen beheer het nie, jy profiele koppel aan die houerlooptydimplementering. Met ander woorde, eendag kan jy vind dat die houers skielik ophou loop nadat jy die houerlooptyd-omgewing opgedateer het (óf deur jou óf, meer waarskynlik, deur die wolkdiensverskaffer).

Wenk # 1: Loop houers met AllowPrivilegeEscaltion=false. Dit sal die grootte van seccomp-profiele verminder en hulle minder sensitief maak vir veranderinge in die houerlooptyd-omgewing.

2. Stel seccomp-profiele op die houervlak

Die secomp-profiel kan op die peulvlak gestel word:

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

...of op die houervlak:

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

Neem asseblief kennis dat die bogenoemde sintaksis sal verander wanneer Kubernetes secomp sal GA word (hierdie geleentheid word verwag in die volgende uitgawe van Kubernetes - 1.18 - ongeveer transl.).

Min mense weet dat Kubernetes nog altyd gehad het foutwat veroorsaak het dat secomp-profiele toegepas is pouse houer. Die looptyd-omgewing vergoed gedeeltelik vir hierdie tekortkoming, maar hierdie houer verdwyn nie uit die peule nie, aangesien dit gebruik word om hul infrastruktuur op te stel.

Die probleem is dat hierdie houer altyd begin met AllowPrivilegeEscalation=true, wat lei tot die probleme wat in paragraaf 1 uitgespreek is, en dit kan nie verander word nie.

Deur seccomp-profiele op die houervlak te gebruik, vermy jy hierdie slaggat en kan jy 'n profiel skep wat aangepas is vir 'n spesifieke houer. Dit sal gedoen moet word totdat die ontwikkelaars die fout reggemaak het en die nuwe weergawe (dalk 1.18?) vir almal beskikbaar word.

Wenk # 2: Stel secomp-profiele op die houervlak.

In 'n praktiese sin dien hierdie reël gewoonlik as 'n universele antwoord op die vraag: "Waarom werk my secomp-profiel met docker runmaar werk nie nadat dit na 'n Kubernetes-kluster ontplooi is nie?

3. Gebruik runtime/default slegs as 'n laaste uitweg

Kubernetes het twee opsies vir ingeboude profiele: runtime/default и docker/default. Albei word geïmplementeer deur die houerlooptyd, nie Kubernetes nie. Daarom kan hulle verskil afhangende van die looptyd-omgewing wat gebruik word en die weergawe daarvan.

Met ander woorde, as gevolg van die verandering van looptyd, kan die houer toegang hê tot 'n ander stel stelseloproepe, wat dit dalk of nie mag gebruik nie. Die meeste looptye gebruik Docker implementering. As jy hierdie profiel wil gebruik, maak asseblief seker dat dit geskik is vir jou.

Profiel docker/default is sedert Kubernetes 1.11 opgeskort, dus vermy dit om dit te gebruik.

Na my mening, profiel runtime/default perfek geskik vir die doel waarvoor dit geskep is: die beskerming van gebruikers teen die risiko's verbonde aan die uitvoering van 'n opdrag docker run op hul motors. Wanneer dit egter kom by besigheidstoepassings wat op Kubernetes-klusters loop, wil ek waag om te argumenteer dat so 'n profiel te oop is en ontwikkelaars moet fokus op die skep van profiele vir hul toepassings (of tipe toepassings).

Wenk # 3: Skep secomp-profiele vir spesifieke toepassings. As dit nie moontlik is nie, skep profiele vir toepassingtipes, skep byvoorbeeld 'n gevorderde profiel wat al die web-API's van die Golang-toepassing insluit. Gebruik slegs looptyd/verstek as 'n laaste uitweg.

In toekomstige plasings sal ek dek hoe om SecDevOps-geïnspireerde seccomp-profiele te skep, dit te outomatiseer en in pyplyne te toets. Met ander woorde, jy sal geen verskoning hê om nie na toepassingspesifieke profiele op te gradeer nie.

4. Onbeperk is NIE 'n opsie nie.

Van eerste Kubernetes-sekuriteitsoudit dit het geblyk dat dit by verstek seccomp gedeaktiveer. Dit beteken dat as jy nie stel PodSecurityPolicy, wat dit in die cluster sal aktiveer, sal alle peule waarvoor die seccomp-profiel nie gedefinieer is nie, werk in seccomp=unconfined.

Om in hierdie modus te werk, beteken dat 'n hele laag isolasie verlore gaan wat die groep beskerm. Hierdie benadering word nie deur sekuriteitskenners aanbeveel nie.

Wenk # 4: Geen houer in die groep moet inloop nie seccomp=unconfined, veral in produksie-omgewings.

5. "Ouditmodus"

Hierdie punt is nie uniek aan Kubernetes nie, maar val steeds in die kategorie "dinge om te weet voordat jy begin".

Soos dit gebeur, was die skep van seccomp-profiele nog altyd uitdagend en maak dit baie staat op proef en fout. Die feit is dat gebruikers eenvoudig nie die geleentheid het om hulle in produksie-omgewings te toets sonder om die toepassing te “los” nie.

Na die vrystelling van die Linux-kern 4.14, het dit moontlik geword om dele van 'n profiel in ouditmodus te laat loop, deur inligting oor alle stelseloproepe in syslog op te neem, maar sonder om dit te blokkeer. Jy kan hierdie modus aktiveer met die parameter SCMT_ACT_LOG:

SCMP_ACT_LOG: seccomp sal nie die draad wat die stelsel oproep maak, beïnvloed as dit nie by enige reël in die filter pas nie, maar inligting oor die stelseloproep sal aangeteken word.

Hier is 'n tipiese strategie om hierdie kenmerk te gebruik:

  1. Laat stelseloproepe toe wat nodig is.
  2. Blokkeer oproepe van die stelsel wat jy weet nie nuttig sal wees nie.
  3. Teken inligting oor alle ander oproepe in die log aan.

'n Vereenvoudigde voorbeeld lyk soos volg:

{
    "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-gemengde-secomp.json)

Maar onthou dat jy alle oproepe moet blokkeer wat jy weet nie gebruik sal word nie en wat moontlik die groep kan benadeel. 'n Goeie basis vir die opstel van 'n lys is die amptelike Docker-dokumentasie. Dit verduidelik in detail watter stelseloproepe in die verstekprofiel geblokkeer word en hoekom.

Daar is egter een vangplek. Alhoewel SCMT_ACT_LOG ondersteun deur die Linux-kern sedert die einde van 2017, het dit eers relatief onlangs die Kubernetes-ekosisteem betree. Daarom, om hierdie metode te gebruik, benodig u 'n Linux-kern 4.14 en runC-weergawe nie laer nie v1.0.0-rc9.

Wenk # 5: 'n Ouditmodusprofiel vir toetsing in produksie kan geskep word deur swart en wit lyste te kombineer, en alle uitsonderings kan aangeteken word.

6. Gebruik witlyste

Witlys vereis bykomende moeite, want jy moet elke oproep identifiseer wat die toepassing dalk benodig, maar hierdie benadering verbeter sekuriteit aansienlik:

Dit word sterk aanbeveel om die witlys-benadering te gebruik, aangesien dit eenvoudiger en meer betroubaar is. Die swartlys sal opgedateer moet word wanneer 'n potensieel gevaarlike stelseloproep (of 'n gevaarlike vlag/opsie as dit op die swartlys is) bygevoeg word. Daarbenewens is dit dikwels moontlik om die voorstelling van 'n parameter te verander sonder om die essensie daarvan te verander en daardeur die beperkings van die swartlys te omseil.

Vir Go-toepassings het ek 'n spesiale hulpmiddel ontwikkel wat die toepassing vergesel en alle oproepe wat tydens uitvoering gemaak word, versamel. Byvoorbeeld, vir die volgende toepassing:

package main

import "fmt"

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

... kom ons begin gosystract soos volg:

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

... en ons kry die volgende resultaat:

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

Vir nou is dit net 'n voorbeeld—meer besonderhede oor die gereedskap sal volg.

Wenk # 6: Laat slegs daardie oproepe toe wat jy regtig nodig het en blokkeer alle ander.

7. Lê die regte fondamente (of berei voor vir onverwagte gedrag)

Die kern sal die profiel afdwing ongeag wat jy daarin skryf. Al is dit nie presies wat jy wou hê nie. Byvoorbeeld, as jy toegang blokkeer tot oproepe soos exit of exit_group, sal die houer nie korrek kan afskakel nie en selfs 'n eenvoudige opdrag soos echo hi hang hom opo vir 'n onbepaalde tydperk. As gevolg hiervan sal u hoë SVE-gebruik in die groep kry:

Seccomp in Kubernetes: 7 dinge wat jy van die begin af moet weet

In sulke gevalle kan 'n hulpprogram tot die redding kom strace - dit sal wys wat die probleem kan wees:

Seccomp in Kubernetes: 7 dinge wat jy van die begin af moet weet
sudo strace -c -p 9331

Maak seker dat die profiele al die stelseloproepe bevat wat die toepassing tydens looptyd benodig.

Wenk # 7: Gee aandag aan detail en maak seker dat alle nodige stelseloproepe gewitlys is.

Dit sluit die eerste deel van 'n reeks artikels af oor die gebruik van seccomp in Kubernetes in die gees van SecDevOps. In die volgende dele sal ons praat oor hoekom dit belangrik is en hoe om die proses te outomatiseer.

PS van vertaler

Lees ook op ons blog:

Bron: will.com

Voeg 'n opmerking