Hook berjalan saat Anda menjalankannya secara manual sebagai root dan mengembalikan Operation not permitted pada saat layanan memulainya. Berkas tidak berubah di antara kedua eksekusi itu; lingkungannya yang berubah. systemd memberi proses dunia yang lebih kecil: lebih sedikit kapabilitas, /dev yang berbeda, jalur sistem berkas hanya-baca, dan batas atas tugas. Bacalah kegagalan itu sebagai batas yang menolak satu operasi tertentu, bukan sebagai skrip yang rusak.

Mulailah dari operasi yang ditolak

Baris log yang menyatakan unit gagal hampir tidak memberi tahu apa pun. Baris yang berguna menyebut panggilan yang ditolak: simpul perangkat yang tidak bisa dibuka, direktori yang tidak bisa ditulisi, ruang nama yang tidak bisa dibuat. Temukan panggilan itu sebelum Anda menyentuh satu direktif pun, karena masing-masing memetakan ke batasan yang berbeda. Lalu bacalah unit yang benar-benar berjalan, termasuk drop-in, bukan berkas yang dikirim paket.

Kueri di bawah mencetak jalur fragmen, direktori drop-in, dan properti yang penting untuk penolakan perangkat atau sistem berkas. Bacalah semuanya sebelum memutuskan batas mana yang relevan:

systemctl show "[email protected]" -p FragmentPath -p DropInPaths -p PrivateDevices -p DevicePolicy -p DeviceAllow -p ProtectHome -p ProtectSystem -p TasksMax
journalctl -u "[email protected]" -b --no-pager | grep -iE 'operation not permitted|permission denied|cannot open|failed'

Tidak ada yang menulis di blok itu. Jika panggilan yang ditolak tidak ada di jurnal, naikkan verbositas klien untuk satu eksekusi alih-alih menebak direktif. Proses yang berjalan membuktikan unit sudah mulai, bukan bahwa hook berjalan dengan hak istimewa yang dibutuhkannya.

Ruang nama membutuhkan hak mount yang tidak pernah dipakai perangkat TUN

Dua operasi yang terlihat sama di dalam satu hook punya profil izin yang berbeda. Membuka /dev/net/tun dan membuat antarmuka membutuhkan administrasi jaringan plus akses ke simpul itu. Membuat ruang nama jaringan bernama juga membutuhkan kerja mount, karena alat ruang nama me-mount /sys tampilan baru dan mengikat direktori status pada tempatnya. unit klien hulu sengaja membiarkan administrasi mount di luar himpunan batasnya, sehingga langkah ruang nama ditolak padahal terowongannya sendiri akan berfungsi.

Itulah sebabnya memberikan simpul perangkat tidak menyelamatkan skrip. Izin perangkat menjawab satu pertanyaan, apakah proses ini boleh membuka simpul ini, dan pertanyaan ruang nama adalah hal lain. Cocokkan panggilan yang gagal dengan kapabilitasnya sebelum memperlebar apa pun.

Uji di shell Anda mewarisi setiap kapabilitas yang dimiliki root tanpa batas, dan unit mewarisi apa yang dipertahankan himpunan batasnya. Kedua eksekusi itu adalah eksperimen yang berbeda bahkan ketika binernya identik.

Perangkat, jalur terlindungi, dan batas atas tugas

Setelah operasi yang ditolak diketahui, tiga kelompok direktif menjelaskan sebagian besar kegagalan. Akses perangkat diatur oleh PrivateDevices, yang menggantikan /dev dengan himpunan minimal perangkat semu, dan oleh DevicePolicy dengan DeviceAllow, yang menentukan apa yang diizinkan cgroup. /dev/net/tun bukan bagian dari himpunan minimal itu, jadi unit dengan PrivateDevices=yes tidak dapat membukanya, apa pun kata kebijakan perangkat.

Perlindungan sistem berkas menjawab pertanyaan kedua. ProtectHome=yes membuat /home, /root dan /run/user tidak dapat diakses, dan ProtectSystem=full membuat /usr, /boot dan /etc hanya-baca. Karena itu hook yang menulis di samping berkas konfigurasinya sendiri berfungsi di shell Anda dan gagal di bawah unit, dengan bentuk izin yang sama seperti kapabilitas yang hilang. Pindahkan masukan yang dapat ditulis ke jalur yang diizinkan kebijakan, atau tambahkan entri ReadWritePaths= yang sempit.

Batas sumber daya adalah kelompok ketiga, dan yang paling tidak jelas. TasksMax= membatasi berapa banyak tugas yang boleh dibuat unit, dan batas atas deskriptor berkas berperilaku sama untuk soket dan pegangan. Penerapan yang tumbuh melewati batas gagal dengan kesalahan sumber daya alih-alih kesalahan izin, dan itulah sebabnya pesan persisnya masih penting.

Keluarkan langkah ruang nama dari hook

Persiapan yang membutuhkan hak istimewa yang tidak boleh dipegang klien adalah milik unitnya sendiri. oneshot yang berjalan sebelum klien, menyimpan hasilnya, dan diurutkan sebelum koneksi memberi langkah ruang nama apa yang dibutuhkannya tanpa menyerahkan hak itu ke proses terowongan. Klien lalu merujuk unit itu alih-alih memanggil skrip dari hook up-nya.

Templat di bawah adalah bentuk awal, bukan sesuatu yang diterapkan tanpa dibaca. Templat itu menyimpan persiapan di tempat hak istimewa berada dan membiarkan unit terowongan tidak tersentuh:

# /etc/systemd/system/[email protected]
[Unit]
Description=Namespace preparation for %i
Before=openvpn-client@%i.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/netns-up.sh %i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_SYS_ADMIN
[Install]
WantedBy=multi-user.target

Tambahkan pengurutan dengan drop-in alih-alih menyunting unit terpaket, agar pemutakhiran tidak bisa diam-diam membuang perubahan Anda. Direktori dikaitkan dengan nama instans, jadi profil kedua membutuhkan berkasnya sendiri:

sudo mkdir -p /etc/systemd/system/[email protected]
sudo tee /etc/systemd/system/[email protected]/10-namespace.conf >/dev/null <<'CONF'
[Unit]
[email protected]
[email protected]
CONF
sudo systemctl daemon-reload

Ulangi panggilan yang sama setelah perubahan

Perbaikan baru terkonfirmasi ketika panggilan yang sama menghasilkan hasil berbeda. Mulai ulang kedua unit, jalankan operasi yang gagal, dan bandingkan hasilnya dengan baris jurnal yang Anda simpan sebelum perubahan. Unit yang mulai berjalan sementara hook tidak pernah berjalan lagi bukanlah perbaikan.

Urutan di bawah menjaga perbandingan tetap jujur, karena memeriksa panggilan yang ditolak, bukan warna unit. Simpan keluarannya di samping baris jurnal yang Anda tangkap sebelum perubahan:

sudo systemctl restart "[email protected]" "[email protected]"
systemctl status "[email protected]" --no-pager
journalctl -u "[email protected]" -b --no-pager | grep -c 'Operation not permitted'
ip -brief addr show tun0

Hitung penolakannya alih-alih membaca baris terakhir, karena hook bisa gagal, mencoba lagi, dan berhasil, dan hanya hitungannya yang menunjukkan apakah batasnya bergerak. Tinggalkan komentar di drop-in yang menyebut direktif yang Anda longgarkan dan alasannya, karena pemutakhiran berikutnya membandingkan konfigurasi Anda dengan bawaan paket. Unit yang hanya mulai setelah semua perlindungan dimatikan belum diperbaiki.

Artikel terkait