GNU/Linux >> Belajar Linux >  >> Linux

Membangun wadah dengan tangan menggunakan ruang nama:mount namespace

Artikel ini melihat mount namespace dan merupakan yang ketiga dalam seri Namespace Linux. Dalam artikel pertama, saya memberikan pengantar tentang tujuh ruang nama yang paling umum digunakan, meletakkan dasar untuk pekerjaan langsung yang dimulai di artikel ruang nama pengguna. Tujuan saya adalah untuk membangun beberapa pengetahuan mendasar tentang bagaimana dasar-dasar wadah Linux bekerja. Jika Anda tertarik dengan bagaimana Linux mengontrol sumber daya pada suatu sistem, lihat seri CGroup, yang saya tulis sebelumnya. Mudah-mudahan, pada saat Anda selesai dengan pekerjaan langsung namespaces, saya dapat mengikat CGroups dan namespaces bersama-sama dengan cara yang berarti, melengkapi gambar untuk Anda.

Namun, untuk saat ini, artikel ini memeriksa namespace mount dan bagaimana hal itu dapat membantu Anda lebih memahami isolasi yang dibawa container Linux ke sysadmin dan, dengan ekstensi, platform seperti OpenShift dan Kubernetes.

[ Anda mungkin juga menyukai: Berbagi grup tambahan dengan wadah Podman ]

Ruang nama pemasangan

mount namespace tidak berperilaku seperti yang Anda harapkan setelah membuat namespace pengguna baru. Secara default, jika Anda membuat namespace mount baru dengan unshare -m , pandangan Anda tentang sistem sebagian besar akan tetap tidak berubah dan tidak dibatasi. Itu karena setiap kali Anda membuat namespace mount baru, sebuah salinan titik mount dari namespace induk dibuat di namespace mount baru. Itu berarti bahwa tindakan apa pun yang diambil pada file di dalam namespace mount yang dikonfigurasi dengan buruk akan mempengaruhi tuan rumah.

Beberapa langkah penyiapan untuk memasang ruang nama

Jadi apa gunanya mount namespace? Untuk membantu mendemonstrasikannya, saya menggunakan tarball Alpine Linux.

Singkatnya, unduh, hapus tar, dan pindahkan ke direktori baru, memberikan izin direktori tingkat atas untuk pengguna yang tidak memiliki hak istimewa:

[root@localhost ~] export CONTAINER_ROOT_FOLDER=/container_practice
[root@localhost ~] mkdir -p ${CONTAINER_ROOT_FOLDER}/fakeroot
[root@localhost ~] cd ${CONTAINER_ROOT_FOLDER}
[root@localhost ~] wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.1-x86_64.tar.gz
[root@localhost ~] tar xvf alpine-minirootfs-3.13.1-x86_64.tar.gz -C fakeroot
[root@localhost ~] chown container-user. -R ${CONTAINER_ROOT_FOLDER}/fakeroot

fakeroot direktori harus dimiliki oleh pengguna container-user karena setelah Anda membuat ruang nama pengguna baru, root pengguna di namespace baru akan dipetakan ke kontainer-pengguna di luar ruang nama. Ini berarti bahwa proses di dalam namespace baru akan berpikir bahwa ia memiliki kemampuan yang diperlukan untuk memodifikasi file-nya. Namun, izin sistem file host akan mencegah pengguna penampung akun dari mengubah file Alpine dari tarball (yang memiliki root sebagai pemilik).

Jadi apa yang terjadi jika Anda memulai namespace mount baru?

PS1='\u@new-mnt$ ' unshare -Umr

Sekarang setelah Anda berada di dalam namespace baru, Anda mungkin tidak berharap untuk melihat titik pemasangan asli dari host. Namun, ini tidak terjadi:

root@new-mnt$ df -h
Filesystem           Size  Used Avail Use% Mounted on
/dev/mapper/cs-root   36G  5.2G   31G  15% /
tmpfs                737M     0  737M   0% /sys/fs/cgroup
devtmpfs             720M     0  720M   0% /dev
tmpfs                737M     0  737M   0% /dev/shm
tmpfs                737M  8.6M  728M   2% /run
tmpfs                148M     0  148M   0% /run/user/0
/dev/vda1            976M  197M  713M  22% /boot


root@new-mnt$ ls /
bin   container_practice  etc   lib    media  opt   root  sbin  sys  usr
boot  dev                 home  lib64  mnt    proc  run   srv   tmp  var

Alasannya adalah karena systemd default untuk secara rekursif berbagi titik pemasangan dengan semua ruang nama baru. Jika Anda memasang tmpfs filesystem di suatu tempat, misalnya, /mnt di dalam namespace mount baru, dapatkah host melihatnya?

root@new-mnt$ mount -t tmpfs tmpfs /mnt

root@new-mnt$ findmnt |grep mnt
└─/mnt     tmpfs               tmpfs      rw,relatime,seclabel,uid=1000,gid=1000

Tuan rumah, bagaimanapun, tidak melihat ini:

[root@localhost ~]# findmnt |grep mnt

Jadi setidaknya, Anda tahu bahwa namespace mount berfungsi dengan benar. Ini adalah saat yang tepat untuk mengambil jalan memutar kecil untuk membahas penyebaran titik pemasangan. Saya meringkas secara singkat, tetapi jika Anda tertarik untuk memahami lebih lanjut, lihat artikel LWN Michael Kerrisk serta halaman manual untuk mount namespace. Saya biasanya tidak terlalu bergantung pada halaman manual karena saya sering menemukan bahwa mereka tidak mudah dicerna. Namun, dalam kasus ini, mereka penuh dengan contoh dan (kebanyakan) dalam bahasa Inggris yang sederhana.

Teori titik mount

Mount menyebar secara default karena fitur di kernel yang disebut subtree bersama . Ini memungkinkan setiap titik pemasangan memiliki jenis propagasinya sendiri yang terkait dengannya. Metadata ini menentukan apakah mount baru di bawah jalur tertentu disebarkan ke titik mount lainnya. Contoh yang diberikan di halaman manual adalah disk optik. Jika disk optik Anda secara otomatis dipasang di bawah /cdrom , konten hanya akan terlihat di ruang nama lain jika jenis propagasi yang sesuai disetel.

Grup rekan dan status pemasangan

Dokumentasi kernel mengatakan bahwa "peer group didefinisikan sebagai sekelompok vfsmount yang menyebarkan peristiwa satu sama lain." Peristiwa adalah hal-hal seperti memasang jaringan berbagi atau melepas perangkat optik. Mengapa ini penting, Anda tanya? Nah, jika menyangkut ruang nama pemasangan, grup rekan sering menjadi faktor penentu apakah tunggangan terlihat dan dapat berinteraksi dengannya atau tidak. Status pemasangan menentukan apakah anggota dalam kelompok sebaya dapat menerima acara tersebut. Menurut dokumentasi kernel yang sama, ada lima status pemasangan:

  1. dibagikan - Sebuah mount milik peer group. Setiap perubahan yang terjadi akan menyebar ke seluruh anggota kelompok sebaya.
  2. budak - Propagasi satu arah. Titik pemasangan master akan menyebarkan peristiwa ke budak, tetapi master tidak akan melihat tindakan apa pun yang dilakukan budak.
  3. berbagi dan menjadi budak - Menunjukkan bahwa mount point memiliki master, tetapi juga memiliki peer group sendiri. Master tidak akan diberi tahu tentang perubahan pada titik pemasangan, tetapi setiap anggota grup sebaya di hilir akan diberitahu.
  4. pribadi - Tidak menerima atau meneruskan acara propagasi apa pun.
  5. tidak dapat diikat - Tidak menerima atau meneruskan acara propagasi apa pun dan tidak bisa menjadi pengikat terpasang.

