622 lines
37 KiB
Markdown
622 lines
37 KiB
Markdown
# Lemana VPN
|
||
|
||
CLI-установка корпоративного VPN `vpn.lemanapro.ru` для macOS.
|
||
|
||
**По умолчанию:** ручной вход без сохранения паролей. Откроется окно корпоративного входа, а логин, пароль и одноразовый код вводятся вручную. Bitwarden, Touch ID, сохранение пароля, подстановка 2FA и автоматический вход включаются только явно.
|
||
|
||
**Режимы входа:** `manual` ничего не сохраняет и ничего не подставляет; `saved-login` хранит LDAP логин/пароль в macOS Keychain и оставляет одноразовый код ручным; `saved-totp` дополнительно хранит постоянный код настройки 2FA; `auto` запускается только явно через `vpn-auto`/`--auto`.
|
||
|
||
Репозиторий собирает в один воспроизводимый пакет то, что раньше было ручной локальной настройкой:
|
||
|
||
- `openconnect` как VPN-клиент;
|
||
- `openconnect-lite` для SAML SSO через Keycloak;
|
||
- опциональный Bitwarden CLI для LDAP-пароля и постоянного кода настройки 2FA;
|
||
- опциональный Touch ID helper для мастер-пароля Bitwarden;
|
||
- Swift Menu Bar app `LemanaVPN.app`;
|
||
- безопасный DNS cleanup через root-owned wrapper;
|
||
- алиасы `vpn`, `vpn-auto`, `vpn-manual`, `vpn-manual-full`, `vpn-debug`, `vpn-fix-dns`.
|
||
|
||
## Быстрая установка
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||
```
|
||
|
||
Если установка запущена из терминала, скрипт работает как простой wizard: объяснит, что будет установлено, по Enter оставит безопасный ручной режим и предложит дополнительные удобства только отдельным выбором.
|
||
|
||
После установки открой новый shell или выполни:
|
||
|
||
```sh
|
||
exec zsh
|
||
vpn
|
||
```
|
||
|
||
## Интерактивная установка
|
||
|
||
Обычный путь — запустить installer без флагов и ответить на вопросы:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||
```
|
||
|
||
Первый важный вопрос — как подключаться:
|
||
|
||
```text
|
||
Как подключаться по умолчанию?
|
||
|
||
1) Вводить всё вручную (рекомендуется)
|
||
Откроется окно входа. Вы сами введёте логин, пароль и одноразовый код.
|
||
|
||
2) Запомнить логин и пароль на этом Mac
|
||
При входе логин и пароль подставятся сами. Одноразовый код вы введёте вручную.
|
||
|
||
3) Настроить автоматический вход
|
||
Нужно заранее сохранить пароль и постоянный код настройки 2FA.
|
||
|
||
Выбор [1/2/3, Enter=1]:
|
||
```
|
||
|
||
Что означают варианты:
|
||
|
||
- `1` — ничего не сохранять. Это самый понятный старт: при подключении открывается окно входа, всё вводится руками.
|
||
- `2` — сохранить LDAP логин и пароль в macOS Keychain. Одноразовый код всё равно вводится руками.
|
||
- `3` — продвинутый путь: сохранить полный набор данных для подстановки или подключить Bitwarden. Если не уверены, выбирайте `1`.
|
||
|
||
Дальше installer спросит только про системные модули: sudoers, aliases, Swift Menu Bar app и автозапуск. Bitwarden и Touch ID появляются только если вы явно выбрали продвинутый путь.
|
||
|
||
Флаги остаются для CI, повторяемых установок и диагностики. Для обычной установки они не нужны.
|
||
|
||
Проверить действия без изменений:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --dry-run
|
||
```
|
||
|
||
Пример неинтерактивного режима для автоматизации:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||
| sh -s -- --non-interactive --auth-profile saved-login --configure-login
|
||
```
|
||
|
||
Принудительно включить интерактивные вопросы:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --interactive
|
||
```
|
||
|
||
Запустить без вопросов, с выбранными флагами и дефолтами:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --non-interactive
|
||
```
|
||
|
||
Если 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 |
|
||
| `~/Applications/LemanaVPN.app` | Swift Menu Bar app для подключения из status bar |
|
||
| `~/Library/LaunchAgents/ru.dokops.LemanaVPN.plist` | Автозапуск Menu Bar app при логине |
|
||
| `~/.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-auto`, `vpn-manual`, `vpn-manual-full`, `vpn-debug`, `vpn-fix-dns` |
|
||
|
||
## Статус модулей
|
||
|
||
`vpn` и `vpn --status` первой строкой показывают, какие модули включены в конфиге и реально установлены на машине:
|
||
|
||
```sh
|
||
vpn --status
|
||
Modules: ✅ core=ok, 🔐 auth_profile=manual, 🔐 credential_source=none, ⏭️ bitwarden=off, ⏭️ touchid=off, ✅ dns=on, ✅ app=on, ✅ autostart=on, ✅ patches=active, ✅ keychain=password:no/totp_seed:no
|
||
VPN disconnected
|
||
```
|
||
|
||
Emoji в human-выводе помогают быстро отличать норму, отключённый опциональный модуль и проблему:
|
||
|
||
- `✅` — модуль установлен или состояние готово;
|
||
- `⏭️` — модуль осознанно отключён;
|
||
- `⚠️` — модуль включён, но чего-то не хватает.
|
||
|
||
Значения:
|
||
|
||
| Поле | Значение |
|
||
| --- | --- |
|
||
| `core=ok` | Есть `openconnect`, `openconnect-lite` и config |
|
||
| `auth_profile=manual/saved-login/saved-totp/auto` | Как CLI будет открывать окно входа и использовать сохранённые данные |
|
||
| `credential_source=none/keychain/bitwarden` | Откуда брать сохранённые данные, если выбран режим с подстановкой |
|
||
| `bitwarden=on` | Модуль явно включён и `bw` установлен |
|
||
| `bitwarden=off` | Модуль отключён по умолчанию или через `--without-bitwarden` |
|
||
| `bitwarden=missing` | Модуль включён, но `bw` не найден |
|
||
| `touchid=on/off/missing` | Состояние Touch ID helper |
|
||
| `dns=on/missing` | Наличие DNS cleanup wrapper |
|
||
| `app=on/missing` | Установлен ли `~/Applications/LemanaVPN.app` |
|
||
| `autostart=on/off` | Есть ли LaunchAgent для запуска приложения при логине |
|
||
| `patches=active/pending` | Применены ли runtime-патчи `openconnect-lite` |
|
||
| `keychain=password:yes/totp_seed:yes` | Есть ли LDAP-пароль и постоянный код настройки 2FA в Keychain |
|
||
|
||
JSON-режим тоже отдаёт модульный статус:
|
||
|
||
```sh
|
||
vpn --status --json
|
||
```
|
||
|
||
## Интерактивная установка
|
||
|
||
Перед установкой `install.sh` печатает текущее состояние:
|
||
|
||
```text
|
||
Detected state:
|
||
openconnect: yes
|
||
pipx: yes
|
||
openconnect-lite: yes
|
||
Bitwarden CLI: no
|
||
Touch ID helper: no
|
||
DNS cleanup: no
|
||
sudoers: no/no
|
||
shell aliases: no
|
||
Swift: yes
|
||
Menu Bar app: no
|
||
LaunchAgent: no
|
||
Keychain password: no
|
||
Keychain 2FA setup: no
|
||
```
|
||
|
||
Если доступен терминал, скрипт ведёт установку вопросами:
|
||
|
||
- оставить ручной вход, сохранить только логин/пароль или настроить подстановку сохранённых данных;
|
||
- поставить Bitwarden CLI только если выбран Bitwarden;
|
||
- собрать Touch ID helper только если выбран Bitwarden;
|
||
- собрать ли Swift Menu Bar app, если `~/Applications/LemanaVPN.app` не найден;
|
||
- включить ли автозапуск Menu Bar app при логине;
|
||
- настроить ли sudoers для `openconnect` и DNS cleanup;
|
||
- добавить ли алиасы в `~/.zshrc`.
|
||
|
||
Флаги имеют приоритет над вопросами и нужны в основном для CI, диагностики или повторяемых unattended installs. Например, `--auth-profile saved-login --configure-login` сразу выберет сохранение логина/пароля, а `--no-shell` не будет предлагать алиасы.
|
||
|
||
В неинтерактивной среде скрипт не задаёт вопросов и использует выбранные флаги/дефолты. Для CI или повторяемой установки лучше явно указывать `--non-interactive`.
|
||
|
||
## Логи установщика и удаления
|
||
|
||
Установщик и uninstall script печатают пошаговый лог с emoji, цветом в интерактивном терминале и коротким пояснением, зачем нужен каждый шаг. Например, перед сборкой Swift-приложения установщик отдельно пишет, что `swift build` может занять время и что строки компилятора вида `[2/5] Write swift-version...` являются нормальным выводом. При удалении отдельно показывается откат runtime-патчей `openconnect-lite`, удаление sudoers/DNS wrapper, приложения, aliases и config.
|
||
|
||
Отключить цвет:
|
||
|
||
```sh
|
||
NO_COLOR=1 sh install.sh
|
||
NO_COLOR=1 sh uninstall.sh
|
||
```
|
||
|
||
Отключить emoji:
|
||
|
||
```sh
|
||
LEMANA_VPN_NO_EMOJI=1 sh install.sh
|
||
LEMANA_VPN_NO_EMOJI=1 sh uninstall.sh
|
||
```
|
||
|
||
## Модули
|
||
|
||
### Core
|
||
|
||
Всегда устанавливается:
|
||
|
||
- `openconnect` через Homebrew;
|
||
- `pipx` через Homebrew;
|
||
- `openconnect-lite` через `pipx`;
|
||
- CLI `vpn-lemanapro.sh`;
|
||
- `openconnect-lite` config;
|
||
- DNS cleanup wrapper.
|
||
|
||
### Как работают режимы входа
|
||
|
||
Keychain entries:
|
||
|
||
- service `openconnect-lite`, account `<LDAP username>` — корпоративный LDAP/domain пароль;
|
||
- service `openconnect-lite`, account `totp/<LDAP username>` — постоянный код настройки 2FA, нужен только для подстановки одноразового кода и auto mode.
|
||
|
||
`auth_profile=manual` — режим по умолчанию. CLI не проверяет Keychain и Bitwarden, открывает видимое окно входа и ничего не подставляет. Логин, пароль и одноразовый код вводятся вручную.
|
||
|
||
`auth_profile=saved-login` — CLI берёт из Keychain только LDAP пароль и подставляет логин/пароль в видимое окно входа. Одноразовый код вводится руками. Настройка:
|
||
|
||
```sh
|
||
vpn --configure-login
|
||
```
|
||
|
||
`auth_profile=saved-totp` — CLI берёт LDAP пароль и постоянный код настройки 2FA из Keychain, подставляет поля в видимое окно входа, но submit не нажимает. Настройка:
|
||
|
||
```sh
|
||
vpn --configure-keychain
|
||
```
|
||
|
||
`auth_profile=auto` — старый автоматический путь: скрытый браузер, подстановка всех полей и submit. Запускается только явно:
|
||
|
||
```sh
|
||
vpn-auto
|
||
vpn --auto
|
||
```
|
||
|
||
`credential_source=bitwarden` — это sync-provider. CLI открывает Bitwarden vault, читает item `LM LDAP`, берёт из него LDAP password и постоянный код настройки 2FA, нормализует `otpauth://...secret=...` если нужно, затем записывает оба секрета в macOS Keychain. Bitwarden не включён по умолчанию.
|
||
|
||
Важно: Lemana VPN не хранит и не принимает текущий 6-значный код как постоянную настройку. Такой код живёт около 30 секунд. Для автоматического SSO нужен именно постоянный secret: raw Base32 или `otpauth://totp/...?...secret=BASE32`.
|
||
|
||
Если запуск идёт из menu-bar app, интерактивного terminal prompt нет. Поэтому настройку сохранённого логина или полного набора данных нужно один раз выполнить в Terminal.
|
||
|
||
### Bitwarden
|
||
|
||
Отключён по умолчанию. Его стоит включать только если у пользователя уже есть запись Bitwarden с корпоративным LDAP-паролем и постоянным кодом настройки 2FA.
|
||
|
||
Постоянный код настройки 2FA — это секрет, который обычно показывается при ручной настройке authenticator. Сам одноразовый код меняется каждые 30 секунд и генерируется `openconnect-lite` в момент входа.
|
||
|
||
Если vault заблокирован и Touch ID helper не смог его открыть, CLI спросит `Bitwarden master password`. Это пароль от хранилища Bitwarden, а не корпоративный LDAP-пароль. Он нужен только чтобы достать LDAP password и постоянный код настройки 2FA из item `LM LDAP` и переложить их в macOS Keychain.
|
||
|
||
Включить Bitwarden можно через продвинутый путь в installer wizard или флагами:
|
||
|
||
То же самое можно задать флагами для неинтерактивной установки:
|
||
|
||
```sh
|
||
sh install.sh --non-interactive --with-bitwarden --auth-profile saved-totp
|
||
```
|
||
|
||
Для Keychain-only режима без Bitwarden используйте:
|
||
|
||
```sh
|
||
sh install.sh --non-interactive --auth-profile saved-login --configure-login
|
||
```
|
||
|
||
Если сохранённые данные уже лежат в Keychain, подключение без Bitwarden не будет спрашивать пароль заново. Для режима `saved-login` одноразовый код всё равно вводится вручную.
|
||
|
||
### Если Bitwarden нет
|
||
|
||
Bitwarden не обязателен. Без него установка по умолчанию работает в полностью ручном режиме: откроется окно входа, а логин, пароль и одноразовый код вводятся руками.
|
||
|
||
Интерактивная установка:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||
```
|
||
|
||
В первом вопросе можно просто нажать Enter:
|
||
|
||
```text
|
||
1) Вводить всё вручную (рекомендуется)
|
||
```
|
||
|
||
Это встроенный бесплатный путь: не нужен Bitwarden account, платный Bitwarden TOTP или внешний password manager.
|
||
|
||
Если хочется, чтобы логин и пароль подставлялись сами, выбери пункт `2` или выполни позже:
|
||
|
||
```sh
|
||
vpn --configure-login
|
||
```
|
||
|
||
Что понадобится:
|
||
|
||
- LDAP username;
|
||
- LDAP password: корпоративный LDAP/domain пароль, не мастер-пароль Bitwarden;
|
||
- одноразовый код из корпоративной 2FA при каждом подключении.
|
||
|
||
Постоянный код настройки 2FA нужен только для `vpn --configure-keychain`, `saved-totp` и `vpn-auto`.
|
||
|
||
Не вставляй текущий 6-значный authenticator code в `vpn --configure-keychain`. Lemana VPN сохраняет в Keychain постоянный код настройки 2FA, а `openconnect-lite` по нему генерирует свежие одноразовые коды во время каждого SSO login.
|
||
|
||
Если запуск идёт из `LemanaVPN.app`, приложение не может безопасно показать интерактивный terminal prompt для сохранения пароля. Настройку saved-login или saved-totp нужно один раз выполнить в Terminal:
|
||
|
||
```sh
|
||
vpn --configure-login
|
||
vpn --configure-keychain
|
||
```
|
||
|
||
Если secret есть только в QR-коде:
|
||
|
||
1. Открой QR-код в приложении/на портале, где настраивалась 2FA.
|
||
2. Найди режим ручной настройки, где показывается secret.
|
||
3. Если доступен только QR, его нужно расшифровать любым локальным QR-сканером и взять параметр `secret`.
|
||
4. Вставь secret в prompt `2FA setup secret BASE32`.
|
||
|
||
Если постоянный 2FA secret получить нельзя, автоматический headless-вход невозможен: `openconnect-lite` не сможет сам генерировать свежий одноразовый код на каждом входе.
|
||
|
||
### Touch ID
|
||
|
||
Отключён по умолчанию и нужен только для Bitwarden-пути. Если пользователь выбрал Bitwarden, установщик может собрать `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
|
||
```
|
||
|
||
### Swift Menu Bar app
|
||
|
||
Включён по умолчанию. Установщик собирает Swift-приложение из исходников в репозитории и кладёт bundle в:
|
||
|
||
```sh
|
||
~/Applications/LemanaVPN.app
|
||
```
|
||
|
||
Приложение живёт в macOS status bar, запускает `~/bin/vpn-lemanapro.sh --json`, показывает состояние VPN, IP, оставшееся время сессии, health-check тоннеля и строку состояния модулей.
|
||
|
||
В отключённом состоянии меню показывает текущий режим установки:
|
||
|
||
- `Режим: полностью вручную` — доступна только обычная кнопка `Подключить`; логин, пароль и одноразовый код вводятся руками.
|
||
- `Режим: логин и пароль сохранены` — доступен вход с подстановкой логина/пароля и ручной ввод одноразового кода.
|
||
- `Режим: сохранённые данные без автоотправки` — доступны сохранённые данные, ручной fallback и явный automatic mode.
|
||
- `Режим: автоматический вход` — обычная кнопка `Подключить` запускает настроенный auto-flow, а ручные fallback-кнопки остаются доступны.
|
||
|
||
Кнопки, для которых текущая установка не готова, не показываются. Например, если не сохранён постоянный код настройки 2FA, в меню не будет автоматического входа. Если рядом с режимом есть подсказка `Настройте в Terminal`, выполните указанную команду в Terminal и нажмите `Обновить статус модулей`.
|
||
|
||
Строка состояния модулей в меню приложения использует те же маркеры, что CLI: `✅` для готового модуля, `⏭️` для отключённого опционального модуля и `⚠️` для проблемы. Иконка строки тоже меняется: `checkmark.circle` для полностью готового набора и `exclamationmark.triangle` для неполной установки.
|
||
|
||
Если в меню видно `modules unavailable: update CLI`, значит запущенное приложение обращается к старому `~/bin/vpn-lemanapro.sh`, который ещё не умеет отдавать модульный статус. Повтори установку через `curl`; установщик обновит CLI и перезапустит уже запущенное `LemanaVPN.app`.
|
||
|
||
Для сборки нужен Swift 5.9+ из Xcode Command Line Tools:
|
||
|
||
```sh
|
||
xcode-select --install
|
||
```
|
||
|
||
Отключить установку приложения:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-app
|
||
```
|
||
|
||
Оставить приложение, но отключить автозапуск:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-autostart
|
||
```
|
||
|
||
Ручной запуск:
|
||
|
||
```sh
|
||
open ~/Applications/LemanaVPN.app
|
||
```
|
||
|
||
## Использование
|
||
|
||
```sh
|
||
vpn # подключиться в настроенном режиме; fresh install = полностью вручную
|
||
vpn-auto # явный автоматический режим: скрытый браузер, auto-fill и submit
|
||
vpn --saved-login # подставить сохранённые логин/пароль, одноразовый код руками
|
||
vpn-manual # видимый браузер, сохранённые данные auto-fill без submit
|
||
vpn-manual-full # полностью ручной режим: видимый браузер без auto-fill и submit
|
||
vpn --manual # то же самое без alias
|
||
vpn --manual-full # то же самое без alias
|
||
vpn --status # статус без нового подключения
|
||
vpn --status --json # статус в JSON
|
||
vpn-debug # видимый браузер и debug-логи
|
||
vpn --manual --debug # ручной режим с debug-логами
|
||
vpn-fix-dns # сбросить корпоративные DNS после аварийного завершения
|
||
open ~/Applications/LemanaVPN.app # открыть Swift-приложение в menu bar
|
||
```
|
||
|
||
Режимы подключения:
|
||
|
||
- `manual` — режим fresh install по умолчанию. Браузер видимый, auto-fill отключён полностью, проверки сохранённых LDAP/TOTP credentials пропускаются: поля Keycloak заполняешь и отправляешь сам.
|
||
- `saved-login` — браузер видимый, логин/пароль берутся из Keychain, одноразовый код вводится руками, submit не нажимается.
|
||
- `saved-totp` / `--manual` — браузер видимый, LDAP-пароль и код 2FA берутся из Keychain/Bitwarden и подставляются в поля, но кнопка входа не нажимается.
|
||
- `auto` / `vpn-auto` — явный автоматический режим. Браузер скрытый, LDAP-пароль и код 2FA берутся из Keychain/Bitwarden, форма заполняется и отправляется автоматически.
|
||
- `--manual-sso` оставлен как совместимый alias для `--manual`.
|
||
- `--manual-no-autofill` оставлен как совместимый alias для `--manual-full`.
|
||
|
||
Первый запуск с Bitwarden, если он выбран явно:
|
||
|
||
1. CLI проверит `bw`.
|
||
2. Если vault locked, попросит мастер-пароль.
|
||
3. Если установлен Touch ID helper, предложит сохранить мастер-пароль за Touch ID prompt.
|
||
4. Достанет `LM LDAP`, запишет LDAP-пароль и постоянный код настройки 2FA в Keychain.
|
||
5. Запустит `openconnect-lite` и пройдёт Keycloak SSO.
|
||
|
||
## Настройка
|
||
|
||
Файл `~/.config/lemana-vpn/env`:
|
||
|
||
```sh
|
||
LEMANA_VPN_USERNAME="<LDAP_USERNAME>"
|
||
LEMANA_VPN_AUTH_PROFILE="manual"
|
||
LEMANA_VPN_CREDENTIAL_SOURCE="none"
|
||
LEMANA_VPN_BW_ITEM="LM LDAP"
|
||
LEMANA_VPN_USE_BITWARDEN="0"
|
||
LEMANA_VPN_USE_TOUCHID="0"
|
||
LEMANA_VPN_DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup"
|
||
```
|
||
|
||
Для режима с сохранённым логином и паролем:
|
||
|
||
```sh
|
||
LEMANA_VPN_USERNAME="<LDAP_USERNAME>"
|
||
LEMANA_VPN_AUTH_PROFILE="saved-login"
|
||
LEMANA_VPN_CREDENTIAL_SOURCE="keychain"
|
||
LEMANA_VPN_USE_BITWARDEN="0"
|
||
LEMANA_VPN_USE_TOUCHID="0"
|
||
LEMANA_VPN_DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup"
|
||
```
|
||
|
||
Если LDAP username не указан при установке, `vpn` спросит его при первом интерактивном запуске в Terminal и сохранит в `~/.config/lemana-vpn/env`. Для неинтерактивной установки можно указать его сразу:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||
| sh -s -- --username <LDAP_USERNAME>
|
||
```
|
||
|
||
## Bitwarden item
|
||
|
||
Нужна запись:
|
||
|
||
- название: `LM LDAP`;
|
||
- username: корпоративный LDAP логин;
|
||
- password: LDAP пароль;
|
||
- TOTP: `otpauth://...secret=BASE32...` или raw BASE32 secret.
|
||
|
||
Это не 6-значный одноразовый код. В Bitwarden должен лежать постоянный 2FA 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 без событий |
|
||
| `legacy auto-fill` | Сохраняет старую рабочую схему `ApplicationWorld`, прямой `value = ...` и простой `click()` | Это ровно тот режим, на котором hidden SSO раньше стабильно проходил Keycloak |
|
||
| `URL guard` | Проверяет `location.href` через `new RegExp(...)` перед auto-fill | Qt игнорирует `@include`, без guard auto-fill может кликнуть Cisco ACS и сломать SAML |
|
||
| `auth redirect` | Читает 302 с `vpn.lemanapro.ru` без автоматического follow-redirect | Python `requests` может падать на TLS reset при открытии `/` на `sslvpna/b`, хотя для SAML нужен только конечный host |
|
||
| `manual submit gate` | Позволяет отключить только auto-click через `LEMANA_VPN_AUTOFILL_CLICK=0` | Ручной режим видит заполненную форму, но сам решает, когда нажать вход |
|
||
| `manual SSO disable` | Позволяет полностью отключить auto-fill через `vpn --manual-full` или `LEMANA_VPN_AUTOFILL_DISABLE=1` | Нужен для низкоуровневой диагностики без подстановки полей |
|
||
|
||
Перед первым изменением 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
|
||
```
|
||
|
||
Обычный `vpn` теперь пишет путь к подробному логу `openconnect-lite`:
|
||
|
||
```sh
|
||
~/Library/Logs/LemanaVPN-openconnect-lite.log
|
||
```
|
||
|
||
Если после `Connecting to VPN (lemanapro)...` SSO завис или не видно, что происходит, смотри этот файл:
|
||
|
||
```sh
|
||
tail -f ~/Library/Logs/LemanaVPN-openconnect-lite.log
|
||
```
|
||
|
||
В обычном режиме CLI также печатает heartbeat `Still waiting for SSO/openconnect-lite...` до успешного подключения, чтобы было понятно, что процесс живой. В `vpn-debug` дополнительно показываются raw-логи и видимый браузер.
|
||
|
||
Если в логе повторяется один и тот же URL вида `employee.auth.lemanapro.ru/realms/employee/login-actions/authenticate`, значит hidden-браузер застрял на Keycloak до перехода в Cisco ACS. Сначала обнови и примени runtime-патчи без подключения:
|
||
|
||
```sh
|
||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||
vpn-lemanapro.sh --patch-only
|
||
```
|
||
|
||
Если лог падает раньше браузера с `SSLEOFError` / `UNEXPECTED_EOF_WHILE_READING` на `sslvpna.lemanapro.ru` или `sslvpnb.lemanapro.ru`, это ломается этап определения конечного Cisco headend. Актуальный runtime-патч `auth redirect` не открывает `/` на `sslvpna/b`, а только берёт `Location` из 302 ответа `vpn.lemanapro.ru` и продолжает штатный SAML init через POST.
|
||
|
||
Если SSO ломается после обновления `openconnect-lite`, запусти:
|
||
|
||
```sh
|
||
vpn-debug
|
||
```
|
||
|
||
Если нужно самому посмотреть форму Keycloak, но оставить подстановку LDAP/TOTP:
|
||
|
||
```sh
|
||
vpn --manual
|
||
```
|
||
|
||
В этом режиме браузер видимый, `openconnect-lite` заполняет поля из Keychain/Bitwarden, но не нажимает submit.
|
||
|
||
Если нужно проверить SSO полностью вручную, без подстановки LDAP-пароля и TOTP:
|
||
|
||
```sh
|
||
vpn --manual-full
|
||
```
|
||
|
||
Этот режим не требует заранее сохранённого LDAP username/password/TOTP и не запускает Bitwarden/Keychain preflight.
|
||
|
||
Если установка падает на строке `install: /usr/local/sbin/...: No such file or directory`, значит на машине не было `/usr/local/sbin`. Актуальный `install.sh` создаёт эту директорию сам; достаточно повторить установку свежей командой `curl`.
|
||
|
||
CLI перед подключением патчит `openconnect-lite`:
|
||
|
||
- `minimal` -> `offscreen`, чтобы Qt WebEngine не падал на macOS;
|
||
- добавляет `input` и `change` events для Keycloak auto-fill, сохраняя старое прямое присваивание `value = ...`;
|
||
- оставляет auto-fill в старом `ApplicationWorld` и не добавляет stateful click guards/native setters;
|
||
- добавляет URL guard, чтобы auto-fill не кликал submit на Cisco ACS;
|
||
- добавляет auth redirect patch, чтобы Python не падал на TLS reset при follow-redirect к `sslvpna/b`;
|
||
- добавляет manual submit gate для видимой ручной диагностики с auto-fill, но без auto-submit.
|
||
|
||
## Удаление
|
||
|
||
Рекомендуемый способ:
|
||
|
||
```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`;
|
||
- останавливает уже запущенный процесс `LemanaVPN`, удаляет `~/Applications/LemanaVPN.app` и LaunchAgent автозапуска;
|
||
- удаляет `~/.config/lemana-vpn`, если не передан `--keep-config`.
|
||
|
||
Опциональные режимы:
|
||
|
||
```sh
|
||
uninstall-lemana-vpn.sh --dry-run
|
||
uninstall-lemana-vpn.sh --keep-config
|
||
uninstall-lemana-vpn.sh --keep-app
|
||
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
|
||
```
|