Seccomp dalam Kubernetes: 7 perkara yang anda perlu tahu dari awal lagi

Catatan. terjemah: Kami membentangkan kepada perhatian anda terjemahan artikel oleh jurutera keselamatan aplikasi kanan di syarikat British ASOS.com. Dengan itu, beliau memulakan satu siri penerbitan khusus untuk meningkatkan keselamatan di Kubernetes melalui penggunaan seccom. Sekiranya pembaca menyukai pengenalan, kami akan mengikuti penulis dan meneruskan bahan-bahan masa depannya mengenai topik ini.

Seccomp dalam Kubernetes: 7 perkara yang anda perlu tahu dari awal lagi

Artikel ini adalah yang pertama dalam satu siri siaran tentang cara membuat profil seccomp dengan semangat SecDevOps, tanpa menggunakan sihir dan sihir. Dalam Bahagian 1, saya akan membincangkan asas dan butiran dalaman untuk melaksanakan seccomp dalam Kubernetes.

Ekosistem Kubernetes menawarkan pelbagai cara untuk mengamankan dan mengasingkan bekas. Artikel tersebut adalah mengenai Mod Pengkomputeran Selamat, juga dikenali sebagai sekomp. Intipatinya adalah untuk menapis panggilan sistem yang tersedia untuk dilaksanakan oleh bekas.

Mengapa ia penting? Bekas hanyalah proses yang dijalankan pada mesin tertentu. Dan ia menggunakan kernel sama seperti aplikasi lain. Jika kontena boleh melakukan sebarang panggilan sistem, tidak lama lagi perisian hasad akan mengambil kesempatan daripada ini untuk memintas pengasingan bekas dan menjejaskan aplikasi lain: maklumat memintas, menukar tetapan sistem, dsb.

profil seccom menentukan panggilan sistem yang harus dibenarkan atau dilumpuhkan. Masa jalan kontena mengaktifkannya apabila ia bermula supaya kernel boleh memantau pelaksanaannya. Menggunakan profil sedemikian membolehkan anda mengehadkan vektor serangan dan mengurangkan kerosakan jika mana-mana program di dalam bekas (iaitu, kebergantungan anda, atau kebergantungan mereka) mula melakukan sesuatu yang tidak dibenarkan untuk dilakukan.

Mencapai asas

Profil seccom asas merangkumi tiga elemen: defaultAction, architectures (Atau archMap) Dan 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-seccom.json)

defaultAction menentukan nasib lalai mana-mana panggilan sistem yang tidak dinyatakan dalam bahagian syscalls. Untuk memudahkan urusan, mari fokus pada dua nilai utama yang akan digunakan:

  • SCMP_ACT_ERRNO — menyekat pelaksanaan panggilan sistem,
  • SCMP_ACT_ALLOW - membenarkan.

Dalam seksyen architectures seni bina sasaran disenaraikan. Ini penting kerana penapis itu sendiri, digunakan pada peringkat kernel, bergantung pada pengecam panggilan sistem, dan bukan pada nama mereka yang dinyatakan dalam profil. Masa jalan kontena akan memadankannya dengan pengecam sebelum digunakan. Ideanya ialah panggilan sistem boleh mempunyai ID yang berbeza sepenuhnya bergantung pada seni bina sistem. Contohnya, panggilan sistem recvfrom (digunakan untuk menerima maklumat daripada soket) mempunyai ID = 64 pada sistem x64 dan ID = 517 pada x86. ia adalah anda boleh mencari senarai semua panggilan sistem untuk seni bina x86-x64.

Dalam bahagian syscalls menyenaraikan semua panggilan sistem dan menentukan perkara yang perlu dilakukan dengannya. Sebagai contoh, anda boleh membuat senarai putih dengan menetapkan defaultAction pada SCMP_ACT_ERRNO, dan panggilan dalam bahagian syscalls tugaskan SCMP_ACT_ALLOW. Oleh itu, anda hanya membenarkan panggilan yang dinyatakan dalam bahagian tersebut syscalls, dan melarang semua yang lain. Untuk senarai hitam anda harus menukar nilai defaultAction dan tindakan sebaliknya.

