# Lemana VPN CLI-установка корпоративного VPN `vpn.lemanapro.ru` для macOS. Репозиторий собирает в один воспроизводимый пакет то, что раньше было ручной локальной настройкой: - `openconnect` как VPN-клиент; - `openconnect-lite` для SAML SSO через Keycloak; - опциональный Bitwarden CLI для LDAP-пароля и TOTP; - опциональный Touch ID helper для мастер-пароля Bitwarden; - безопасный DNS cleanup через root-owned wrapper; - алиасы `vpn`, `vpn-debug`, `vpn-fix-dns`. ## Быстрая установка ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh ``` После установки открой новый shell или выполни: ```sh exec zsh vpn ``` ## Варианты установки Полная установка, режим по умолчанию: ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh ``` Без Touch ID, но с Bitwarden: ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-touchid ``` Минимальная установка без Bitwarden и Touch ID. Пароль LDAP и TOTP будут один раз записаны в macOS Keychain вручную: ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --minimal --configure-keychain ``` Проверить действия без изменений: ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --dry-run ``` Если raw URL отличается, переопредели базовый адрес: ```sh curl -fsSL https://example.org/dokril/lemana-vpn/raw/branch/main/install.sh \ | LEMANA_VPN_RAW_BASE_URL=https://example.org/dokril/lemana-vpn/raw/branch/main sh ``` ## Что ставится | Путь | Назначение | | --- | --- | | `~/bin/vpn-lemanapro.sh` | Основной CLI для подключения, статуса и sync секретов | | `~/bin/uninstall-lemana-vpn.sh` | Локальный uninstall helper | | `~/bin/keychain-fingerprint` | Опциональный Touch ID helper для мастер-пароля Bitwarden | | `~/.config/lemana-vpn/env` | Локальная конфигурация модулей | | `~/.config/lemana-vpn/patch-backups/` | Backup исходника `openconnect-lite` перед runtime-патчами | | `~/.config/openconnect-lite/config.toml` | Профиль SSO и auto-fill правила Keycloak | | `/usr/local/sbin/lemana-vpn-dns-cleanup` | Root-owned wrapper для сброса только корпоративных DNS | | `/etc/sudoers.d/lemana-vpn-openconnect` | `NOPASSWD` только для `openconnect` | | `/etc/sudoers.d/lemana-vpn-dns` | `NOPASSWD` только для DNS cleanup wrapper | | `~/.zshrc` | Идемпотентный блок алиасов `vpn`, `vpn-debug`, `vpn-fix-dns` | ## Модули ### Core Всегда устанавливается: - `openconnect` через Homebrew; - `pipx` через Homebrew; - `openconnect-lite` через `pipx`; - CLI `vpn-lemanapro.sh`; - `openconnect-lite` config; - DNS cleanup wrapper. ### Bitwarden Включён по умолчанию. CLI при каждом запуске `vpn` пытается получить LDAP-пароль и TOTP из записи Bitwarden `LM LDAP`, затем записывает их в macOS Keychain для `openconnect-lite`. Отключить: ```sh sh install.sh --without-bitwarden ``` В этом режиме credentials нужно положить в Keychain вручную: ```sh vpn-lemanapro.sh --configure-keychain ``` ### Touch ID Включён по умолчанию. Установщик собирает `keychain-fingerprint` из `https://github.com/dss99911/keychain-fingerprint.git` и кладёт бинарник в `~/bin/keychain-fingerprint`. Важно: этот helper показывает системный Touch ID prompt перед чтением мастер-пароля Bitwarden, но это не аппаратный Keychain ACL. Это удобный локальный гейт поверх записи Keychain. Отключить: ```sh sh install.sh --without-touchid ``` ## Использование ```sh vpn # подключиться vpn --status # статус без нового подключения vpn --status --json # статус в JSON vpn-debug # видимый браузер и debug-логи vpn-fix-dns # сбросить корпоративные DNS после аварийного завершения ``` Первый запуск с Bitwarden: 1. CLI проверит `bw`. 2. Если vault locked, попросит мастер-пароль. 3. Если установлен Touch ID helper, предложит сохранить мастер-пароль за Touch ID prompt. 4. Достанет `LM LDAP`, запишет LDAP-пароль и TOTP в Keychain. 5. Запустит `openconnect-lite` и пройдёт Keycloak SSO. ## Настройка Файл `~/.config/lemana-vpn/env`: ```sh LEMANA_VPN_USERNAME="60103293" LEMANA_VPN_BW_ITEM="LM LDAP" LEMANA_VPN_USE_BITWARDEN="1" LEMANA_VPN_USE_TOUCHID="1" LEMANA_VPN_DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup" ``` Для другого логина: ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \ | sh -s -- --username 12345678 ``` ## Bitwarden item Нужна запись: - название: `LM LDAP`; - username: корпоративный LDAP логин; - password: LDAP пароль; - TOTP: `otpauth://...secret=BASE32...` или raw BASE32 secret. ## Почему DNS wrapper, а не wildcard sudoers Старый вариант давал `NOPASSWD` на `networksetup -setdnsservers *`. Это слишком широкое право: любой локальный процесс пользователя мог поменять DNS на произвольный сервер. Новый вариант разрешает sudo только на `/usr/local/sbin/lemana-vpn-dns-cleanup`. Wrapper сбрасывает DNS только если текущий DNS начинается с `10.`, то есть похож на корпоративный VPN DNS. ## Runtime-патчи openconnect-lite `openconnect-lite` работает, но для текущей macOS + Keycloak SSO цепочки ему нужны три runtime-патча. CLI применяет их перед подключением в файле: ```sh ~/.local/pipx/venvs/openconnect-lite/lib/python*/site-packages/openconnect_lite/browser/webengine_process.py ``` Патчи: | Патч | Что меняет | Зачем | | --- | --- | --- | | `minimal -> offscreen` | Меняет Qt platform mode для скрытого браузера | `minimal` падает с Qt WebEngine на macOS | | `input/change events` | После `value = ...` отправляет DOM events | Keycloak не реагирует на прямую запись value | | `URL guard` | Проверяет `location.href` через `new RegExp(...)` перед auto-fill | Qt игнорирует `@include`, без guard auto-fill может кликнуть Cisco ACS и сломать SAML | Перед первым изменением CLI сохраняет оригинальный файл: ```sh ~/.config/lemana-vpn/patch-backups/webengine_process.py.before-lemana-vpn ``` Откат патчей выполняет uninstall script. Если backup отсутствует, автоматического rollback нет: значит файл был уже патчен старой ручной установкой или `openconnect-lite` переустановили после backup. ## Диагностика Проверить установку: ```sh command -v vpn-lemanapro.sh openconnect --version ~/.local/bin/openconnect-lite --help sudo -n /usr/local/sbin/lemana-vpn-dns-cleanup vpn --status ``` Если SSO ломается после обновления `openconnect-lite`, запусти: ```sh vpn-debug ``` CLI перед подключением патчит `openconnect-lite`: - `minimal` -> `offscreen`, чтобы Qt WebEngine не падал на macOS; - добавляет `input` и `change` events для Keycloak auto-fill; - добавляет URL guard, чтобы auto-fill не кликал submit на Cisco ACS. ## Удаление Рекомендуемый способ: ```sh curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/uninstall.sh | sh ``` Или локально: ```sh uninstall-lemana-vpn.sh ``` Что делает uninstall: - восстанавливает `openconnect-lite` из backup, если backup есть; - удаляет `vpn-lemanapro.sh` и `uninstall-lemana-vpn.sh`; - удаляет sudoers rules и DNS cleanup wrapper; - удаляет блок `lemana-vpn` из `~/.zshrc`; - удаляет `~/.config/openconnect-lite/config.toml`; - удаляет `~/.config/lemana-vpn`, если не передан `--keep-config`. Опциональные режимы: ```sh uninstall-lemana-vpn.sh --dry-run uninstall-lemana-vpn.sh --keep-config uninstall-lemana-vpn.sh --remove-keychain uninstall-lemana-vpn.sh --remove-touchid-helper uninstall-lemana-vpn.sh --remove-openconnect-lite ``` Ручной вариант, если нужен полный контроль: ```sh rm -f ~/bin/vpn-lemanapro.sh ~/bin/uninstall-lemana-vpn.sh rm -rf ~/.config/lemana-vpn rm -f ~/.config/openconnect-lite/config.toml sudo rm -f /usr/local/sbin/lemana-vpn-dns-cleanup sudo rm -f /etc/sudoers.d/lemana-vpn-openconnect /etc/sudoers.d/lemana-vpn-dns ``` Из `~/.zshrc` удалить блок: ```sh # >>> lemana-vpn ... # <<< lemana-vpn ```