Seccomp Kubernetes-ում. 7 բան, որ դուք պետք է իմանաք հենց սկզբից

Նշում. թարգմ.Ձեր ուշադրությանն ենք ներկայացնում բրիտանական ASOS.com հավելվածների անվտանգության ավագ ինժեների հոդվածի թարգմանությունը: Դրանով նա սկսում է հրապարակումների շարք՝ նվիրված Kubernetes-ում անվտանգության բարելավմանը seccomp-ի օգտագործման միջոցով։ Եթե ​​ընթերցողներին դուր է գալիս ներածությունը, մենք կհետևենք հեղինակին և կշարունակենք նրա հետագա նյութերն այս թեմայով:

Seccomp Kubernetes-ում. 7 բան, որ դուք պետք է իմանաք հենց սկզբից

Այս հոդվածը առաջինն է մի շարք գրառումների այն մասին, թե ինչպես ստեղծել seccomp պրոֆիլներ SecDevOps-ի ոգով, առանց կախարդության և կախարդության դիմելու: Մաս XNUMX-ում ես կներկայացնեմ Kubernetes-ում seccomp-ի ներդրման հիմունքները և ներքին մանրամասները:

Kubernetes էկոհամակարգն առաջարկում է տարաները ապահովելու և մեկուսացնելու բազմաթիվ եղանակներ: Հոդվածը վերաբերում է Անվտանգ հաշվողական ռեժիմին, որը նաև հայտնի է որպես seccomp. Դրա էությունը կայանում է նրանում, որ զտել համակարգի կանչերը, որոնք հասանելի են բեռնարկղերով կատարման համար:

Ինչու՞ է դա կարևոր: Կոնտեյները պարզապես կոնկրետ մեքենայի վրա աշխատող գործընթաց է: Եվ այն օգտագործում է միջուկը այնպես, ինչպես մյուս հավելվածները: Եթե ​​կոնտեյներները կարողանան կատարել որևէ համակարգային զանգ, շատ շուտով չարամիտ ծրագրերը կօգտվեին դրանից՝ շրջանցելու կոնտեյների մեկուսացումը և ազդելու այլ հավելվածների վրա՝ գաղտնալսելու տեղեկատվությունը, փոխելու համակարգի կարգավորումները և այլն:

seccomp պրոֆիլները սահմանում են, թե որ համակարգային զանգերը պետք է թույլատրվեն կամ անջատվեն: Կոնտեյների գործարկման ժամանակը ակտիվացնում է դրանք, երբ այն սկսվում է, որպեսզի միջուկը կարողանա վերահսկել դրանց կատարումը: Նման պրոֆիլների օգտագործումը թույլ է տալիս սահմանափակել հարձակման վեկտորը և նվազեցնել վնասը, եթե կոնտեյների ներսում գտնվող որևէ ծրագիր (այսինքն՝ ձեր կախվածությունները կամ դրանց կախվածությունները) սկսի անել մի բան, որն անթույլատրելի է:

Հասկանալով հիմունքները

Հիմնական seccomp պրոֆիլը ներառում է երեք տարր. defaultAction, architectures (Կամ archMap) Եվ 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 որոշում է բաժնում չնշված ցանկացած համակարգային զանգի կանխադրված ճակատագիրը syscalls. Ամեն ինչ հեշտացնելու համար եկեք կենտրոնանանք երկու հիմնական արժեքների վրա, որոնք կօգտագործվեն.

  • SCMP_ACT_ERRNO — արգելափակում է համակարգային զանգի կատարումը,
  • SCMP_ACT_ALLOW - թույլ է տալիս:

Բաժին architectures Թիրախային ճարտարապետությունները թվարկված են: Սա կարևոր է, քանի որ ֆիլտրն ինքնին, որը կիրառվում է միջուկի մակարդակում, կախված է համակարգի կանչերի նույնացուցիչներից, այլ ոչ թե պրոֆիլում նշված դրանց անուններից: Կոնտեյների գործարկման ժամանակը դրանք կհամապատասխանի նույնացուցիչներին՝ օգտագործելուց առաջ: Գաղափարն այն է, որ համակարգային զանգերը կարող են ունենալ բոլորովին այլ ID-ներ՝ կախված համակարգի ճարտարապետությունից: Օրինակ՝ համակարգային զանգ recvfrom (օգտագործվում է վարդակից տեղեկատվություն ստանալու համար) ունի ID = 64 x64 համակարգերի վրա և ID = 517 x86-ի վրա: Այստեղ դուք կարող եք գտնել բոլոր համակարգի կանչերի ցանկը x86-x64 ճարտարապետությունների համար:

