Files
OpenVPN-Monitoring-Simple/DOCS/Operations/PLAN-validation-and-privilege-drop.md
T
iclaoudezinandClaude Sonnet 5.5 3836049230 Docs: add operations records (SUMMARY, Hysteria chain manifest, reboot test, plans)
- DOCS/Operations: current-state SUMMARY of the ENTRY deployment (access,
  install, egress via Hysteria2, security findings and fixes, risk
  assessment, commits/backups, open items), the Hysteria chain manifest
  with an OpenVPN Monitor section, reboot test results, and the plan and
  rollout records for settings validation and privilege separation.
- Link them from README and DOCS/General/Index.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 12:59:55 +00:00

7.3 KiB
Raw Blame History

План: валидация настроек (п.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.