Kubernetesdə Seccomp: Əvvəldən bilməli olduğunuz 7 şey

Qeyd. tərcümə.: Böyük Britaniyanın ASOS.com şirkətində tətbiqlərin təhlükəsizliyi üzrə baş mühəndisin məqaləsinin tərcüməsini diqqətinizə təqdim edirik. Bununla o, seccomp istifadə edərək Kubernetesdə təhlükəsizliyin yaxşılaşdırılmasına həsr olunmuş bir sıra nəşrlərə başlayır. Əgər oxucular girişi bəyənsələr, müəllifi izləyəcəyik və onun bu mövzuda gələcək materiallarına davam edəcəyik.

Kubernetesdə Seccomp: Əvvəldən bilməli olduğunuz 7 şey

Bu məqalə SecDevOps ruhunda seccomp profillərini sehr və cadugərliyə müraciət etmədən necə yaratmaq barədə yazılar seriyasından birincisidir. XNUMX-ci hissədə mən Kubernetes-də seccomp tətbiqinin əsaslarını və daxili təfərrüatlarını əhatə edəcəyəm.

Kubernetes ekosistemi konteynerləri qorumaq və təcrid etmək üçün müxtəlif üsullar təklif edir. Məqalə kimi də tanınan Təhlükəsiz Hesablama Rejimi haqqındadır seccomp. Onun mahiyyəti konteynerlər tərəfindən icra üçün mövcud olan sistem çağırışlarını süzgəcdən keçirməkdir.

Niyə vacibdir? Konteyner sadəcə müəyyən bir maşında işləyən bir prosesdir. Və digər proqramlar kimi nüvədən istifadə edir. Konteynerlər hər hansı sistem çağırışlarını yerinə yetirə bilsəydilər, çox keçmədən zərərli proqram bundan istifadə edərək konteyner izolyasiyasından yan keçəcək və digər proqramlara təsir göstərəcək: məlumatı ələ keçirəcək, sistem parametrlərini dəyişdirəcək və s.

seccomp profilləri hansı sistem zənglərinə icazə verilməli və ya söndürülməli olduğunu müəyyən edir. Konteynerin işləmə vaxtı onları işə saldıqda aktivləşdirir ki, nüvə onların icrasına nəzarət edə bilsin. Bu cür profillərdən istifadə etmək sizə hücum vektorunu məhdudlaşdırmağa və konteyner daxilində hər hansı bir proqram (yəni sizin asılılıqlarınız və ya onların asılılıqları) icazə verilməyən işi görməyə başlayarsa, zərəri azaltmağa imkan verir.

Əsaslara keçmək

Əsas seccomp profilinə üç element daxildir: defaultAction, architectures (Və ya archMap) Və 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"
        }
    ]
}

(orta-basic-seccomp.json)

defaultAction bölmədə göstərilməyən istənilən sistem çağırışının standart taleyini müəyyən edir syscalls. İşləri asanlaşdırmaq üçün istifadə olunacaq iki əsas dəyərə diqqət yetirək:

  • SCMP_ACT_ERRNO — sistem çağırışının icrasını bloklayır,
  • SCMP_ACT_ALLOW - imkan verir.

Bölmədə architectures hədəf arxitekturaları sadalanır. Bu vacibdir, çünki kernel səviyyəsində tətbiq olunan filtrin özü profildə göstərilən adlardan deyil, sistem çağırış identifikatorlarından asılıdır. Konteynerin işləmə müddəti istifadə etməzdən əvvəl onları identifikatorlara uyğunlaşdıracaq. İdeya ondan ibarətdir ki, sistem zəngləri sistem arxitekturasından asılı olaraq tamamilə fərqli identifikatorlara malik ola bilər. Məsələn, sistem çağırışı recvfrom (soketdən məlumat almaq üçün istifadə olunur) x64 sistemlərində ID = 64 və x517-da ID = 86-yə malikdir. Burada x86-x64 arxitekturaları üçün bütün sistem çağırışlarının siyahısını tapa bilərsiniz.

Bölmədə syscalls bütün sistem zənglərini sadalayır və onlarla nə edəcəyini müəyyənləşdirir. Məsələn, təyin etməklə ağ siyahı yarada bilərsiniz defaultAction haqqında SCMP_ACT_ERRNO, və bölmədə zənglər syscalls təyin etmək SCMP_ACT_ALLOW. Beləliklə, siz yalnız bölmədə göstərilən zənglərə icazə verirsiniz syscalls, və bütün digərlərini qadağan edin. Qara siyahı üçün dəyərləri dəyişdirməlisiniz defaultAction və əksinə hərəkətlər.