Բաժնում syscalls թվարկում է բոլոր համակարգային զանգերը և նշում, թե ինչ անել դրանց հետ: Օրինակ, կարող եք ստեղծել սպիտակ ցուցակ՝ կարգավորելով defaultAction մասին SCMP_ACT_ERRNO, և զանգեր բաժնում syscalls նշանակել SCMP_ACT_ALLOW. Այսպիսով, դուք թույլատրում եք միայն բաժնում նշված զանգերը syscalls, և արգելել բոլոր մյուսներին: Սև ցուցակի համար դուք պետք է փոխեք արժեքները defaultAction և հակառակ գործողությունները:

Այժմ պետք է մի քանի խոսք ասել ոչ այնքան ակնհայտ նրբերանգների մասին։ Խնդրում ենք նկատի ունենալ, որ ստորև ներկայացված առաջարկությունները ենթադրում են, որ դուք տեղակայում եք բիզնես հավելվածների շարք Kubernetes-ում և ցանկանում եք, որ դրանք աշխատեն հնարավորինս նվազագույն արտոնություններով:

1. AllowPrivilegeEscalation=կեղծ

В securityContext կոնտեյները ունի պարամետր AllowPrivilegeEscalation. Եթե ​​այն տեղադրված է false, տարաները կսկսվեն (on) բիթ no_new_priv. Այս պարամետրի իմաստը ակնհայտ է անունից. այն թույլ չի տալիս կոնտեյներին նոր գործընթացներ գործարկել ավելի շատ արտոնություններով, քան ինքն ունի:

Այս տարբերակի դրված կողմնակի ազդեցությունը true (կանխադրված) այն է, որ կոնտեյների գործարկման ժամանակը կիրառում է seccomp պրոֆիլը գործարկման գործընթացի հենց սկզբում: Այսպիսով, բոլոր համակարգային զանգերը, որոնք անհրաժեշտ են ներքին գործարկման ժամանակի գործընթացները գործարկելու համար (օրինակ՝ օգտատերերի/խմբերի ID-ների կարգավորում, որոշակի հնարավորությունների հեռացում) պետք է միացված լինեն պրոֆիլում:

Կոնտեյներ, որն աննշան բաներ է անում echo hi, կպահանջվեն հետևյալ թույլտվությունները.

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

... սրանց փոխարեն.

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

Բայց կրկին, ինչու է սա խնդիր: Անձամբ ես կխուսափեի հետևյալ համակարգային զանգերի սպիտակ ցուցակում ներառելուց (եթե դրանց իրական կարիք չկա). capset, set_tid_address, setgid, setgroups и setuid. Այնուամենայնիվ, իրական մարտահրավերն այն է, որ թույլ տալով գործընթացներ, որոնց վրա բացարձակապես վերահսկողություն չունեք, դուք պրոֆիլները կապում եք կոնտեյների գործարկման ժամանակի իրականացման հետ: Այլ կերպ ասած, մի օր դուք կարող եք պարզել, որ կոնտեյների գործարկման միջավայրը թարմացնելուց հետո (կամ ձեր կամ, ավելի հավանական է, ամպային ծառայության մատակարարի կողմից), բեռնարկղերը հանկարծակի դադարում են աշխատել:

Հուշում # 1Օգտագործեք բեռնարկղերը AllowPrivilegeEscaltion=false. Սա կնվազեցնի seccomp պրոֆիլների չափը և դրանք ավելի քիչ զգայուն կդարձնի կոնտեյների գործարկման միջավայրի փոփոխությունների նկատմամբ:

2. Seccomp պրոֆիլների կարգավորում կոնտեյների մակարդակում

