Како да откриете кој 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 работа, бидејќи алатката за именски простори 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-от смее да ги создаде, а горната граница на датотечни дескриптори се однесува исто за socket и рачки. Распоредување што пораснало над границата паѓа со грешка за ресурси наместо со грешка за дозвола, и затоа точната порака сѐ уште е важна.
Извадете го чекорот со именски простор од 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 што стартува само откако ќе се исклучи секоја заштита не е поправен.