Seccomp katika Kubernetes: Mambo 7 unayohitaji kujua tangu mwanzo

Kumbuka. tafsiri.: Tunawasilisha kwa uangalifu wako tafsiri ya makala ya mhandisi mkuu wa usalama wa maombi katika kampuni ya Uingereza ya ASOS.com. Kwa hiyo, anaanza mfululizo wa machapisho yaliyojitolea kuboresha usalama huko Kubernetes kupitia matumizi ya seccomp. Ikiwa wasomaji wanapenda utangulizi, tutamfuata mwandishi na kuendelea na nyenzo zake za baadaye juu ya mada hii.

Seccomp katika Kubernetes: Mambo 7 unayohitaji kujua tangu mwanzo

Makala hii ni ya kwanza katika mfululizo wa machapisho kuhusu jinsi ya kuunda wasifu wa seccomp katika roho ya SecDevOps, bila kutumia uchawi na uchawi. Katika Sehemu ya 1, nitaangazia misingi na maelezo ya ndani ya utekelezaji wa seccomp katika Kubernetes.

Mfumo ikolojia wa Kubernetes hutoa njia mbalimbali za kulinda na kutenga vyombo. Nakala hiyo inahusu Njia salama ya Kompyuta, inayojulikana pia kama seccomp. Kiini chake ni kuchuja simu za mfumo zinazopatikana kwa kutekelezwa na vyombo.

Kwa nini ni muhimu? Chombo ni mchakato tu unaoendeshwa kwenye mashine maalum. Na hutumia kernel kama programu zingine. Ikiwa vyombo vinaweza kupiga simu za mfumo wowote, hivi karibuni programu hasidi itachukua fursa hii kukwepa kutengwa kwa kontena na kuathiri programu zingine: kukatiza habari, kubadilisha mipangilio ya mfumo, n.k.

wasifu wa seccomp hufafanua ni simu zipi za mfumo zinafaa kuruhusiwa au kuzimwa. Muda wa kukimbia wa chombo huwasha inapoanza ili kernel iweze kufuatilia utekelezaji wao. Kutumia wasifu kama huo hukuruhusu kuweka kikomo cha vekta ya kushambulia na kupunguza uharibifu ikiwa programu yoyote ndani ya kontena (yaani, utegemezi wako, au utegemezi wao) itaanza kufanya kitu ambacho hairuhusiwi kufanya.

Kufikia misingi

Profaili ya msingi ya seccomp inajumuisha vitu vitatu: defaultAction, architectures (Au archMap) na 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"
        }
    ]
}

(kati-msingi-seccomp.json)

defaultAction huamua hatima chaguo-msingi ya simu yoyote ya mfumo ambayo haijabainishwa katika sehemu hiyo syscalls. Ili kurahisisha mambo, hebu tuzingatie maadili mawili kuu ambayo yatatumika:

  • SCMP_ACT_ERRNO - huzuia utekelezaji wa simu ya mfumo,
  • SCMP_ACT_ALLOW - inaruhusu.

Katika sehemu architectures usanifu unaolengwa umeorodheshwa. Hii ni muhimu kwa sababu kichujio yenyewe, kinachotumiwa kwenye kiwango cha kernel, inategemea vitambulisho vya simu za mfumo, na si kwa majina yao yaliyotajwa kwenye wasifu. Muda wa matumizi ya kontena utawafananisha na vitambulisho kabla ya matumizi. Wazo ni kwamba simu za mfumo zinaweza kuwa na vitambulisho tofauti kabisa kulingana na usanifu wa mfumo. Kwa mfano, simu ya mfumo recvfrom (inayotumiwa kupokea taarifa kutoka kwa tundu) ina ID = 64 kwenye mifumo ya x64 na ID = 517 kwenye x86. Hapa unaweza kupata orodha ya simu zote za mfumo kwa usanifu wa x86-x64.

Katika sehemu syscalls huorodhesha simu zote za mfumo na kubainisha cha kufanya nazo. Kwa mfano, unaweza kuunda orodha iliyoidhinishwa kwa kuweka defaultAction juu ya SCMP_ACT_ERRNO, na simu katika sehemu hiyo syscalls kabidhi SCMP_ACT_ALLOW. Kwa hivyo, unaruhusu tu simu zilizoainishwa kwenye sehemu syscalls, na kuwakataza wengine wote. Kwa orodha nyeusi unapaswa kubadilisha maadili defaultAction na vitendo kinyume chake.