İndi o qədər də aydın olmayan nüanslar haqqında bir neçə kəlmə deməliyik. Nəzərə alın ki, aşağıdakı tövsiyələr Kubernetes-də bir sıra biznes proqramları yerləşdirdiyinizi və onların mümkün olan ən az imtiyazlarla işləməsini istədiyinizi güman edir.

1. AllowPrivilegeEscalation=false

В securityContext konteynerin parametri var AllowPrivilegeEscalation. Əgər quraşdırılıbsa false, konteynerlər ( ilə başlayacaqon) bit no_new_priv. Bu parametrin mənası adından aydındır: konteynerin özündən daha çox imtiyazlarla yeni prosesləri işə salmasına mane olur.

Bu seçimin bir yan təsiri təyin olunur true (standart) konteynerin işləmə vaxtı başlanğıc prosesinin ən əvvəlində seccomp profilini tətbiq etməsidir. Beləliklə, daxili iş vaxtı proseslərini yerinə yetirmək üçün tələb olunan bütün sistem zəngləri (məsələn, istifadəçi/qrup identifikatorlarının təyin edilməsi, müəyyən imkanların ləğvi) profildə aktivləşdirilməlidir.

Önəmsiz şeylər edən konteynerə echo hi, aşağıdakı icazələr tələb olunacaq:

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

...bunların yerinə:

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

Amma yenə deyirəm, niyə bu problemdir? Şəxsən mən aşağıdakı sistem zənglərini ağ siyahıya salmaqdan çəkinərdim (əgər onlara real ehtiyac yoxdursa): capset, set_tid_address, setgid, setgroups и setuid. Bununla belə, əsl problem ondadır ki, üzərində heç bir nəzarəti olmayan proseslərə icazə verməklə, profilləri konteynerin icra müddətinin tətbiqinə bağlayırsınız. Başqa sözlə, bir gün siz konteynerin işləmə mühitini (ya sizin tərəfinizdən, ya da daha çox ehtimal ki, bulud xidməti provayderi tərəfindən) yenilədikdən sonra konteynerlərin işləməsini dayandırdığını görə bilərsiniz.

İpucu # 1: ilə konteynerləri işə salın AllowPrivilegeEscaltion=false. Bu, seccomp profillərinin ölçüsünü azaldacaq və onları konteyner işləmə mühitindəki dəyişikliklərə daha az həssas edəcək.

2. Konteyner səviyyəsində seccomp profillərinin qurulması

Seccomp profili pod səviyyəsində təyin edilə bilər:

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

...və ya konteyner səviyyəsində:

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

Nəzərə alın ki, Kubernetes seccomp olduqda yuxarıdakı sintaksis dəyişəcək GA olacaq (bu hadisə Kubernetes-in növbəti buraxılışında gözlənilir - 1.18 - təqribən tərcümə).

Kubernetesin həmişə olduğunu az adam bilir səhvseccomp profillərinin tətbiq edilməsinə səbəb oldu konteyneri dayandırın. İş vaxtı mühiti bu çatışmazlığı qismən kompensasiya edir, lakin bu konteyner onların infrastrukturunu konfiqurasiya etmək üçün istifadə edildiyi üçün podlardan yox olmur.

Problem ondadır ki, bu konteyner həmişə onunla başlayır AllowPrivilegeEscalation=true1-ci bənddə səslənən problemlərə gətirib çıxarır və bu dəyişdirilə bilməz.

Konteyner səviyyəsində seccomp profillərindən istifadə etməklə siz bu tələdən qaçırsınız və xüsusi konteynerə uyğunlaşdırılmış profil yarada bilərsiniz. Bu, tərtibatçılar səhvi düzəldənə və yeni versiya (bəlkə 1.18?) hamı üçün əlçatan olana qədər edilməlidir.

İpucu # 2: Konteyner səviyyəsində seccomp profillərini təyin edin.

Praktiki mənada bu qayda adətən suala universal cavab rolunu oynayır: “Niyə mənim seccomp profilim onunla işləyir docker runlakin Kubernetes klasterinə yerləşdirdikdən sonra işləmir?

