# План: валидация настроек (п.1) и запуск API не от root (п.2) Дата: 2026-09-30. Узел: 213.226.125.13 (Alpine, OpenRC). Приложение: `/opt/OpenVPN-Monitoring-Simple`. Основание: SUMMARY-ovpn-monitor.md, раздел 6.5 — администратор панели фактически равен root, т.к. Profiler работает от root, а настройки без проверки попадают в `server.conf`. ## Исходные факты - `APP_CORE` (API, gatherer) root не нужен: читает `openvpn-status.log`, пишет свою SQLite-БД и лог. - Profiler требует root только для: записи `/etc/openvpn/server.conf`, `rc-service openvpn`, чтения PKI-файлов самим OpenVPN. - В коде уже есть fallback `staging/server.conf`. - В шаблоне `script-security 2` стоит внутри `{% if user_defined_cdscripts %}`. - `doas` установлен; конфигурация только `permit nopass :wheel`. ## Пункт 1. Валидация настроек (3 слоя) **Слой A. Схемы (`APP_PROFILER/schemas.py`)** — валидаторы только на `*Update`-схемах (старые значения из БД не ломают `GET`). | Поле | Правило | |---|---| | `port`, `management_port` | 1–65535 | | `vpn_network`, `vpn_netmask` | `ipaddress`: сеть и корректная маска | | `split_routes[]` | CIDR или «сеть маска», нормализация через `ipaddress` | | `dns_servers[]` | IPv4/IPv6 через `ipaddress` | | `public_ip` | IP или hostname по маске, без пробелов и кавычек | | `management_interface_address` | только loopback | | `tun_mtu` / `mssfix` | 576–9000 / 536–1500 | | `connect_script`, `disconnect_script` | пусто или `^/etc/openvpn/scripts/[A-Za-z0-9_.-]{1,64}$` | | PKI `fqdn_ca`, `fqdn_server` | маска как у `username` | | PKI `easyrsa_dn` | `cn_only` или `org` | | PKI `req_country` | `^[A-Z]{2}$` | | PKI `req_province/city/org/ou` | `^[A-Za-z0-9 .,_-]{0,64}$` | | PKI `req_email` | простая маска email | | PKI `key_size` | 2048 / 3072 / 4096 | | PKI сроки | целые в разумных пределах | **Слой B. Скрипты (`routers/server.py`, до генерации):** `realpath` внутри `/etc/openvpn/scripts/`, файл существует, владелец root, нет прав записи для group/other. **Слой C. Генератор (`services/generator.py`):** перед записью проверить, что ни одно значение не содержит `\n`, `\r`, `"`, `\`; иначе ошибка и файл не пишется. Тесты: невалидные значения (перевод строки в DNS, `../` в скрипте, `/` в организации, порт 0) → 422; валидный набор → 200 и корректный `server.conf`. ## Пункт 2. Profiler и API не от root Схема: пользователь `ovpmon` + маленький root-помощник, сам валидирующий конфиг (защита в глубину: инъекция в конфиг не даёт root даже при обходе слоёв A–C). 1. **Пользователь и права.** Системный `ovpmon`. Владелец: `/var/lib/ovpmon`, `/var/log/ovpmon`, `APP_PROFILER/{easy-rsa,client-config,staging,*.db,profiler.log}`, `APP_CORE/{*.db,*.log}`. `pki/`: каталоги 755, `crl.pem` 644, приватные ключи 600. Код и `venv` остаются root-owned. `/etc/ovpmon/env` остаётся root 600. 2. **OpenRC:** `command_user="ovpmon:ovpmon"` в `ovpmon-*`. 3. **Помощник `/usr/local/sbin/ovpmon-helper`** (root, 755, Python). Подкоманды без пользовательских аргументов: - `install-config`: читает только `/var/lib/ovpmon/staging/server.conf` (один раз в память, защита от TOCTOU), проверяет allowlist директив (запрещены `up`, `down`, `plugin`, `route-up`, `tls-verify`, `auth-user-pass-verify`, `learn-address`, неизвестные; `client-connect/disconnect` и `script-security` — только со скриптом из `/etc/openvpn/scripts/` с проверкой владельца и прав), пишет `/etc/openvpn/server.conf` атомарно (root:root 644). - `service start|stop|restart|status` только для `openvpn`. 4. **`doas`:** `/etc/doas.d/ovpmon.conf`, точные `args` для каждой подкоманды. 5. **Код Profiler:** на хосте `services/process.py` и `routers/server.py` вызывают `doas ovpmon-helper …`; ветка контейнера и `staging` не меняются. 6. **`APP_CORE`:** только смена владельца и `command_user`. 7. **Каталог скриптов:** `/etc/openvpn/scripts/` root:root 755, по умолчанию пустой. ### Порядок 1. Бэкап `/etc/openvpn`, БД, `/etc/init.d/ovpmon-*`, код, `easy-rsa/`. 2. Слои A–C + тесты, перезапуск Profiler. 3. Пользователь, `chown`, помощник, `doas`; ручная проверка помощника. 4. Переключить `process.py` и `server.py` на помощник. 5. Переключить init-скрипты на `command_user`, перезапускать по одному. 6. Обновить документацию и SUMMARY, отдельные коммиты. ### Проверка (п.2) - `ps`: Profiler и API под `ovpmon`. - От `ovpmon`: нет доступа к `/etc/shadow`, `/root`, `/etc/hysteria/*.yaml`, запись в `/etc/openvpn` запрещена. - UI: Initialize PKI, генерация и запись конфига, Start/Stop/Restart OpenVPN, создание/скачивание/отзыв профиля, мониторинг. - Инъекция директивы в `staging/server.conf` отвергается помощником, `/etc/openvpn/server.conf` не меняется. - Прямые вызовы `doas` с другими аргументами отклоняются. - OpenVPN-клиент подключается и выходит через hel. - Не сломаны fail2ban, HTTPS 8088, `ip rule 102`. ## Риски | Риск | Смягчение | |---|---| | Сервис не стартует из-за прав | бэкап, `chown` до переключения, откат правкой init-скриптов | | Allowlist блокирует легальный конфиг | первый прогон в режиме проверки без записи; список директив из `server.conf.j2` | | Ошибка в `doas` `args` | негативные тесты от `ovpmon`, запасная root-SSH-сессия | | Потеря ключей PKI | копия `easy-rsa/` перед `chown` | ## Статус - Пункт 1 — реализован (2026-09-30), см. SUMMARY раздел 6.6 и DOCS/Changes/2026-09-30_Settings_Validation.md. - Пункт 2 — реализован (2026-09-30), см. IMPLEMENTATION-02-privilege-separation.md и DOCS/Changes/2026-09-30_Privilege_Separation.md.