Sasa tunapaswa kusema maneno machache kuhusu nuances ambayo si wazi sana. Tafadhali kumbuka kuwa mapendekezo yaliyo hapa chini yanachukulia kuwa unatumia safu ya maombi ya biashara kwenye Kubernetes na unataka yaendeshe kwa mapendeleo machache iwezekanavyo.

1. RuhusuPrivilegeEscalation=uongo

В securityContext chombo kina parameter AllowPrivilegeEscalation. Ikiwa imewekwa ndani false, vyombo vitaanza na (on) kidogo no_new_priv. Maana ya paramu hii ni dhahiri kutoka kwa jina: inazuia kontena kuzindua michakato mpya na marupurupu zaidi kuliko yenyewe.

Madhara ya chaguo hili yakiwekwa true (chaguo-msingi) ni kwamba wakati wa kukimbia wa kontena unatumika wasifu wa seccomp mwanzoni mwa mchakato wa kuanza. Kwa hivyo, simu zote za mfumo zinazohitajika ili kuendesha michakato ya ndani ya muda wa matumizi (kwa mfano, kuweka vitambulisho vya mtumiaji/kikundi, kuacha uwezo fulani) lazima ziwashwe kwenye wasifu.

Kwa chombo kinachofanya mambo madogo echo hi, ruhusa zifuatazo zitahitajika:

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

... badala ya haya:

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

Lakini tena, kwa nini hili ni tatizo? Binafsi, ningeepuka kuorodhesha simu zifuatazo za mfumo (isipokuwa kuna hitaji la kweli kwao): capset, set_tid_address, setgid, setgroups и setuid. Walakini, changamoto ya kweli ni kwamba kwa kuruhusu michakato ambayo huna udhibiti kabisa, unaunganisha wasifu kwenye utekelezaji wa wakati wa kukimbia wa kontena. Kwa maneno mengine, siku moja unaweza kupata kwamba baada ya kusasisha mazingira ya kukimbia kwa chombo (ama na wewe au, uwezekano mkubwa, na mtoa huduma wa wingu), vyombo vinaacha kufanya kazi ghafla.

Kidokezo # 1: Endesha vyombo na AllowPrivilegeEscaltion=false. Hii itapunguza saizi ya wasifu wa seccomp na kuzifanya zisiwe nyeti sana kwa mabadiliko katika mazingira ya muda wa matumizi ya kontena.

2. Kuweka wasifu wa seccomp kwenye kiwango cha kontena

Wasifu wa seccomp unaweza kuwekwa katika kiwango cha pod:

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

...au kwa kiwango cha kontena:

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

Tafadhali kumbuka kuwa syntax iliyo hapo juu itabadilika wakati Kubernetes seccomp itakuwa GA (tukio hili linatarajiwa katika toleo lijalo la Kubernetes - 1.18 - takriban. transl.).

Watu wachache wanajua kuwa Kubernetes amekuwa nayo kila wakati mduduambayo ilisababisha wasifu wa seccomp kutumika kwa pause chombo. Mazingira ya wakati wa kukimbia hulipa fidia kwa upungufu huu, lakini chombo hiki hakipotee kutoka kwenye maganda, kwani hutumiwa kusanidi miundombinu yao.

Shida ni kwamba chombo hiki huanza kila wakati AllowPrivilegeEscalation=true, na kusababisha matatizo yaliyotolewa katika aya ya 1, na hii haiwezi kubadilishwa.

Kwa kutumia wasifu wa seccomp katika kiwango cha kontena, unaweza kuepuka hatari hii na unaweza kuunda wasifu ambao umeundwa kulingana na kontena mahususi. Hii italazimika kufanywa hadi watengenezaji warekebishe hitilafu na toleo jipya (labda 1.18?) lipatikane kwa kila mtu.

Kidokezo # 2: Weka wasifu wa seccomp kwenye kiwango cha kontena.

Kwa maana ya vitendo, sheria hii kawaida hutumika kama jibu la jumla kwa swali: "Kwa nini wasifu wangu wa seccomp hufanya kazi na docker runlakini haifanyi kazi baada ya kupeleka kwenye nguzo ya Kubernetes?