3. İş vaxtı/defoltdan yalnız son çarə kimi istifadə edin

Kubernetesdə quraşdırılmış profillər üçün iki seçim var: runtime/default и docker/default. Hər ikisi Kubernetes deyil, konteyner işləmə vaxtı ilə həyata keçirilir. Buna görə də, onlar istifadə olunan işləmə mühitindən və onun versiyasından asılı olaraq fərqlənə bilər.

Başqa sözlə, iş vaxtının dəyişdirilməsi nəticəsində konteyner istifadə edə və ya istifadə edə bilməyən fərqli sistem zənglərinə çıxış əldə edə bilər. Əksər iş vaxtları istifadə edir Docker tətbiqi. Bu profildən istifadə etmək istəyirsinizsə, onun sizin üçün uyğun olduğundan əmin olun.

Profil docker/default Kubernetes 1.11-dən bəri köhnəlmişdir, ona görə də istifadə etməyin.

Məncə, profil runtime/default yaradıldığı məqsədə mükəmməl uyğun gəlir: istifadəçiləri əmrin icrası ilə bağlı risklərdən qorumaq docker run maşınlarında. Bununla belə, Kubernetes klasterlərində işləyən biznes tətbiqlərinə gəldikdə, belə bir profilin çox açıq olduğunu və tərtibatçıların öz tətbiqləri (və ya tətbiq növləri) üçün profillər yaratmağa diqqət yetirməli olduğunu iddia etməyə cəsarət edərdim.

İpucu # 3: Xüsusi proqramlar üçün seccomp profilləri yaradın. Bu mümkün deyilsə, tətbiq növləri üçün profillər yaradın, məsələn, Golang tətbiqinin bütün veb API-lərini özündə birləşdirən inkişaf etmiş profil yaradın. Yalnız son çarə kimi iş vaxtı/defoltdan istifadə edin.

Gələcək yazılarda SecDevOps-dan ilhamlanmış seccomp profillərinin necə yaradılması, onları avtomatlaşdırması və boru kəmərlərində sınaqdan keçirilməsi haqqında danışacağam. Başqa sözlə, tətbiq üçün xüsusi profillərə yüksəlməmək üçün heç bir bəhanəniz olmayacaq.

4. Məhdudiyyətsiz seçim DEYİL.

Haqqında ilk Kubernetes təhlükəsizlik auditi bir qayda olaraq belə çıxdı seccomp əlil. Bu o deməkdir ki, əgər təyin etməsəniz PodSecurityPolicy, bu, klasterdə imkan verəcək, seccomp profilinin müəyyən edilmədiyi bütün podlar işləyəcək seccomp=unconfined.

Bu rejimdə işləmək, klasteri qoruyan bütün izolyasiya təbəqəsinin itirilməsi deməkdir. Bu yanaşma təhlükəsizlik mütəxəssisləri tərəfindən tövsiyə edilmir.

İpucu # 4: Çoxluqda heç bir konteyner işləməməlidir seccomp=unconfined, xüsusilə istehsal mühitlərində.

5. "Audit rejimi"

Bu nöqtə Kubernetes üçün unikal deyil, lakin yenə də “başlamazdan əvvəl bilməli olduğunuz şeylər” kateqoriyasına aiddir.

Bu baş verdiyi kimi, seccomp profillərinin yaradılması həmişə çətin olub və sınaq və səhvlərə əsaslanıb. Məsələ burasındadır ki, istifadəçilərin sadəcə olaraq tətbiqi “atmaq” riski olmadan istehsal mühitində sınaqdan keçirmək imkanı yoxdur.

Linux kernel 4.14 buraxıldıqdan sonra profilin hissələrini audit rejimində işlətmək, bütün sistem zəngləri haqqında məlumatları syslog-da qeyd etmək, lakin onları bloklamadan mümkün olmuşdur. Parametrdən istifadə edərək bu rejimi aktivləşdirə bilərsiniz SCMT_ACT_LOG:

SCMP_ACT_LOG: filtrdə heç bir qaydaya uyğun gəlmirsə, seccomp sistem çağırışı edən mövzuya təsir etməyəcək, lakin sistem çağırışı haqqında məlumat qeyd olunacaq.

Bu funksiyadan istifadə etmək üçün tipik strategiya budur:

  1. Lazım olan sistem zənglərinə icazə verin.
  2. Faydalı olmayacağını bildiyiniz sistemdən zəngləri bloklayın.
  3. Bütün digər zənglər haqqında məlumatı jurnalda qeyd edin.

