GNU/Linux >> Belajar Linux >  >> Linux

Membangun wadah Linux dengan tangan menggunakan ruang nama

Belum lama ini, saya menulis sebuah artikel yang mengulas tentang ruang nama yang paling umum. Informasinya bagus untuk dimiliki, dan sampai batas tertentu, saya yakin Anda dapat memperkirakan bagaimana Anda dapat memanfaatkan pengetahuan ini dengan baik. Biasanya bukan gaya saya untuk membiarkan hal-hal begitu terbuka. Jadi untuk beberapa artikel berikutnya, saya meluangkan waktu untuk mendemonstrasikan beberapa ruang nama yang lebih penting melalui lensa pembuatan wadah Linux primitif. Dalam beberapa hal, saya menuliskan pengalaman saya dengan teknik yang saya gunakan saat memecahkan masalah wadah Linux di situs klien. Dengan mengingat hal itu, saya mulai dengan fondasi wadah apa pun, terutama jika keamanan menjadi perhatian.

Sedikit tentang kemampuan Linux

Keamanan pada sistem Linux dapat mengambil banyak bentuk. Untuk tujuan artikel ini, saya terutama memperhatikan keamanan dalam hal izin file. Sebagai pengingat, semua yang ada di sistem Linux adalah semacam file, dan oleh karena itu izin file adalah garis pertahanan pertama terhadap aplikasi yang mungkin berperilaku tidak semestinya.

Cara utama Linux menangani izin file adalah melalui implementasi pengguna . Ada pengguna biasa, yang Linux menerapkan pemeriksaan hak istimewa, dan ada superuser yang melewati sebagian besar (jika tidak semua) pemeriksaan. Singkatnya, model Linux asli adalah semua-atau-tidak sama sekali.

Untuk menyiasatinya, beberapa program binari memiliki set uid sedikit diatur pada mereka. Pengaturan ini memungkinkan program untuk dijalankan sebagai pengguna yang memiliki biner. passwd utilitas adalah contoh yang baik untuk ini. Setiap pengguna dapat menjalankan utilitas ini pada sistem. Perlu memiliki hak istimewa yang lebih tinggi pada sistem untuk berinteraksi dengan shadow file, yang menyimpan hash untuk kata sandi pengguna di sistem Linux. Sedangkan passwd binary memiliki pemeriksaan bawaan untuk memastikan bahwa satu pengguna normal tidak dapat mengubah kata sandi pengguna lain, banyak aplikasi tidak memiliki tingkat pengawasan yang sama, terutama jika administrator sistem mengaktifkan set uid sedikit.

kemampuanLinux diciptakan untuk menyediakan aplikasi model keamanan yang lebih terperinci. Alih-alih menjalankan biner sebagai root, Anda hanya dapat menerapkan kemampuan khusus yang diperlukan aplikasi agar efektif. Pada Kernel Linux 5.1, ada 38 kemampuan. Halaman manual untuk kapabilitas sebenarnya ditulis dengan cukup baik dan menggambarkan setiap kapabilitas.

kumpulan kemampuan adalah cara di mana kemampuan dapat diberikan ke utas. Singkatnya, ada lima set kemampuan total, tetapi untuk diskusi ini, hanya dua di antaranya yang relevan:Efektif dan Diizinkan.

Efektif :Kernel memverifikasi setiap tindakan yang diistimewakan dan memutuskan apakah akan mengizinkan atau melarang panggilan sistem. Jika utas atau file memiliki efektif kapabilitas, Anda diizinkan untuk melakukan tindakan yang terkait dengan kapabilitas efektif.

Diizinkan :Kemampuan yang diizinkan belum aktif. Namun, jika suatu proses telah diizinkan kapabilitas, artinya proses itu sendiri dapat memilih untuk meningkatkan hak istimewanya menjadi hak istimewa yang efektif.

Untuk melihat kemampuan apa yang mungkin dimiliki proses tertentu, Anda dapat menjalankan getpcaps ${PID} memerintah. Output dari perintah ini akan terlihat berbeda tergantung pada distribusi Linux. Di RHEL/CentOS Anda akan mendapatkan seluruh daftar kemampuan:

[root@CentOS8 ~]# getpcaps $$
Capabilities for `1304': = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,38,39+ep

Jika Anda menjalankan perintah man 7 capabilities , Anda akan menemukan daftar semua kemampuan ini bersama dengan deskripsi untuk masing-masing. Di beberapa distribusi, seperti Ubuntu atau Arch, menjalankan perintah yang sama hanya akan menghasilkan ini:

[root@Arch ~]# getpcaps $$
414429: =ep

Ada spasi putih sebelum = tanda. Spasi putih ini dapat dipertukarkan dengan kata kunci semua . Seperti yang mungkin sudah Anda duga, ini berarti bahwa semua kemampuan yang tersedia pada sistem diberikan di E efektif dan P set kemampuan yang dipancarkan.

Mengapa ini penting? Pertama, set kemampuan terkait dengan ruang nama pengguna (yang saya bahas di bawah). Untuk saat ini, artinya setiap namespace akan memiliki serangkaian kemampuan sendiri yang hanya berlaku untuk miliknya ruang nama. Misalkan Anda memiliki namespace bernama dibatasi . Ada kemungkinan bahwa dibatasi penampilan seperti itu memiliki semua kemampuan yang tepat seperti yang terlihat dengan getpcaps memerintah. Namun, jika dibatasi dibuat oleh proses dan namespace yang tidak memiliki set kemampuan penuh (seperti pengguna normal), dibatasi tidak dapat diberikan izin lebih pada sistem daripada proses pembuatan.

Singkatnya, kapabilitas, meskipun bukan teknologi namespace, bekerja bersama dalam menentukan apa dan bagaimana proses di dalam namespace dapat dilakukan.

[ Anda mungkin juga menikmati: Menjalankan Podman tanpa root sebagai pengguna non-root ]

Ruang nama pengguna

Sebelum Anda mendalami pembuatan namespace pengguna, berikut adalah ringkasan singkat tentang tujuan namespace ini. Seperti yang saya bahas di artikel sebelumnya, nama pengguna, dan akhirnya nomor identifikasi pengguna (UID), adalah salah satu lapisan keamanan yang akan digunakan sistem untuk memastikan bahwa orang dan proses tidak mengakses hal-hal yang tidak diizinkan.

Teori di balik ruang nama pengguna

Ruang nama pengguna adalah cara untuk wadah (satu set proses yang terisolasi) untuk memiliki serangkaian izin yang berbeda dari sistem itu sendiri. Setiap penampung mewarisi izinnya dari pengguna yang membuat ruang nama pengguna baru. Misalnya, di sebagian besar sistem Linux, ID pengguna biasa dimulai pada atau di atas 1000. Sepanjang sisa seri ini, saya menggunakan pengguna bernama container-user , yang memiliki ID berikut (konteks SELinux dihilangkan untuk demo ini):

uid=1000(container-user) gid=1000(container-user) groups=1000(container-user)

Penting untuk dicatat bahwa kecuali secara sengaja dibatasi oleh administrator sistem, setiap pengguna dapat, secara teori, membuat ruang nama pengguna baru. Namun, ini tidak memberikan kebingungan apa pun dari administrator pada sistem itu sendiri. Ruang nama pengguna adalah hierarki. Perhatikan diagram di bawah ini:

Dalam diagram ini, garis hitam menunjukkan aliran penciptaan. Pengguna kontainer-pengguna membuat namespace untuk pengguna yang disebut pengguna aplikasi . Secara teori, ini akan menjadi ujung depan web atau aplikasi lain. Selanjutnya, pengguna aplikasi membuat ruang nama pengguna untuk pengguna-java . Di ruang nama ini, pengguna-java membuat namespace untuk db-user .

Karena ini adalah hierarki, pengguna penampung dapat melihat dan mengakses semua file yang dibuat oleh salah satu ruang nama yang dihasilkan dari UID-nya. Demikian pula, karena root pengguna di sistem Linux dapat melihat dan berinteraksi dengan semua file pada sistem, termasuk yang dibuat oleh container-user , akar pengguna (diwakili oleh garis merah) dapat memiliki otoritas total atas semua ruang nama.

Namun, kebalikannya tidak benar. pengguna db pengguna, dalam hal ini, tidak dapat melihat atau berinteraksi dengan apa pun di atasnya. Jika pemetaan ID tetap sama (kebijakan default), pengguna aplikasi , pengguna java , dan pengguna-db semua memiliki UID yang sama. Namun, meskipun mereka berbagi UID yang sama, pengguna db tidak dapat berinteraksi dengan pengguna java , yang tidak dapat berinteraksi dengan pengguna aplikasi , dan seterusnya.

Setiap izin yang diberikan di ruang nama pengguna hanya berlaku di ruang nama sendiri dan mungkin ruang nama di bawahnya.

Langsung dengan ruang nama pengguna

Untuk membuat ruang nama pengguna baru, cukup gunakan unshare -U perintah:

[container-user@localhost ~]$ PS1='\u@app-user$ ' unshare -U
nobody@app-user$

Perintah di atas menyertakan PS1 variabel yang hanya mengubah shell sehingga lebih mudah untuk menentukan di mana namespace shell aktif. Menariknya, Anda akan melihat bahwa pengguna adalah bukan siapa-siapa :

nobody@app-user$ whoami
nobody
nobody@app-user$ id
uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)

Ini karena, secara default, tidak ada pemetaan ID pengguna yang dilakukan. Saat tidak ada pemetaan yang ditentukan, namespace hanya menggunakan aturan sistem Anda untuk menentukan cara menangani pengguna yang tidak ditentukan.

Namun, jika Anda membuat namespace seperti ini:

PS1='\u@app-user$ ' unshare -Ur

Pemetaan akan dibuat secara otomatis untuk Anda:

root@app-user$ cat /proc/$$/uid_map
         0       1000       1

File ini mewakili yang berikut:

ID-inside-ns      ID-outside-ns      range

Rentang value mewakili jumlah pengguna yang akan dipetakan. Misalnya, jika ini 0 1000 4 , pemetaannya akan seperti ini

0    1000
1    1001
2    1002
3    1003

Dan seterusnya. Sering kali, Anda hanya benar-benar peduli dengan root pemetaan pengguna, tetapi opsi tersedia jika diinginkan. Apa yang terjadi saat Anda membuat pengguna-java ruang nama?

root@app-user$ PS1='\u@java-user$ ' unshare -Ur
root@java-user$ 

Seperti yang diharapkan, prompt shell berubah, dan Anda adalah pengguna root, tetapi seperti apa pemetaan UID?

root@java-user$ cat /proc/$$/uid_map
         0          0          1

Anda lihat sekarang, Anda memiliki 0 ke 0 pemetaan. Itu karena pengguna yang membuat namespace baru digunakan untuk proses pemetaan ID. Sejak Anda root di namespace sebelumnya, namespace baru memiliki pemetaan root untuk mengakar . Namun, karena root di pengguna aplikasi namespace tidak memiliki root pada sistem, namespace baru tidak root pengguna.

Selain hanya memeriksa uid_map , Anda juga dapat memverifikasi dari luar namespace apakah dua proses berada dalam namespace yang sama. Tentu saja, Anda perlu menemukan PID prosesnya terlebih dahulu, tetapi dengan itu, Anda dapat menjalankan perintah berikut:

readlink /proc/$PID/ns/user

Untuk membuatnya lebih mudah, saya menjalankan yang berikut ini:

[container-user@localhost ~]$ PS1='\u@app-user$ ' unshare -Ur
root@app-user$ sleep 100000

Di terminal lain, saya menggali PID dan menggunakan readlink perintah pada PID itu serta shell saat ini:

[root@localhost ~]# readlink /proc/1307/ns/user 
user:[4026532275]

[root@localhost ~]# readlink /proc/$$/ns/user
user:[4026531837]

Seperti yang Anda lihat, tautan pengguna berbeda. Jika mereka beroperasi di namespace yang sama, akan terlihat seperti ini:

[root@localhost ~]# readlink /proc/1424/ns/user 
user:[4026532275]

[root@localhost ~]# readlink /proc/1307/ns/user 
user:[4026532275]

Keuntungan terbesar dari namespace pengguna adalah kemampuan untuk menjalankan container tanpa hak akses root. Selain itu, bergantung pada cara Anda menyiapkan pemetaan UID, Anda dapat sepenuhnya menghindari pengguna super di dalam ruang nama pengguna tertentu. Ini berarti tidak mungkin menjalankan proses istimewa apa pun di dalam jenis namespace ini.

Catatan :Pengguna namespace mengatur setiap namespace. Ini berarti kemampuan namespace berhubungan langsung dengan kemampuan pengguna induknya ruang nama.

akar asli, penuh ruang nama pengguna memiliki semua ruang nama pada sistem dalam diagram di bawah ini. Hubungan ini berpotensi menjadi dua arah. Jika proses berjalan di net namespace berjalan sebagai root , ini dapat memengaruhi semua proses lain yang dimiliki oleh root ruang nama pengguna. Namun, saat membuat ruang nama pengguna yang tidak memiliki hak istimewa memungkinkan ruang nama pengguna baru untuk mengakses sumber daya di ruang nama lain, itu mungkin tidak mengubahnya karena tidak memilikinya. Jadi, sementara proses di namespace unprivileged dapat ping sebuah IP (yang bergantung pada net namespace), mungkin tidak mengubah konfigurasi jaringan host.

Banyak hal di luar apa yang Anda anggap sebagai wadah Linux menggunakan ruang nama. Format pengemasan Linux Flatpak menggunakan ruang nama pengguna serta beberapa teknologi lain untuk menyediakan kotak pasir aplikasi. Flatpaks membundel semua pustaka aplikasi dalam file distribusi paket yang sama. Hal ini memungkinkan mesin Linux menerima aplikasi terbaru tanpa harus khawatir apakah Anda memiliki versi glibc yang benar diinstal, misalnya. Kemampuan untuk memiliki ini di ruang nama pengguna mereka sendiri berarti bahwa (secara teori) proses yang salah di dalam flatpak tidak dapat mengubah (atau bahkan mungkin mengakses) file atau proses apa pun di luar ruang nama.

[ Memulai container? Lihat kursus gratis ini. Menyebarkan aplikasi kemas:Tinjauan teknis. ]

Menutup

Penggunaan ruang nama pengguna saja tidak menyelesaikan masalah yang coba ditangani oleh Flatpak dan lainnya. Sementara ruang nama pengguna merupakan bagian integral dari cerita keamanan dan kemampuan ruang nama lain, mereka tidak memberikan banyak hal sendiri. Ada banyak hal yang perlu dipertimbangkan saat membuat ruang nama baru yang terisolasi. Di artikel berikutnya, saya akan membahas penggunaan mount namespace bersama dengan namespace pengguna untuk membuat chroot -Lingkungan seperti dengan ruang nama.

Jika Anda mencari beberapa tantangan untuk membantu memperkuat pemahaman Anda, cobalah memetakan berbagai pengguna ke dalam namespace baru. Apa yang terjadi jika Anda memetakan seluruh rentang ke dalam namespace? Apakah mungkin untuk menjadi pengguna Apache di ruang nama yang tidak memiliki hak istimewa? Apa implikasi keamanan untuk menulis uid_map yang buruk mengajukan? (Petunjuk :Anda akan membutuhkan dua cangkang terbuka; satu untuk membuat dan tinggal di dalam namespace baru dan yang lainnya untuk menulis uid_map dan gid_map file. Jika Anda kesulitan dengan ini, kirimkan saya baris di Twitter @linuxovens).


Linux
  1. Ruang Nama Linux

  2. 5 gambar kontainer Linux favorit saya

  3. Membangun wadah dengan tangan menggunakan ruang nama:Ruang nama UTS

  1. Debug Linux menggunakan ProcDump

  2. Linux – Kernel:Dukungan Namespaces?

  3. 50 Tutorial Sysadmin UNIX / Linux

  1. Menggunakan Perintah ripgrep (rg) di Linux

  2. Kali Linux di Android menggunakan Linux Deploy

  3. Contoh penggunaan getnstimeofday di kernel Linux