3. Tumia wakati wa kukimbia/chaguo-msingi pekee kama suluhu la mwisho

Kubernetes ina chaguzi mbili za profaili zilizojengwa ndani: runtime/default и docker/default. Zote mbili zinatekelezwa na wakati wa kukimbia kwa kontena, sio Kubernetes. Kwa hivyo, zinaweza kutofautiana kulingana na mazingira ya wakati wa kukimbia na toleo lake.

Kwa maneno mengine, kama matokeo ya kubadilisha wakati wa kukimbia, chombo kinaweza kufikia seti tofauti ya simu za mfumo, ambazo zinaweza kutumia au kutotumia. Wakati mwingi wa kukimbia hutumia Utekelezaji wa Docker. Ikiwa ungependa kutumia wasifu huu, tafadhali hakikisha kuwa unakufaa.

profile docker/default imeacha kutumika tangu Kubernetes 1.11, kwa hivyo epuka kuitumia.

Kwa maoni yangu, wasifu runtime/default inafaa kabisa kwa madhumuni ambayo iliundwa: kulinda watumiaji kutokana na hatari zinazohusiana na kutekeleza amri docker run kwenye magari yao. Walakini, linapokuja suala la programu za biashara zinazoendeshwa kwenye vikundi vya Kubernetes, ningethubutu kusema kwamba wasifu kama huo uko wazi sana na wasanidi wanapaswa kuzingatia kuunda wasifu kwa programu zao (au aina za programu).

Kidokezo # 3: Unda wasifu wa seccomp kwa programu mahususi. Ikiwa hii haiwezekani, tengeneza wasifu wa aina za programu, kwa mfano, unda wasifu wa hali ya juu unaojumuisha API zote za wavuti za programu ya Golang. Tumia tu wakati wa kukimbia/chaguo-msingi kama suluhu la mwisho.

Katika machapisho yajayo, nitashughulikia jinsi ya kuunda wasifu wa seccomp unaoongozwa na SecDevOps, kuzibadilisha kiotomatiki, na kuzijaribu kwenye bomba. Kwa maneno mengine, hutakuwa na kisingizio cha kutoboresha hadi wasifu mahususi wa programu.

4. Kutofungwa SI chaguo.

Ya ukaguzi wa kwanza wa usalama wa Kubernetes iligeuka kuwa kwa chaguo-msingi seccomp imezimwa. Hii ina maana kwamba kama huna kuweka PodSecurityPolicy, ambayo itaiwezesha kwenye nguzo, maganda yote ambayo wasifu wa seccomp haujafafanuliwa utafanya kazi ndani yake. seccomp=unconfined.

Uendeshaji katika hali hii ina maana kwamba safu nzima ya insulation inapotea ambayo inalinda nguzo. Mbinu hii haipendekezwi na wataalam wa usalama.

Kidokezo # 4: Hakuna kontena kwenye nguzo inapaswa kuingia ndani seccomp=unconfined, hasa katika mazingira ya uzalishaji.

5. "Njia ya ukaguzi"

Hatua hii si ya Kubernetes pekee, lakini bado inaangukia katika kitengo cha "mambo ya kujua kabla ya kuanza".

Inapotokea, kuunda wasifu wa seccomp daima imekuwa changamoto na hutegemea sana majaribio na makosa. Ukweli ni kwamba watumiaji hawana fursa ya kuwajaribu katika mazingira ya uzalishaji bila kuhatarisha "kuacha" programu.

Baada ya kutolewa kwa Linux kernel 4.14, iliwezekana kuendesha sehemu za wasifu katika hali ya ukaguzi, kurekodi habari kuhusu simu zote za mfumo kwenye syslog, lakini bila kuzizuia. Unaweza kuamsha hali hii kwa kutumia parameter SCMT_ACT_LOG:

SCMP_ACT_LOG: seccomp haitaathiri uzi unaopiga simu ikiwa hailingani na sheria yoyote kwenye kichungi, lakini habari kuhusu simu ya mfumo itawekwa.

Hapa kuna mkakati wa kawaida wa kutumia kipengele hiki:

  1. Ruhusu simu za mfumo zinazohitajika.
  2. Zuia simu kutoka kwa mfumo ambao unajua hautakuwa na manufaa.
  3. Rekodi habari kuhusu simu zingine zote kwenye logi.

