Hook koneksi pada daemon VPN berjalan sebagai daemon, dan biasanya itu berarti berjalan sebagai root. Begitu salah satu hook itu menulis ke direktori home seseorang atau memulai ulang pembantu desktop, Anda telah memberi sebuah peristiwa jaringan kemampuan untuk bertindak sebagai pengguna lokal mana pun. Jalan pintas yang biasa, membaca nama pengguna dari variabel lingkungan dan meneruskannya, tidak memperbaikinya. Itu hanya memberi label ulang pada tindakan tanpa mengubah akun mana yang menjalankannya. Yang berhasil adalah penyerahan tiga bagian, di mana langkah istimewa menyatakan apa yang terjadi dan unit terpisah melakukan tindakan itu dengan identitas yang benar.

Nama pengguna di lingkungan bukan sakelar identitas

Unix menentukan apa yang boleh disentuh proses dari ID pengguna efektifnya, bukan dari string di lingkungannya. Menyetel USER=alice atau mengekspor LOGNAME mengubah apa yang dicetak perangkat lunak ceroboh pada keluarannya; itu tidak mengubah apa pun pada pemeriksaan kepemilikan berkas. Hook yang berjalan sebagai root dengan variabel itu tetap membuka berkas Alice sebagai root.

Namanya juga bukan nama yang sama. Login akses jarak jauh, akun Unix lokal, dan nama umum sertifikat adalah tiga pengenal yang sering bertepatan dan kadang tidak. Pengguna yang mengautentikasi sebagai a.smith mungkin tidak punya akun lokal sama sekali, atau dipetakan ke asmith melalui layanan direktori. Desain apa pun yang mengasumsikan satu string melayani ketiga peran akan rusak pada kontraktor pertama.

Jadi pertanyaan pertama bukan «pengguna mana yang terhubung» melainkan «akun lokal mana yang diizinkan melakukan tindakan ini». Jawab itu dari basis data akun Anda sendiri, bukan dari apa yang dikirim klien:

id -u alice
getent passwd alice | cut -d: -f1,3,6
stat -c '%U:%G %a %n' /home/alice/.local/state/vpn-status.json

Perintah ketiga adalah yang dilewati orang. Jika berkas tujuan dimiliki root karena hook sebelumnya membuatnya, tindakan pengguna yang dikonfigurasi dengan benar akan gagal dengan kesalahan izin yang terlihat seperti masalah systemd dan sebenarnya bukan.

Daemon tetap di tempatnya

Mengubah User= milik layanan VPN itu sendiri menjadi Alice adalah tuas yang salah. Itu mengubah cara daemon mengikat antarmuka, membaca kunci, menulis berkas statusnya, dan mengelola rute, dan memindahkan semua risiko itu ke unit yang tadinya bekerja. Daemon membutuhkan hak istimewanya; tindakan lanjutan tidak.

Lihat apa yang sebenarnya dilakukan unit itu sebelum menyentuhnya. Dua perintah memberi tahu Anda identitas eksekusi dan baris perintah persis yang berlaku, termasuk apa pun yang ditambahkan oleh penimpaan:

systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server

Pada pemasangan paket bawaan, daemon adalah root dan skrip --up mewarisinya. Konfirmasikan itu alih-alih mengasumsikannya, karena distribusi yang diperketat mungkin telah memindahkannya ke akun khusus, dan drop-in yang ditulis tangan mungkin menjalankan hook melalui pembungkus dengan aturan berbeda.

Tiga bagian bernama, satu pemicu sempit

Susunan yang bertahan dari pemeliharaan memiliki peristiwa, pemicu, dan tindakan. Daemon melaporkan bahwa sesi bernama telah naik. Pemicu menerima fakta kecil itu dan meminta satu tindakan tetap. Tindakan berjalan di bawah akun lokal yang memiliki berkas yang disentuhnya. Tidak ada apa pun dalam rantai yang menerima jalur perintah sembarang.

Tindakannya sendiri adalah unit layanan biasa, dan identitasnya adalah satu direktif di dalamnya:

[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i

Perhatikan bahwa User=alice berlaku untuk seluruh unit, dan systemd mendokumentasikan satu pengecualian yang layak diketahui: perintah dengan awalan + berjalan dengan hak istimewa penuh terlepas dari itu. Awalan itu adalah alat sah untuk satu langkah istimewa dan cara mudah membatalkan pemisahan yang baru saja Anda bangun, jadi perlakukan + apa pun dalam unit itu sebagai sesuatu yang harus dibenarkan dalam tinjauan.

Jaga masukan pemicu tetap minimal dan tidak rahasia. Pengenal sesi, akun yang dipetakan, dan stempel waktu biasanya semua yang dibutuhkan. Jangan pernah meneruskan fragmen shell, jalur eksekutabel, atau blok lingkungan yang disediakan klien melewati batas, karena pihak penerima tidak punya cara membedakan nilai sah dari nilai yang disuntikkan.

Verifikasi identitas yang benar-benar berjalan

Tinjauan konfigurasi bukan bukti. Setelah koneksi uji yang disetujui, konfirmasikan UID yang menyentuh berkas dan UID yang masih dipakai daemon:

stat -c '%U %G %y %n' /home/alice/.local/state/vpn-status.json
ps -o user=,pid=,cmd= -p "$(pgrep -o -f 'openvpn --daemon')"
systemd-run --uid=alice --pipe /usr/local/bin/refresh-vpn-status --dry-run

Baris pertama seharusnya menunjukkan Alice dan stempel waktu di dalam jendela uji Anda. Baris kedua seharusnya masih menunjukkan root atau akun layanan paket, yang membuktikan daemon tidak berpindah. Baris ketiga adalah cara termurah menguji izin tindakan tanpa menunggu koneksi ulang sungguhan.

Jika pemilik berkas adalah Alice tetapi grup atau modenya berubah antar-jalan, carilah UMask= atau perbedaan izin direktori alih-alih kesalahan logika. Jika stempel waktu tidak bergerak sama sekali, pemicu tidak pernah menyala, dan langkah berikutnya yang berguna adalah journalctl -u untuk unit tindakan alih-alih koneksi ulang klien lagi.

Apa yang masih tidak dibuktikan peristiwa koneksi

Tunnel yang terbentuk adalah satu fakta. Itu tidak berarti sesi desktop terbuka, bus sesi dapat dijangkau, atau sumber daya privat yang diinginkan tindakan itu sudah tersedia. Unit oneshot di bawah UID Alice memiliki identitasnya dan tidak memiliki sesinya, jadi apa pun yang memerlukan bus grafis harus melalui mekanisme sesi pengguna yang didukung dan mendefinisikan apa yang terjadi saat ia keluar.

Koneksi ulang juga berulang. Laptop yang tidur di kereta dapat menghasilkan selusin peristiwa koneksi dalam satu jam, dan hook yang menambahkan satu baris setiap kali mengubah berkas status menjadi log yang tidak bisa dibaca siapa pun. Buat tindakan itu idempoten, atau biarkan ia mengganti satu catatan berkunci sesi.

Terakhir, batasi radius kerusakan di dalam unit itu sendiri: tampilan sistem berkas hanya-baca di luar direktori status, tanpa hak istimewa baru, dan dengan batas waktu eksplisit. Pemisahan antara daemon dan tindakan pengguna layak dimiliki sendiri, tetapi jauh lebih berharga ketika tindakan itu tidak dapat melakukan apa pun kecuali satu hal yang Anda setujui.

Artikel terkait