Seccomp պրոֆիլը կարող է սահմանվել pod մակարդակում.

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

...կամ կոնտեյների մակարդակում.

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

Խնդրում ենք նկատի ունենալ, որ վերը նշված շարահյուսությունը կփոխվի, երբ Kubernetes seccomp կդառնա Գ.Ա (այս իրադարձությունը սպասվում է Kubernetes-ի հաջորդ թողարկումում՝ 1.18 - մոտավորապես թարգմ.):

Քչերը գիտեն, որ Kubernetes-ը միշտ ունեցել է bugինչը ստիպեց կիրառվել seccomp պրոֆիլների վրա դադար կոնտեյներ. Գործարկման միջավայրը մասամբ փոխհատուցում է այս թերությունը, բայց այս կոնտեյները չի անհետանում պատյաններից, քանի որ այն օգտագործվում է դրանց ենթակառուցվածքը կարգավորելու համար:

Խնդիրն այն է, որ այս կոնտեյները միշտ սկսվում է AllowPrivilegeEscalation=true, հանգեցնելով 1-ին կետում հնչեցված խնդիրներին, և դա հնարավոր չէ փոխել։

Օգտագործելով seccomp պրոֆիլները կոնտեյների մակարդակում, դուք խուսափում եք այս ծուղակից և կարող եք ստեղծել պրոֆիլ, որը հարմարեցված է կոնկրետ կոնտեյների համար: Դա պետք է արվի այնքան ժամանակ, քանի դեռ մշակողները չեն ուղղել սխալը, և նոր տարբերակը (գուցե 1.18՞) հասանելի դառնա բոլորի համար։

Հուշում # 2Սահմանեք seccomp պրոֆիլները կոնտեյների մակարդակում:

Գործնական իմաստով այս կանոնը սովորաբար ծառայում է որպես համընդհանուր պատասխան այն հարցին. «Ինչու է իմ seccomp պրոֆիլն աշխատում. docker runբայց չի աշխատում Kubernetes կլաստերում տեղակայվելուց հետո:

3. Օգտագործեք գործարկման/կանխադրված ժամանակը միայն որպես վերջին միջոց

Kubernetes-ն ունի ներկառուցված պրոֆիլների երկու տարբերակ. runtime/default и docker/default. Երկուսն էլ իրականացվում են կոնտեյների գործարկման ժամանակով, այլ ոչ թե Kubernetes-ով: Հետևաբար, դրանք կարող են տարբերվել՝ կախված գործարկման ժամանակի միջավայրից և դրա տարբերակից:

Այլ կերպ ասած, գործարկման ժամանակի փոփոխման արդյունքում կոնտեյները կարող է մուտք ունենալ համակարգային զանգերի այլ շարք, որը նա կարող է օգտագործել կամ չօգտագործել: Գործարկման ժամանակների մեծ մասը օգտագործում է Դոկերի իրականացում. Եթե ​​ցանկանում եք օգտագործել այս պրոֆիլը, համոզվեք, որ այն հարմար է ձեզ համար:

Անձնագիր docker/default հնացել է Kubernetes 1.11-ից, այնպես որ խուսափեք այն օգտագործելուց:

Իմ կարծիքով՝ պրոֆիլ runtime/default լիովին համապատասխանում է այն նպատակին, որի համար այն ստեղծվել է. պաշտպանել օգտվողներին հրամանի կատարման հետ կապված ռիսկերից docker run իրենց մեքենաների վրա։ Այնուամենայնիվ, երբ խոսքը վերաբերում է Kubernetes կլաստերներով աշխատող բիզնես հավելվածներին, ես կհամարձակվեմ պնդել, որ նման պրոֆիլը չափազանց բաց է, և մշակողները պետք է կենտրոնանան իրենց հավելվածների (կամ հավելվածների տեսակների) համար պրոֆիլներ ստեղծելու վրա:

Հուշում # 3Ստեղծեք seccomp պրոֆիլներ հատուկ հավելվածների համար: Եթե ​​դա հնարավոր չէ, ստեղծեք պրոֆիլներ հավելվածների տեսակների համար, օրինակ՝ ստեղծեք առաջադեմ պրոֆիլ, որը ներառում է Golang հավելվածի բոլոր վեբ API-ները: Օգտագործեք գործարկման/կանխադրված ժամանակը միայն որպես վերջին միջոց:

Հետագա գրառումներում ես կպատմեմ, թե ինչպես ստեղծել SecDevOps-ով ոգեշնչված seccomp պրոֆիլներ, ավտոմատացնել դրանք և փորձարկել դրանք խողովակաշարերում: Այլ կերպ ասած, դուք ոչ մի արդարացում չեք ունենա հավելվածին հատուկ պրոֆիլներ չթարմացնելու համար:

4. Անսահմանափակ լինելը տարբերակ ՉԷ:

Of առաջին Kubernetes անվտանգության աուդիտ պարզվեց, որ լռելյայն seccomp անջատված է. Սա նշանակում է, որ եթե դուք չեք սահմանել PodSecurityPolicy, որը թույլ կտա այն կլաստերում, բոլոր բլոկները, որոնց համար seccomp պրոֆիլը սահմանված չէ, կաշխատեն seccomp=unconfined.

Այս ռեժիմով աշխատելը նշանակում է, որ մեկուսացման ամբողջ շերտը կորել է, որը պաշտպանում է կլաստերը: Այս մոտեցումը խորհուրդ չի տրվում անվտանգության փորձագետների կողմից:

Հուշում # 4Կլաստերում ոչ մի կոնտեյներ չպետք է աշխատի seccomp=unconfined, հատկապես արտադրական միջավայրերում:

5. «Աուդիտի ռեժիմ»

Այս կետը եզակի չէ Kubernetes-ի համար, բայց դեռևս պատկանում է «նախքան սկսելը իմանալու բաներ» կատեգորիային:

Ինչպես պատահում է, seccomp պրոֆիլների ստեղծումը միշտ էլ եղել է դժվար և մեծապես հիմնված է փորձության և սխալի վրա: Փաստն այն է, որ օգտատերերը պարզապես հնարավորություն չունեն փորձարկել դրանք արտադրական միջավայրում՝ առանց հավելվածը «գցելու» վտանգի։

Linux kernel 4.14-ի թողարկումից հետո հնարավոր դարձավ պրոֆիլի մասերը գործարկել աուդիտի ռեժիմում՝ գրանցելով բոլոր համակարգային զանգերի մասին տեղեկատվությունը syslog-ում, բայց առանց դրանք արգելափակելու: Դուք կարող եք ակտիվացնել այս ռեժիմը, օգտագործելով պարամետրը SCMT_ACT_LOG:

SCMP_ACT_LOGseccomp-ը չի ազդի համակարգային զանգ կատարող շղթայի վրա, եթե այն չի համընկնում զտիչի որևէ կանոնի վրա, սակայն համակարգային զանգի մասին տեղեկատվությունը կգրանցվի:

Ահա այս հատկանիշն օգտագործելու բնորոշ ռազմավարությունը.

  1. Թույլատրել համակարգային զանգերը, որոնք անհրաժեշտ են:
  2. Արգելափակեք համակարգից զանգերը, որոնք դուք գիտեք, որ օգտակար չեն լինի:
  3. Գրանցեք բոլոր այլ զանգերի մասին տեղեկությունները գրանցամատյանում:

Պարզեցված օրինակն այսպիսի տեսք ունի.

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

Բայց հիշեք, որ դուք պետք է արգելափակեք բոլոր զանգերը, որոնք գիտեք, որ չեն օգտագործվելու, և որոնք կարող են վնասել կլաստերին: Ցուցակ կազմելու լավ հիմք է պաշտոնյան Docker փաստաթղթեր. Այն մանրամասն բացատրում է, թե որ համակարգային զանգերն են արգելափակված լռելյայն պրոֆիլում և ինչու:

Այնուամենայնիվ, կա մեկ բռնում. Չնայած նրան SCMT_ACT_LOG Linux միջուկի կողմից 2017 թվականի վերջից աջակցվող, այն համեմատաբար վերջերս է մտել Kubernetes էկոհամակարգ: Հետևաբար, այս մեթոդն օգտագործելու համար ձեզ անհրաժեշտ կլինի Linux միջուկ 4.14 և runC տարբերակ ոչ ցածր v1.0.0-rc9.