Mfano rahisi unaonekana kama hii:

{
    "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"
        }
    ]
}

(kati-mchanganyiko-seccomp.json)

Lakini kumbuka kuwa unahitaji kuzuia simu zote ambazo unajua hazitatumika na ambazo zinaweza kudhuru nguzo. Msingi mzuri wa kuandaa orodha ni rasmi Nyaraka za Docker. Inaelezea kwa undani ni simu zipi za mfumo zimezuiwa katika wasifu chaguo-msingi na kwa nini.

Hata hivyo, kuna catch moja. Ingawa SCMT_ACT_LOG ikiungwa mkono na kernel ya Linux tangu mwisho wa 2017, iliingia kwenye mfumo wa ikolojia wa Kubernetes hivi majuzi tu. Kwa hivyo, kutumia njia hii utahitaji Linux kernel 4.14 na toleo la runC sio chini v1.0.0-rc9.

Kidokezo # 5: Wasifu wa hali ya ukaguzi wa majaribio katika toleo la umma unaweza kuundwa kwa kuchanganya orodha nyeusi na nyeupe, na vighairi vyote vinaweza kurekodiwa.

6. Tumia orodha zilizoidhinishwa

Uorodheshaji ulioidhinishwa unahitaji juhudi zaidi kwa sababu ni lazima utambue kila simu ambayo programu inaweza kuhitaji, lakini mbinu hii inaboresha usalama pakubwa:

Inapendekezwa sana kutumia mbinu ya walioidhinishwa kwa kuwa ni rahisi na ya kuaminika zaidi. Orodha iliyoidhinishwa itahitaji kusasishwa wakati simu inayoweza kuwa hatari ya mfumo (au bendera/chaguo hatari ikiwa iko kwenye orodha iliyoidhinishwa) inapoongezwa. Kwa kuongeza, mara nyingi inawezekana kubadilisha uwakilishi wa parameter bila kubadilisha kiini chake na hivyo kupitisha vikwazo vya orodha nyeusi.

Kwa programu za Go, nilitengeneza zana maalum ambayo huambatana na programu na kukusanya simu zote zinazopigwa wakati wa utekelezaji. Kwa mfano, kwa maombi yafuatayo:

package main

import "fmt"

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

... tuzindue gosystract hivyo:

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

... na tunapata matokeo yafuatayo:

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

Kwa sasa, huu ni mfano tu—maelezo zaidi kuhusu zana yatafuata.

Kidokezo # 6: Ruhusu simu zile pekee ambazo unahitaji kweli na uzuie zingine zote.

7. Weka misingi sahihi (au jitayarishe kwa tabia usiyotarajia)

Kernel itatekeleza wasifu bila kujali unachoandika ndani yake. Hata kama sio vile ulivyotaka. Kwa mfano, ukizuia ufikiaji wa simu kama exit au exit_group, chombo hakitaweza kuzima kwa usahihi na hata amri rahisi kama echo hi tumnyongao kwa muda usiojulikana. Kama matokeo, utapata matumizi ya juu ya CPU kwenye nguzo:

Seccomp katika Kubernetes: Mambo 7 unayohitaji kujua tangu mwanzo

Katika hali kama hizi, shirika linaweza kuja kuwaokoa strace - itaonyesha shida inaweza kuwa nini:

Seccomp katika Kubernetes: Mambo 7 unayohitaji kujua tangu mwanzo
sudo strace -c -p 9331

Hakikisha kwamba wasifu una simu zote za mfumo ambazo programu inahitaji wakati wa utekelezaji.

Kidokezo # 7: Zingatia undani na hakikisha simu zote muhimu za mfumo zimeidhinishwa.

Hii inahitimisha sehemu ya kwanza ya mfululizo wa makala kuhusu kutumia seccomp katika Kubernetes katika ari ya SecDevOps. Katika sehemu zifuatazo tutazungumza juu ya kwa nini hii ni muhimu na jinsi ya kubinafsisha mchakato.

PS kutoka kwa mtafsiri

Soma pia kwenye blogi yetu:

Chanzo: mapenzi.com

Kuongeza maoni