Penting untuk dicatat bahwa status titik pemasangan adalah per titik pemasangan . Artinya, jika Anda memiliki / dan /boot , misalnya, Anda harus menerapkan status yang diinginkan secara terpisah ke setiap titik pemasangan.

Jika Anda bertanya-tanya tentang container, sebagian besar mesin container menggunakan status pemasangan pribadi saat memasang volume di dalam container. Jangan terlalu khawatir tentang ini untuk saat ini. Saya hanya ingin memberikan beberapa konteks. Jika Anda ingin mencoba beberapa skenario pemasangan tertentu, lihat halaman manual karena contohnya cukup bagus.

Membuat namespace mount kami

Jika Anda menggunakan bahasa pemrograman seperti Go atau C, Anda dapat menggunakan panggilan kernel sistem mentah untuk membuat lingkungan yang sesuai untuk namespace baru Anda. Namun, karena maksud di balik ini adalah untuk membantu Anda memahami cara berinteraksi dengan container yang sudah ada, Anda harus melakukan beberapa tipuan bash untuk membuat namespace mount baru Anda ke status yang diinginkan.

Pertama, buat namespace mount baru sebagai pengguna biasa:

unshare -Urm

Setelah Anda berada di dalam namespace, lihat findmnt dari perangkat mapper, yang berisi sistem file root (untuk singkatnya, saya menghapus sebagian besar opsi mount dari output):

findmnt |grep mapper

/       /dev/mapper/cs-root      xfs           rw,relatime,[...]

Hanya ada satu mount point yang memiliki root device mapper. Ini penting karena salah satu hal yang harus Anda lakukan adalah mengikat perangkat mapper ke direktori Alpine:

export CONTAINER_ROOT_FOLDER=/container_practice
mount --bind ${CONTAINER_ROOT_FOLDER}/fakeroot ${CONTAINER_ROOT_FOLDER}/fakeroot
cd ${CONTAINER_ROOT_FOLDER}/fakeroot

Ini karena Anda menggunakan utilitas bernama pivot_root untuk melakukan chroot -seperti tindakan. pivot_root membutuhkan dua argumen:new_root dan old_root (terkadang disebut sebagai put_old ). pivot_root memindahkan sistem file root dari proses saat ini ke direktori put_old dan membuat new_root sistem file root baru.

PENTING :Catatan tentang chroot . chroot sering dianggap memiliki manfaat keamanan ekstra. Sampai batas tertentu, ini benar, karena dibutuhkan lebih banyak keahlian untuk membebaskan diri darinya. chroot yang dibangun dengan hati-hati bisa sangat aman. Namun, chroot tidak mengubah atau membatasi kemampuan Linux yang saya singgung di artikel namespace sebelumnya. Juga tidak membatasi panggilan sistem ke kernel. Ini berarti bahwa penyerang yang cukup terampil berpotensi lolos dari chroot yang belum dipikirkan dengan baik. Mount dan ruang nama pengguna membantu memecahkan masalah ini.

Jika Anda menggunakan pivot_root tanpa pengikatan mount, perintah merespons dengan:

pivot_root: failed to change root from `.' to `old_root/': Invalid argument

Untuk beralih ke sistem file root Alpine, pertama, buat direktori untuk old_root dan kemudian putar ke sistem file root (Alpine) yang dimaksud. Karena sistem file root Alpine Linux tidak memiliki symlink untuk /bin dan /sbin , Anda harus menambahkannya ke jalur Anda dan akhirnya, melepas old_root :

mkdir old_root
pivot_root . old_root
PATH=/bin:/sbin:$PATH
umount -l /old_root

Anda sekarang memiliki lingkungan yang bagus di mana pengguna dan pasang namespaces bekerja sama untuk menyediakan lapisan isolasi dari host. Anda tidak lagi memiliki akses ke biner di host. Coba keluarkan findmnt perintah yang Anda gunakan sebelumnya:

root@new-mnt$ findmnt
-bash: findmnt: command not found

Anda juga dapat melihat sistem file root atau mencoba melihat apa yang terpasang:

root@new-mnt$ ls -l /
total 12
drwxr-xr-x    2 root     root          4096 Jan 28 21:51 bin
drwxr-xr-x    2 root     root            18 Feb 17 22:53 dev
drwxr-xr-x   15 root     root          4096 Jan 28 21:51 etc
drwxr-xr-x    2 root     root             6 Jan 28 21:51 home
drwxr-xr-x    7 root     root           247 Jan 28 21:51 lib
drwxr-xr-x    5 root     root            44 Jan 28 21:51 media
drwxr-xr-x    2 root     root             6 Jan 28 21:51 mnt
drwxrwxr-x    2 root     root             6 Feb 17 23:09 old_root
drwxr-xr-x    2 root     root             6 Jan 28 21:51 opt
drwxr-xr-x    2 root     root             6 Jan 28 21:51 proc
drwxr-xr-x    2 root     root             6 Feb 17 22:53 put_old
drwx------    2 root     root            27 Feb 17 22:53 root
drwxr-xr-x    2 root     root             6 Jan 28 21:51 run
drwxr-xr-x    2 root     root          4096 Jan 28 21:51 sbin
drwxr-xr-x    2 root     root             6 Jan 28 21:51 srv
drwxr-xr-x    2 root     root             6 Jan 28 21:51 sys
drwxrwxrwt    2 root     root             6 Feb 19 16:38 tmp
drwxr-xr-x    7 root     root            66 Jan 28 21:51 usr
drwxr-xr-x   12 root     root           137 Jan 28 21:51 var


root@new-mnt$ mount
mount: no /proc/mounts

Menariknya, tidak ada proc sistem file dipasang secara default. Coba pasang:

root@new-mnt$ mount -t proc proc /proc
mount: permission denied (are you root?)

root@new-mnt$ whoami
root

Karena proc adalah jenis mount khusus yang terkait dengan namespace PID yang tidak dapat Anda mount meskipun Anda berada di mount namespace Anda sendiri. Ini kembali ke pewarisan kemampuan yang saya bahas sebelumnya. Saya akan mengambil diskusi ini di artikel berikutnya ketika saya membahas namespace PID. Namun, sebagai pengingat tentang pewarisan, lihat diagram di bawah ini:

Pada artikel berikutnya, saya akan mengulangi diagram ini, tetapi jika Anda telah mengikuti sejak awal, Anda harus dapat membuat beberapa kesimpulan sebelum itu.

[ Panduan pemilik API:7 praktik terbaik program API yang efektif ] 

Menutup

Dalam artikel ini, saya membahas beberapa teori yang lebih dalam seputar mount namespace. Saya membahas kelompok rekan dan bagaimana mereka berhubungan dengan status pemasangan yang diterapkan ke setiap titik pemasangan pada suatu sistem. Untuk bagian langsung, Anda mengunduh sistem file minimal Alpine Linux dan kemudian mempelajari cara menggunakan ruang nama pengguna dan memasang untuk menciptakan lingkungan yang sangat mirip dengan chroot kecuali berpotensi lebih aman.

Untuk saat ini, uji sistem file pemasangan di dalam dan di luar namespace baru Anda. Coba buat titik pemasangan baru yang menggunakan bersama , pribadi , dan budak status gunung. Di artikel berikutnya, saya akan menggunakan namespace PID untuk terus membangun kontainer primitif guna mendapatkan akses ke proc sistem file dan isolasi proses.


Linux
  1. Membangun Awan Pajak

  2. Docker di Docker tidak dapat memasang volume

  3. Pindahkan instalasi Linux menggunakan btrfs pada subvolume default (subvolid=0) ke subvolume lain

  1. Memecahkan masalah menggunakan sistem file proc di Linux

  2. Demystifying namespace dan container di Linux

  3. Lihat/manipulasi mount ruang nama di Linux

  1. Membangun kepercayaan di komunitas Linux

  2. 7 namespace Linux yang paling banyak digunakan

  3. Cara meringankan beban pada registri kontainer Anda menggunakan Quay.io