Sekarang kita harus mengatakan beberapa perkataan tentang nuansa yang tidak begitu jelas. Sila ambil perhatian bahawa pengesyoran di bawah menganggap bahawa anda menggunakan barisan aplikasi perniagaan pada Kubernetes dan anda mahu ia dijalankan dengan jumlah keistimewaan yang paling sedikit.

1. AllowPrivilegeEscalation=false

В securityContext bekas mempunyai parameter AllowPrivilegeEscalation. Jika ia dipasang di false, bekas akan bermula dengan (on) sedikit no_new_priv. Maksud parameter ini jelas dari namanya: ia menghalang bekas daripada melancarkan proses baharu dengan lebih banyak keistimewaan daripada yang dimilikinya sendiri.

Kesan sampingan pilihan ini ditetapkan kepada true (lalai) ialah masa jalan kontena menggunakan profil seccom pada permulaan proses permulaan. Oleh itu, semua panggilan sistem yang diperlukan untuk menjalankan proses masa jalan dalaman (cth menetapkan ID pengguna/kumpulan, menggugurkan keupayaan tertentu) mesti didayakan dalam profil.

Kepada bekas yang melakukan perkara remeh echo hi, kebenaran berikut akan diperlukan:

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

... bukannya ini:

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

Tetapi sekali lagi, mengapa ini menjadi masalah? Secara peribadi, saya akan mengelak daripada menyenarai putih panggilan sistem berikut (melainkan terdapat keperluan sebenar untuknya): capset, set_tid_address, setgid, setgroups и setuid. Walau bagaimanapun, cabaran sebenar ialah dengan membenarkan proses yang anda tidak mempunyai kawalan langsung, anda mengikat profil pada pelaksanaan masa jalan kontena. Dalam erti kata lain, suatu hari nanti anda mungkin mendapati bahawa selepas mengemas kini persekitaran masa jalan kontena (sama ada oleh anda atau, lebih berkemungkinan, oleh pembekal perkhidmatan awan), kontena tiba-tiba berhenti berjalan.

Petua # 1: Jalankan bekas dengan AllowPrivilegeEscaltion=false. Ini akan mengurangkan saiz profil seccom dan menjadikannya kurang sensitif terhadap perubahan dalam persekitaran masa jalan kontena.

2. Menetapkan profil seccom pada tahap kontena

Profil seccomp boleh ditetapkan pada tahap pod:

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

...atau pada tahap kontena:

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

Sila ambil perhatian bahawa sintaks di atas akan berubah apabila Kubernetes seccomp akan menjadi GA (acara ini dijangka dalam keluaran seterusnya Kubernetes - 1.18 - lebih kurang transl.).

Tidak ramai yang tahu bahawa Kubernetes selalu ada pepijatyang menyebabkan profil seccom digunakan pada jeda bekas. Persekitaran masa jalan sebahagiannya mengimbangi kekurangan ini, tetapi bekas ini tidak hilang daripada pod, kerana ia digunakan untuk mengkonfigurasi infrastrukturnya.

Masalahnya ialah bekas ini sentiasa bermula dengan AllowPrivilegeEscalation=true, membawa kepada masalah yang disuarakan dalam perenggan 1, dan ini tidak boleh diubah.

Dengan menggunakan profil seccomp di peringkat kontena, anda mengelakkan perangkap ini dan boleh membuat profil yang disesuaikan dengan bekas tertentu. Ini perlu dilakukan sehingga pembangun membetulkan pepijat dan versi baharu (mungkin 1.18?) tersedia untuk semua orang.

Petua # 2: Tetapkan profil seccom pada tahap kontena.

Dalam erti kata yang praktikal, peraturan ini biasanya berfungsi sebagai jawapan universal kepada soalan: "Mengapa profil seccomp saya berfungsi dengan docker runtetapi tidak berfungsi selepas digunakan ke kluster Kubernetes?

