Хуки підключення в демоні VPN працюють від імені демона, а це зазвичай означає, що вони працюють від імені root. У ту мить, коли один із таких хуків пише в чийсь домашній каталог або перезапускає помічник робочого столу, ви дали мережевій події здатність діяти від імені будь-якого локального користувача. Звичайний короткий шлях, прочитати ім’я користувача зі змінної середовища і передати його далі, цього не виправляє. Він лише перейменовує дію, не змінюючи обліковий запис, який її виконує. Працює трискладова передача, у якій привілейований крок повідомляє, що сталося, а окремий юніт виконує дію під правильною ідентичністю.

Ім’я користувача в середовищі не є перемикачем ідентичності

Unix вирішує, чого може торкатися процес, за його чинним ідентифікатором користувача, а не за рядками в його середовищі. Встановлення USER=alice або експорт LOGNAME змінює те, що недбале програмне забезпечення друкує у своєму виводі; на перевірки володіння файлами це не впливає ніяк. Хук, що працює від root із цією змінною, усе одно відкриває файли Аліси від імені root.

Імена теж не одне й те саме ім’я. Логін віддаленого доступу, локальний обліковий запис Unix і загальне ім’я сертифіката це три ідентифікатори, які часто збігаються, а іноді ні. Користувач, який проходить автентифікацію як a.smith, може взагалі не мати локального облікового запису або відображатися на asmith через службу каталогів. Будь-який проєкт, що припускає, ніби один рядок обслуговує всі три ролі, зламається вже на першому підряднику.

Отже, перше питання не «який користувач підключений», а «якому локальному обліковому запису дозволено виконувати цю дію». Відповідайте на нього з власної бази облікових записів, а не з того, що надіслав клієнт:

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

Третя команда це та, яку люди пропускають. Якщо цільовий файл належить root, бо його створив попередній хук, правильно налаштована дія користувача завершиться помилкою доступу, яка виглядає як проблема systemd і нею не є.

Демон залишається там, де він є

Змінювати власний User= служби VPN на Алісу це неправильний важіль. Це змінює те, як демон прив’язує інтерфейси, читає ключі, пише файл стану й керує маршрутами, і переносить увесь цей ризик у юніт, який працював. Демонові потрібні його привілеї; наступній дії ні.

Подивіться, що юніт насправді робить, перш ніж його чіпати. Дві команди показують ідентичність виконання та точні чинні командні рядки, включно з усім, що додало перевизначення:

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

За стандартного встановлення з пакета демон це root, і скрипт --up успадковує це. Підтвердьте це, а не припускайте, бо зміцнений дистрибутив міг перемістити його на окремий обліковий запис, а написаний вручну drop-in може запускати хук через обгортку з іншими правилами.

Три названі частини, один вузький тригер

Схема, що переживає обслуговування, має подію, тригер і дію. Демон повідомляє, що іменована сесія піднялася. Тригер приймає цей маленький факт і просить одну фіксовану дію. Дія працює під локальним обліковим записом, якому належать файли, яких вона торкається. Ніщо в ланцюгу не приймає довільний шлях команди.

Сама дія це звичайний сервісний юніт, а ідентичність це одна директива всередині нього:

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

Зверніть увагу, що User=alice діє на весь юніт, і systemd документує один виняток, який варто знати: команда з префіксом + виконується з повними привілеями незалежно від цього. Цей префікс це законний інструмент для одного привілейованого кроку й зручний спосіб скасувати щойно збудоване розділення, тому будь-який + у цьому юніті вважайте тим, що треба обґрунтувати на огляді.

Тримайте вхід тригера мінімальним і не секретним. Ідентифікатор сесії, зіставлений обліковий запис і позначка часу зазвичай це все, що потрібно. Ніколи не передавайте через межу фрагмент оболонки, шлях до виконуваного файлу або блок середовища від клієнта, бо приймальна сторона не має способу відрізнити законне значення від впровадженого.

Перевірте ідентичність, яка справді працювала

Огляд конфігурації це не доказ. Після схваленого тестового підключення підтвердьте UID, який торкнувся файлу, і UID, який демон досі використовує:

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

Перший рядок має показати Алісу й позначку часу в межах вашого тестового вікна. Другий має досі показувати root або службовий обліковий запис пакета, що доводить, що демон не зрушив. Третій це найдешевший спосіб перевірити права дії, не чекаючи справжнього повторного підключення.

Якщо власник файлу Аліса, але його група або режим змінилися між запусками, шукайте UMask= або різницю в правах каталогу, а не логічну помилку. Якщо позначка часу взагалі не зрушила, тригер так і не спрацював, і корисний наступний крок це journalctl -u для юніта дії, а не ще одне повторне підключення клієнта.

Чого подія підключення досі не доводить

Встановлений тунель це один факт. Він не означає, що сеанс робочого столу розблоковано, шина сеансу доступна або що приватний ресурс, потрібний дії, вже доступний. Юніт oneshot під UID Аліси має її ідентичність і нічого з її сеансу, тому все, що потребує графічної шини, має проходити через підтримуваний механізм користувацького сеансу й визначати, що відбувається, коли вона вийшла з системи.

Повторні підключення теж повторюються. Ноутбук, що засинає в потязі, може видати десяток подій підключення за годину, а хук, який щоразу дописує рядок, перетворює файл стану на журнал, який ніхто не може прочитати. Зробіть дію ідемпотентною або дозвольте їй замінювати один запис із ключем за сесією.

Насамкінець обмежте радіус ураження в самому юніті: подання файлової системи лише для читання поза каталогом стану, жодних нових привілеїв і явний тайм-аут. Розділення демона й дії користувача цінне саме собою, але воно варте набагато більше, коли дія не може зробити нічого, крім того єдиного, що ви схвалили.

Схожі статті