Jalankan tindakan selepas sambungan VPN sebagai pengguna, bukan sebagai daemon
Pemboleh ubah persekitaran yang menyatakan USER=alice tidak mengubah akaun mana yang menjalankan hook. Pisahkan peristiwa, pencetus dan tindakan, kemudian buktikan UID.
Hook sambungan pada daemon VPN berjalan sebagai daemon, dan biasanya itu bermakna ia berjalan sebagai root. Sebaik sahaja salah satu hook itu menulis ke direktori rumah seseorang atau memulakan semula pembantu desktop, anda telah memberikan kepada peristiwa rangkaian keupayaan untuk bertindak sebagai mana-mana pengguna tempatan. Jalan pintas biasa, membaca nama pengguna daripada pemboleh ubah persekitaran dan menyalurkannya, tidak membaiki perkara itu. Ia hanya melabel semula tindakan itu tanpa mengubah akaun mana yang melaksanakannya. Yang berkesan ialah penyerahan tiga bahagian, di mana langkah istimewa menyatakan apa yang berlaku dan unit berasingan melakukan tindakan itu di bawah identiti yang betul.
Nama pengguna dalam persekitaran bukan suis identiti
Unix menentukan apa yang boleh disentuh oleh proses berdasarkan ID pengguna berkesannya, bukan berdasarkan rentetan dalam persekitarannya. Menetapkan USER=alice atau mengeksport LOGNAME mengubah apa yang dicetak oleh perisian cuai dalam outputnya; ia tidak mengubah apa-apa pada semakan pemilikan fail. Hook yang berjalan sebagai root dengan pemboleh ubah itu tetap membuka fail Alice sebagai root.
Nama-nama itu juga bukan nama yang sama. Log masuk akses jauh, akaun Unix tempatan dan nama umum sijil ialah tiga pengecam yang sering bertemu dan kadangkala tidak. Pengguna yang mengesahkan diri sebagai a.smith mungkin tidak mempunyai akaun tempatan sama sekali, atau mungkin dipetakan ke asmith melalui perkhidmatan direktori. Mana-mana reka bentuk yang menganggap satu rentetan memenuhi ketiga-tiga peranan akan rosak pada kontraktor pertama.
Jadi soalan pertama bukan «pengguna mana yang bersambung» tetapi «akaun tempatan mana yang dibenarkan melakukan tindakan ini». Jawab perkara itu daripada pangkalan data akaun anda sendiri, bukan daripada apa yang dihantar oleh 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 ialah yang dilangkau oleh orang. Jika fail sasaran dimiliki oleh root kerana hook sebelum ini menciptanya, tindakan pengguna yang dikonfigurasikan dengan betul akan gagal dengan ralat kebenaran yang kelihatan seperti masalah systemd dan sebenarnya bukan.
Daemon kekal di tempatnya
Menukar User= milik perkhidmatan VPN itu sendiri kepada Alice ialah tuas yang salah. Ia mengubah cara daemon mengikat antara muka, membaca kunci, menulis fail statusnya dan mengurus laluan, dan ia memindahkan semua risiko itu ke dalam unit yang berfungsi. Daemon memerlukan keistimewaannya; tindakan susulan tidak.
Lihat apa yang sebenarnya dilakukan oleh unit itu sebelum menyentuhnya. Dua perintah memberitahu anda identiti pelaksanaan dan baris perintah tepat yang berkuat kuasa, termasuk apa-apa yang ditambah oleh override:
systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server
Pada pemasangan pakej lalai, daemon ialah root dan skrip --up mewarisi perkara itu. Sahkan perkara itu dan jangan anggap, kerana distribusi yang diperkukuh mungkin telah memindahkannya ke akaun khusus, dan drop-in yang ditulis dengan tangan mungkin menjalankan hook melalui pembalut dengan peraturan yang berbeza.
Tiga bahagian bernama, satu pencetus sempit
Susunan yang bertahan dalam penyelenggaraan mempunyai peristiwa, pencetus dan tindakan. Daemon melaporkan bahawa sesi bernama telah naik. Pencetus menerima fakta kecil itu dan meminta satu tindakan tetap. Tindakan itu berjalan di bawah akaun tempatan yang memiliki fail yang disentuhnya. Tiada apa-apa dalam rantaian menerima laluan perintah sewenang-wenangnya.
Tindakan itu sendiri ialah unit perkhidmatan biasa, dan identiti ialah satu direktif di dalamnya:
[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i
Perhatikan bahawa User=alice terpakai kepada seluruh unit, dan systemd mendokumentasikan satu pengecualian yang wajar diketahui: perintah dengan awalan + berjalan dengan keistimewaan penuh tanpa mengira perkara itu. Awalan itu ialah alat sah untuk satu langkah istimewa dan cara mudah untuk membatalkan pemisahan yang baru anda bina, jadi anggap mana-mana + dalam unit itu sebagai sesuatu yang perlu dijustifikasikan semasa semakan.
Kekalkan input pencetus minimum dan tidak rahsia. Pengecam sesi, akaun yang dipetakan dan cap masa biasanya semua yang diperlukan. Jangan sekali-kali menyalurkan serpihan shell, laluan fail boleh laku atau blok persekitaran yang diberikan oleh klien melepasi sempadan, kerana pihak penerima tiada cara untuk membezakan nilai sah daripada yang disuntik.
Sahkan identiti yang benar-benar berjalan
Semakan konfigurasi bukan bukti. Selepas sambungan ujian yang diluluskan, sahkan UID yang menyentuh fail dan UID yang masih digunakan oleh 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 sepatutnya menunjukkan Alice dan cap masa dalam tetingkap ujian anda. Yang kedua sepatutnya masih menunjukkan root atau akaun perkhidmatan pakej, yang membuktikan daemon tidak bergerak. Yang ketiga ialah cara paling murah untuk menguji kebenaran tindakan tanpa menunggu sambungan semula sebenar.
Jika pemilik fail ialah Alice tetapi kumpulan atau modnya berubah antara jalanan, cari UMask= atau perbezaan kebenaran direktori dan bukan ralat logik. Jika cap masa tidak bergerak sama sekali, pencetus tidak pernah tercetus, dan langkah seterusnya yang berguna ialah journalctl -u untuk unit tindakan dan bukan sambungan semula klien yang lain.
Apa yang masih tidak dibuktikan oleh peristiwa sambungan
Terowong yang terbentuk ialah satu fakta. Ia tidak bermakna sesi desktop terbuka, bas sesi boleh dicapai, atau sumber peribadi yang dikehendaki tindakan itu sudah tersedia. Unit oneshot di bawah UID Alice mempunyai identitinya dan tiada apa-apa daripada sesinya, jadi apa-apa yang memerlukan bas grafik mesti melalui mekanisme sesi pengguna yang disokong dan menentukan apa yang berlaku apabila dia log keluar.
Sambungan semula juga berulang. Komputer riba yang tidur dalam kereta api boleh menghasilkan selusin peristiwa sambungan dalam satu jam, dan hook yang menambah satu baris setiap kali menjadikan fail status sebagai log yang tiada siapa boleh baca. Jadikan tindakan itu idempoten, atau biarkan ia menggantikan satu rekod berkunci sesi.
Akhir sekali, hadkan radius kerosakan dalam unit itu sendiri: paparan sistem fail baca sahaja di luar direktori status, tiada keistimewaan baharu, dan had masa yang jelas. Pemisahan antara daemon dan tindakan pengguna berbaloi dengan sendirinya, tetapi ia lebih berbaloi apabila tindakan itu tidak boleh melakukan apa-apa kecuali satu perkara yang anda luluskan.