3. Gunakan runtime/default sahaja sebagai pilihan terakhir

Kubernetes mempunyai dua pilihan untuk profil terbina dalam: runtime/default и docker/default. Kedua-duanya dilaksanakan oleh masa jalan kontena, bukan Kubernetes. Oleh itu, ia mungkin berbeza bergantung pada persekitaran masa jalan yang digunakan dan versinya.

Dalam erti kata lain, akibat daripada menukar masa jalan, bekas mungkin mempunyai akses kepada set panggilan sistem yang berbeza, yang mungkin digunakan atau tidak. Kebanyakan masa jalan digunakan Pelaksanaan Docker. Jika anda ingin menggunakan profil ini, sila pastikan ia sesuai untuk anda.

Profil docker/default telah ditamatkan sejak Kubernetes 1.11, jadi elakkan menggunakannya.

Pada pendapat saya, profil runtime/default sangat sesuai untuk tujuan ia dicipta: melindungi pengguna daripada risiko yang berkaitan dengan melaksanakan arahan docker run pada kereta mereka. Walau bagaimanapun, apabila ia berkaitan dengan aplikasi perniagaan yang dijalankan pada kluster Kubernetes, saya berani berhujah bahawa profil sedemikian adalah terlalu terbuka dan pembangun harus menumpukan pada mencipta profil untuk aplikasi mereka (atau jenis aplikasi).

Petua # 3: Buat profil seccom untuk aplikasi tertentu. Jika ini tidak mungkin, buat profil untuk jenis aplikasi, contohnya, buat profil lanjutan yang merangkumi semua API web aplikasi Golang. Hanya gunakan runtime/default sebagai pilihan terakhir.

Dalam siaran akan datang, saya akan membincangkan cara membuat profil seccomp yang diilhamkan oleh SecDevOps, mengautomasikannya dan mengujinya dalam saluran paip. Dengan kata lain, anda tidak mempunyai alasan untuk tidak menaik taraf kepada profil khusus aplikasi.

4. Unconfined BUKAN pilihan.

Daripada audit keselamatan Kubernetes pertama ternyata secara lalai seccom dilumpuhkan. Ini bermakna jika anda tidak menetapkan PodSecurityPolicy, yang akan membolehkannya dalam kelompok, semua pod yang profil seccomp tidak ditentukan akan berfungsi seccomp=unconfined.

Beroperasi dalam mod ini bermakna seluruh lapisan penebat hilang yang melindungi kluster. Pendekatan ini tidak disyorkan oleh pakar keselamatan.

Petua # 4: Tiada bekas dalam gugusan harus berjalan masuk seccomp=unconfined, terutamanya dalam persekitaran pengeluaran.

5. "Mod audit"

Perkara ini bukan unik untuk Kubernetes, tetapi masih termasuk dalam kategori "perkara yang perlu diketahui sebelum anda bermula".

Seperti yang berlaku, membuat profil seccomp sentiasa mencabar dan sangat bergantung pada percubaan dan kesilapan. Hakikatnya ialah pengguna tidak mempunyai peluang untuk menguji mereka dalam persekitaran pengeluaran tanpa mengambil risiko "menggugurkan" aplikasi.

Selepas keluaran kernel Linux 4.14, ia menjadi mungkin untuk menjalankan bahagian profil dalam mod audit, merekodkan maklumat tentang semua panggilan sistem dalam syslog, tetapi tanpa menyekatnya. Anda boleh mengaktifkan mod ini menggunakan parameter SCMT_ACT_LOG:

SCMP_ACT_LOG: seccomp tidak akan menjejaskan urutan yang membuat panggilan sistem jika ia tidak sepadan dengan mana-mana peraturan dalam penapis, tetapi maklumat tentang panggilan sistem akan direkodkan.

Berikut ialah strategi biasa untuk menggunakan ciri ini:

  1. Benarkan panggilan sistem yang diperlukan.
  2. Sekat panggilan daripada sistem yang anda tahu tidak akan berguna.
  3. Rekod maklumat tentang semua panggilan lain dalam log.

