Hook-овете за връзка при VPN демон работят като демона и обикновено това значи, че работят като root. В момента, в който един от тези hook-ове запише в домашната директория на някого или рестартира помощник на работния плот, вие сте дали на мрежово събитие способността да действа като произволен локален потребител. Обичайният пряк път, да прочетете потребителско име от променлива на средата и да го предадете нататък, не поправя това. Той преименува действието, без да променя кой акаунт го изпълнява. Работи трикомпонентно предаване, при което привилегированата стъпка казва какво се е случило, а отделна единица извършва действието под правилната идентичност.

Потребителско име в средата не е превключвател на идентичност

Unix решава до какво може да се докосне един процес по неговия ефективен потребителски ID, а не по низовете в средата му. Задаването на USER=alice или експортирането на LOGNAME променя какво небрежен софтуер отпечатва в изхода си; не променя нищо в проверките за собственост на файлове. Hook, който работи като 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, защото предишният hook го е създал, правилно конфигурирано потребителско действие ще се провали с грешка за разрешение, която изглежда като проблем със systemd и не е.

Демонът си остава там, където е

Смяната на собствения User= на VPN услугата на Алис е грешен лост. Това променя как демонът свързва интерфейси, чете ключове, записва файла си със състояние и управлява маршрути, и прехвърля целия този риск в единица, която е работела. Демонът се нуждае от привилегиите си; последващото действие не.

Вижте какво всъщност прави единицата, преди да я пипате. Две команди ви казват изпълнителната идентичност и точните командни редове в сила, включително всичко добавено от файл за замяна:

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

При стандартна инсталация от пакет демонът е root и скриптът --up наследява това. Потвърдете го, вместо да предполагате, защото затегнато издание може да го е преместило към специален акаунт, а ръчно написан drop-in може да пуска hook-а през обвивка с различни правила.

Три именувани части, един тесен тригер

Подредбата, която оцелява при поддръжка, има събитие, тригер и действие. Демонът съобщава, че именувана сесия е вдигната. Тригерът приема този малък факт и иска едно фиксирано действие. Действието работи под локалния акаунт, който притежава файловете, които пипа. Нищо във веригата не приема произволен път до команда.

Самото действие е обикновена service единица, а идентичността е една директива вътре в нея:

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

Обърнете внимание, че User=alice се отнася за цялата единица, и systemd документира едно изключение, което си струва да се знае: команда с префикс + работи с пълни привилегии независимо от това. Този префикс е законен инструмент за една привилегирована стъпка и удобен начин да отмените разделението, което току-що изградихте, затова третирайте всеки + в тази единица като нещо, което трябва да се обоснове при преглед.

Дръжте входа на тригера минимален и несекретен. Идентификаторът на сесията, преобразуваният акаунт и времева марка обикновено са всичко необходимо. Никога не предавайте през границата фрагмент от shell, път до изпълним файл или блок от среда, предоставен от клиента, защото приемащата страна няма как да различи законна стойност от инжектирана.

Проверете идентичността, която наистина е работила

Прегледът на конфигурацията не е доказателство. След одобрена тестова връзка потвърдете 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 на Алис има нейната идентичност и нищо от сесията ѝ, затова всичко, което изисква графична шина, трябва да мине през поддържания механизъм за потребителска сесия и да определи какво става, когато тя е излязла.

Повторните свързвания също се повтарят. Лаптоп, който заспива във влак, може да произведе дузина събития за връзка за час, а hook, който всеки път добавя ред, превръща файл със състояние в журнал, който никой не може да чете. Направете действието идемпотентно или го оставете да заменя един запис с ключ по сесия.

Накрая, ограничете радиуса на щетите в самата единица: изглед на файловата система само за четене извън директорията на състоянието, без нови привилегии и с явен таймаут. Разделението между демон и потребителско действие си струва само по себе си, но струва много повече, когато действието не може да направи нищо друго освен единственото, което сте одобрили.

Подобни статии