VPN на Mac під час завантаження: launchd стежить за завданням, а не за тунелем
plist, що пройшов lint, нічого не доводить ні про облікові дані, ні про готовність. Прив'яжіть завдання до його сеансу, тримайте клієнт на передньому плані й перевіряйте в цьому контексті.
Завдання запускається під час входу, журнал показує запуск клієнта, але тунель так і не піднімається. Або піднімається і зникає за кілька секунд. В обох випадках список властивостей, найімовірніше, був гаразд. launchd дав дві обіцянки, приймаючи завдання: він стежитиме за процесом, і цей процес продовжуватиме працювати. VPN потрібне і те, і те, а коректний XML-файл не дає жодного.
Коректний список властивостей — ще не працюючий сервіс
plutil -lint перевіряє структуру. Він не може сказати, чи існує бінарний файл, чи підтримує аргументи ця версія клієнта і чи запускається завдання в контексті, де доступні облікові дані. Це семантичні питання, і вони пояснюють більшість збоїв, які виглядають як проблеми launchd.
plutil -lint /Library/LaunchDaemons/com.example.vpn.plist
launchctl print system/com.example.vpn
Прочитайте вивід другої команди, а не припускайте, що завдання завантажено. Він повідомляє останній статус виходу й чи працює сервіс, що дозволяє до правки профілю відрізнити «так і не запустилося» від «запустилося й померло».
Агенти успадковують сеанс користувача, демони — ні
Документація Apple щодо launchd розділяє агентів окремих користувачів і системні демони. Агент працює в контексті користувача, який увійшов, з його зв'язкою ключів і середовищем. Демон працює без цього сеансу, і перенесення завдання до системного каталогу не відтворює інтерактивні облікові дані користувача.
Саме ця різниця визначає архітектуру. Якщо з'єднання вимагає, щоб людина увійшла або підтвердила запит MFA, підтримуваний варіант — завдання в сеансі користувача, яке запускається після входу. Якщо воно має працювати без жодного користувача, клієнту потрібна схвалена бездоглядна ідентичність із власним процесом поновлення й відкликання. Вибір неправильного рядка дає завдання, яке чисто стартує і падає на першому кроці автентифікації.
Не маскуйте різницю паролем у масиві аргументів або вимкненням перевірки сертифікатів. І те, і те перетворює вимогу автентифікації на постійний секрет у читабельному файлі, а друге означає, що тунель автентифікує все, що відповідає.
Нагляд працює лише тоді, коли процес залишається на передньому плані
Клієнт, який сам демонізується, негайно повертає керування launchd, і спостерігач починає стежити за вже завершеним процесом. Тунель може бути піднятий, але launchd вважає, що завдання не вдалося, і його політика перезапуску зробить те, чого ви не мали на увазі.
Використовуйте документований режим переднього плану або сервісу. Якщо продукт має власну підтримувану функцію запуску, вона вже знає, як залишатися на передньому плані й як передати керування мережевому стеку; власне завдання — окремий проєкт, а не її поліпшення.
Дайте завданню унікальну мітку, потрібний виконуваний файл і продуманий масив аргументів. Масив — не командний рядок оболонки, тому конвеєри й переспрямування там не працюють, а лапки поводяться інакше. Команда, яка успішно виконується в терміналі адміністратора, — у найкращому разі попередня перевірка.
Облікові дані мають працювати без запиту
Робота без супроводу не усуває проблему облікових даних, а переносить її. Хтось має володіти ідентичністю, вирішувати, скільки вона живе, і документувати, як її замінюють. Сертифікат без контролю терміну дії перетворюється на збій із датою в календарі.
Тримайте секрети поза аргументами й поза стандартним виводом завдання. Якщо клієнт підтримує читання облікових даних із захищеного сховища, використовуйте цей шлях і перевірте, що контекст виконання завдання може дістатися сховища. Демон, що працює від root, зазвичай не може прочитати елемент зв'язки ключів входу, і це саме та деталь, яка проявляється лише в системному контексті.
Визначте, що означає готово, і перевіряйте саме там
Успішний запуск доводить, що процес почався. Він не доводить, що мережа піднята, що шлюз прийняв ідентичність або що приватний застосунок доступний. Якщо щось інше залежить від тунелю, йому потрібен сигнал готовності, що відображає з'єднання, а не час запуску завдання.
Повтори мають бути обмеженими й мають відрізняти відсутню мережу від відхилених облікових даних. Перезапуск при кожній помилці не полагодить прострочений сертифікат і дає журнал, повний однакових спроб, який приховує справжню.
Прийміть завдання в тому контексті, у якому воно справді працюватиме: без мережі під час завантаження, за звичайного входу, після пробудження зі сну й за контрольованої зупинки. Потім запишіть мітку завдання, версію клієнта й ревізію профілю разом, щоб наступна людина успадкувала відстежуваний сервіс, а не файл, що колись працював.