Contoh ringkas kelihatan seperti ini:

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

Tetapi ingat bahawa anda perlu menyekat semua panggilan yang anda tahu tidak akan digunakan dan yang berpotensi membahayakan kluster. Asas yang baik untuk menyusun senarai adalah rasmi Dokumentasi Docker. Ia menerangkan secara terperinci panggilan sistem mana yang disekat dalam profil lalai dan sebabnya.

Walau bagaimanapun, terdapat satu tangkapan. Walaupun SCMT_ACT_LOG disokong oleh kernel Linux sejak akhir 2017, ia memasuki ekosistem Kubernetes hanya baru-baru ini. Oleh itu, untuk menggunakan kaedah ini anda memerlukan kernel Linux 4.14 dan versi runC tidak lebih rendah v1.0.0-rc9.

Petua # 5: Profil mod audit untuk ujian dalam pengeluaran boleh dibuat dengan menggabungkan senarai hitam dan putih, dan semua pengecualian boleh dilog.

6. Gunakan senarai putih

Penyenaraian putih memerlukan usaha tambahan kerana anda perlu mengenal pasti setiap panggilan yang mungkin diperlukan oleh aplikasi, tetapi pendekatan ini meningkatkan keselamatan dengan ketara:

Adalah sangat disyorkan untuk menggunakan pendekatan senarai putih kerana ia lebih mudah dan lebih dipercayai. Senarai hitam perlu dikemas kini apabila panggilan sistem yang berpotensi berbahaya (atau bendera/pilihan berbahaya jika terdapat dalam senarai hitam) ditambahkan. Di samping itu, selalunya mungkin untuk menukar perwakilan parameter tanpa mengubah intipatinya dan dengan itu memintas sekatan senarai hitam.

Untuk aplikasi Go, saya membangunkan alat khas yang mengiringi aplikasi dan mengumpulkan semua panggilan yang dibuat semasa pelaksanaan. Sebagai contoh, untuk aplikasi berikut:

package main

import "fmt"

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

... mari kita lancarkan gosystract seperti ini:

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

... dan kami mendapat hasil berikut:

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

Buat masa ini, ini hanyalah satu contoh—butiran lanjut tentang alatan akan menyusul.

Petua # 6: Benarkan hanya panggilan yang anda perlukan dan sekat semua panggilan lain.

7. Letakkan asas yang betul (atau bersedia untuk tingkah laku yang tidak dijangka)

Kernel akan menguatkuasakan profil tanpa mengira apa yang anda tulis di dalamnya. Walaupun ia bukan apa yang anda mahukan. Contohnya, jika anda menyekat akses kepada panggilan seperti exit atau exit_group, bekas tidak akan dapat ditutup dengan betul dan juga arahan mudah seperti echo hi gantung diao untuk tempoh yang tidak ditentukan. Akibatnya, anda akan mendapat penggunaan CPU yang tinggi dalam kelompok:

Seccomp dalam Kubernetes: 7 perkara yang anda perlu tahu dari awal lagi

Dalam kes sedemikian, utiliti boleh datang untuk menyelamatkan strace - ia akan menunjukkan apa masalahnya:

Seccomp dalam Kubernetes: 7 perkara yang anda perlu tahu dari awal lagi
sudo strace -c -p 9331

Pastikan bahawa profil mengandungi semua panggilan sistem yang diperlukan oleh aplikasi semasa masa jalan.

Petua # 7: Beri perhatian kepada perincian dan pastikan semua panggilan sistem yang diperlukan disenarai putih.

Ini menyimpulkan bahagian pertama siri artikel tentang menggunakan seccomp dalam Kubernetes dalam semangat SecDevOps. Dalam bahagian berikut kita akan bercakap tentang mengapa ini penting dan cara mengautomasikan proses.

PS daripada penterjemah

Baca juga di blog kami:

Sumber: www.habr.com

Tambah komen