Sadələşdirilmiş bir nümunə belə görünür:

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

(orta qarışıq-seccomp.json)

Ancaq unutmayın ki, istifadə olunmayacağını bildiyiniz və klasterə potensial zərər verə biləcək bütün zəngləri bloklamalısınız. Siyahını tərtib etmək üçün yaxşı əsas rəsmidir Docker sənədləri. Bu, standart profildə hansı sistem zənglərinin bloklandığını və nə üçün olduğunu ətraflı izah edir.

Bununla belə, bir tutma var. Baxmayaraq ki SCMT_ACT_LOG 2017-ci ilin sonundan bəri Linux nüvəsi tərəfindən dəstəklənən, Kubernetes ekosisteminə nisbətən yaxınlarda daxil oldu. Buna görə də, bu metoddan istifadə etmək üçün sizə Linux nüvəsi 4.14 və daha aşağı olmayan runC versiyası lazımdır v1.0.0-rc9.

İpucu # 5: İstehsalda sınaq üçün audit rejimi profili ağ və qara siyahıları birləşdirərək yaradıla bilər və bütün istisnalar daxil edilə bilər.

6. Ağ siyahılardan istifadə edin

Ağ siyahı əlavə etmək üçün əlavə səy tələb edir, çünki siz proqrama lazım ola biləcək hər bir zəngi müəyyənləşdirməlisiniz, lakin bu yanaşma təhlükəsizliyi xeyli yaxşılaşdırır:

Daha sadə və daha etibarlı olduğu üçün ağ siyahı yanaşmasından istifadə etmək çox tövsiyə olunur. Potensial təhlükəli sistem çağırışı (və ya qara siyahıdadırsa təhlükəli bayraq/seçim) əlavə edildikdə qara siyahı yenilənməlidir. Bundan əlavə, çox vaxt parametrin mahiyyətini dəyişdirmədən onun təsvirini dəyişdirmək və bununla da qara siyahının məhdudiyyətlərini keçmək mümkündür.

Go proqramları üçün mən tətbiqi müşayiət edən və icra zamanı edilən bütün zəngləri toplayan xüsusi alət hazırladım. Məsələn, aşağıdakı tətbiq üçün:

package main

import "fmt"

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

... başlayaq gosystract beləliklə:

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

... və aşağıdakı nəticəni əldə edirik:

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

Hələlik bu, sadəcə bir nümunədir - alətlər haqqında daha ətraflı məlumat veriləcək.

İpucu # 6: Yalnız həqiqətən ehtiyac duyduğunuz zənglərə icazə verin və digərlərini bloklayın.

7. Düzgün təməl qoyun (və ya gözlənilməz davranışa hazır olun)

Nüvə, nə yazmağınızdan asılı olmayaraq profili tətbiq edəcək. Tam olaraq istədiyiniz kimi olmasa belə. Məsələn, kimi zənglərə girişi bloklasanız exit və ya exit_group, konteyner düzgün və hətta sadə bir əmr kimi bağlana bilməyəcək echo hi onu asıno qeyri-müəyyən müddətə. Nəticədə, klasterdə yüksək CPU istifadəsi əldə edəcəksiniz:

Kubernetesdə Seccomp: Əvvəldən bilməli olduğunuz 7 şey

Belə hallarda yardımçı yardıma gələ bilər strace - problemin nə ola biləcəyini göstərəcək:

Kubernetesdə Seccomp: Əvvəldən bilməli olduğunuz 7 şey
sudo strace -c -p 9331

Profillərdə proqramın işləmə zamanı ehtiyac duyduğu bütün sistem zənglərini ehtiva etdiyinə əmin olun.

İpucu # 7: Detallara diqqət yetirin və bütün lazımi sistem zənglərinin ağ siyahıya salındığından əmin olun.

Bu, SecDevOps ruhunda Kubernetes-də seccomp-dan istifadə ilə bağlı bir sıra məqalələrin birinci hissəsini yekunlaşdırır. Növbəti hissələrdə bunun nə üçün vacib olduğunu və prosesi necə avtomatlaşdırmaq barədə danışacağıq.

Tərcüməçidən PS

Bloqumuzda da oxuyun:

Mənbə: www.habr.com

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