Հուշում # 5Արտադրության մեջ փորձարկման աուդիտի ռեժիմի պրոֆիլը կարող է ստեղծվել սև և սպիտակ ցուցակները համադրելով, և բոլոր բացառությունները կարող են գրանցվել:

6. Օգտագործեք սպիտակ ցուցակներ

Սպիտակ ցուցակը լրացուցիչ ջանքեր է պահանջում, քանի որ դուք պետք է բացահայտեք յուրաքանչյուր զանգ, որը կարող է անհրաժեշտ լինել հավելվածին, սակայն այս մոտեցումը զգալիորեն բարելավում է անվտանգությունը.

Խստորեն խորհուրդ է տրվում օգտագործել սպիտակ ցուցակի մոտեցումը, քանի որ այն ավելի պարզ է և հուսալի: Սև ցուցակը պետք է թարմացվի, երբ ավելացվում է պոտենցիալ վտանգավոր համակարգային զանգ (կամ վտանգավոր դրոշակ/տարբերակ, եթե այն գտնվում է սև ցուցակում): Բացի այդ, հաճախ հնարավոր է փոխել պարամետրի ներկայացումը առանց դրա էությունը փոխելու և դրանով իսկ շրջանցել սև ցուցակի սահմանափակումները:

Go հավելվածների համար ես մշակեցի հատուկ գործիք, որն ուղեկցում է հավելվածին և հավաքում է կատարման ընթացքում կատարված բոլոր զանգերը: Օրինակ՝ հետևյալ հավելվածի համար.

package main

import "fmt"

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

... եկեք գործարկենք gosystract այնպես որ,

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

... և ստանում ենք հետևյալ արդյունքը.

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

Առայժմ սա ընդամենը օրինակ է. գործիքների մասին ավելի մանրամասն կհետևեն:

Հուշում # 6Թույլ տվեք միայն այն զանգերը, որոնք ձեզ իսկապես անհրաժեշտ են և արգելափակեք բոլոր մյուսներին:

7. Դրեք ճիշտ հիմքերը (կամ պատրաստվեք անսպասելի վարքի)

Միջուկը կգործադրի պրոֆիլը, անկախ նրանից, թե ինչ եք գրում դրանում: Նույնիսկ եթե դա հենց այնպես չէ, ինչ ուզում էիր: Օրինակ, եթե արգելափակեք մուտքը դեպի նման զանգեր exit կամ exit_group, կոնտեյները չի կարողանա ճիշտ փակել և նույնիսկ պարզ հրամանը, ինչպես echo hi կախել նրանo անորոշ ժամկետով. Արդյունքում, դուք կստանաք CPU-ի բարձր օգտագործում կլաստերում.

Seccomp Kubernetes-ում. 7 բան, որ դուք պետք է իմանաք հենց սկզբից

Նման դեպքերում կարող է օգնության գալ կոմունալ ծառայությունը strace - ցույց կտա, թե որն է խնդիրը.

Seccomp Kubernetes-ում. 7 բան, որ դուք պետք է իմանաք հենց սկզբից
sudo strace -c -p 9331

Համոզվեք, որ պրոֆիլները պարունակում են բոլոր համակարգային զանգերը, որոնք անհրաժեշտ են հավելվածին գործարկման ժամանակ:

Հուշում # 7Ուշադրություն դարձրեք մանրամասներին և համոզվեք, որ բոլոր անհրաժեշտ համակարգային զանգերը սպիտակ ցուցակում են:

Սրանով ավարտվում է Kubernetes-ում seccomp-ը SecDevOps-ի ոգով օգտագործելու մասին հոդվածների շարքի առաջին մասը: Հաջորդ մասերում մենք կխոսենք այն մասին, թե ինչու է դա կարևոր և ինչպես ավտոմատացնել գործընթացը:

PS թարգմանչից

Կարդացեք նաև մեր բլոգում.

Source: www.habr.com

Добавить комментарий