Како пронаћи који systemd sandbox одбија ваш OpenVPN hook
Hook ради као root и не успева под systemd-ом јер unit задржава мање могућности, мањи /dev и путање само за читање.
Hook ради када га покренете ручно као root и враћа Operation not permitted у тренутку када га услуга покрене. Датотека се није променила између тих покретања; окружење јесте. systemd даје процесу мањи свет: мање могућности, другачији /dev, путање датотечног система само за читање и горњу границу задатака. Неуспех читајте као границу која је одбила једну одређену операцију, а не као скрипту која се покварила.
Почните од операције која је одбијена
Линија дневника која каже да је unit неуспешан не говори вам готово ништа. Корисна линија именује позив који је одбијен: чвор уређаја који није могао да се отвори, директоријум у који није могло да се пише, именски простор који није могао да се створи. Пронађите тај позив пре него што дотакнете било коју директиву, јер свака одговара другом ограничењу. Затим прочитајте unit који је стварно радио, укључујући drop-in датотеке, уместо датотеке коју је испоручио пакет.
Упит испод исписује путању фрагмента, директоријуме за drop-in и својства која су важна за одбијање уређаја или датотечног система. Прочитајте их све пре него што одлучите која је граница релевантна:
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'Ништа у том блоку не пише. Ако одбијени позив недостаје у дневнику, повећајте детаљност клијента за једно покретање уместо да погађате директиве. Процес који ради доказује да је unit стартовао, а не да је hook радио са потребним привилегијама.
Именском простору су потребна права за mount која TUN уређај никада не користи
Две операције које унутар једног hook-а изгледају исто имају различите профиле дозвола. Отварање /dev/net/tun и стварање интерфејса захтева мрежну администрацију плус приступ том чвору. Стварање именованог мрежног именског простора такође захтева рад са mount-ом, јер алат именских простора монтира свеж /sys поглед и причвршћује директоријум стања на место. Узводни unit клијента намерно оставља администрацију mount-а изван свог скупа ограничења, па се корак именског простора одбија док би сам тунел радио.
Зато давање чвора уређаја не спасава скрипту. Дозвола за уређај одговара на једно питање, да ли овај процес сме да отвори овај чвор, а питање именског простора је друго. Ускладите позив који не успева са његовом могућношћу пре него што било шта проширите.
Тест у вашем shell-у наслеђује сваку могућност коју има неограничени root, а unit наслеђује оно што је његов скуп ограничења задржао. Та два покретања су различити експерименти чак и када је бинарни фајл исти.
Уређаји, заштићене путање и горње границе задатака
Када је одбијена операција позната, три групе директива објашњавају већину неуспеха. Приступ уређајима уређује PrivateDevices, који замењује /dev минималним скупом псеудоуређаја, и DevicePolicy са DeviceAllow, који одлучују шта cgroup дозвољава. /dev/net/tun није део тог минималног скупа, па unit са PrivateDevices=yes не може да га отвори шта год политика уређаја каже.
Заштита датотечног система одговара на друго питање. ProtectHome=yes чини /home, /root и /run/user недоступним, а ProtectSystem=full чини /usr, /boot и /etc само за читање. Зато hook који пише поред своје конфигурационе датотеке ради у вашем shell-у и не успева под unit-ом, са истим обликом дозволе као недостајућа могућност. Преместите улаз у који се пише на путању коју политика дозвољава, или додајте узак ReadWritePaths= унос.
Ограничења ресурса су трећа група, и најмање очигледна. TasksMax= ограничава колико задатака unit сме да створи, а горња граница датотечних дескриптора понаша се исто за сокете и ручке. Поставка која је прерасла границу не успева са грешком ресурса, а не са грешком дозволе, и зато је тачна порука и даље важна.
Изместите корак именског простора из hook-а
Припрема која захтева привилегију коју клијент не сме да има припада сопственом unit-у. Oneshot који ради пре клијента, чува свој резултат и поређан је пре везе даје кораку именског простора шта му је потребно, а да те привилегије не предаје процесу тунела. Клијент затим референцира тај unit уместо да позива скрипту из свог up hook-а.
Шаблон испод је почетни облик, а не нешто што се примењује без читања. Држи припрему тамо где живи привилегија и оставља unit тунела нетакнут:
# /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Додајте редослед кроз drop-in уместо да уређујете упаковани unit, како надоградња не би могла тихо да одбаци вашу измену. Директоријум је везан за назив инстанце, па други профил захтева сопствену датотеку:
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Поновите исти позив након измене
Поправка се потврђује само када исти позив да другачији резултат. Поново покрените оба unit-а, извршите операцију која није успела и упоредите њен исход са линијом дневника коју сте сачували пре измене. Unit који стартује док hook више никада не ради није поправка.
Низ испод одржава поређење поштеним, јер проверава одбијени позив, а не боју unit-а. Сачувајте његов излаз поред линије дневника коју сте забележили пре измене:
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Бројте одбијања уместо да читате последњу линију, јер hook може да подбаци, покуша поново и успе, и само број показује да ли се граница померила. Оставите коментар у drop-in-у са називом директиве коју сте ублажили и разлогом, пошто следећа надоградња пореди вашу конфигурацију са упакованим подразумеваним. Unit који стартује тек када је свака заштита искључена није поправљен.