# Документация проекта: Развертывание конфигурации HAProxy по событию через systemd path ## 1. Архитектурное описание Комплекс предназначен для мгновенного и контролируемого отката/применения резервной конфигурации балансировщика **HAProxy** по клику оператора с рабочей станции Windows. Вместо периодического опроса через cron система использует событийную модель ядра Linux (**inotify**) через связку **systemd path** + **systemd service**, что обеспечивает нулевую задержку реакции и отсутствие холостых запусков скрипта. ``` [ Рабочая станция Windows ] | (Ярлык на рабочем столе) | deployfile.exe (.NET 4.8) | | (1. SSH-сессия: ed25519) | (2. Запись status/change.me + status/sha256.hash) v [ Linux-сервер (HAProxy) ] /var/lib/depfile/status/change.me | (Событие inotify: IN_CLOSE_WRITE) v depfile-watcher.path (systemd) | (Активирует однократный сервис) v depfile-watcher.service (systemd: oneshot) | (Запуск /usr/local/bin/deploy_haproxy.sh) | |-- 1. Валидация SHA-256 суммы файла change.me |-- 2. Проверка синтаксиса backup/haproxy.cfg (haproxy -c) |-- 3. Подмена боевого /etc/haproxy/haproxy.cfg |-- 4. Перезапуск службы haproxy (systemctl restart) |-- 5. Удаление директории status/ `-- 6. Запись отчета в deployment/success.me ``` --- ## 2. Настройка Linux-сервера ### 2.1. Создание сервисного пользователя и рабочих каталогов Подключитесь к серверу с правами `root` или через `sudo`: ```bash # 1. Создаем системного пользователя с домашним каталогом /var/lib/depfile sudo useradd -m -d /var/lib/depfile -s /bin/bash -c "File deploment service" depfile # 2. Назначаем права доступа на домашний каталог sudo chown -R depfile:depfile /var/lib/depfile sudo chmod 750 /var/lib/depfile # 3. Создаем каталог резервных конфигураций HAProxy и размещаем эталонный конфиг sudo mkdir -p /etc/haproxy/backup sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/backup/haproxy.cfg sudo chown -R root:root /etc/haproxy/backup sudo chmod 750 /etc/haproxy/backup ``` ### 2.2. Подготовка каталога SSH-ключей Домашняя директория пользователя — `/var/lib/depfile`, путь к файлу доверенных ключей: `/var/lib/depfile/.ssh/authorized_keys`. ```bash sudo -u depfile mkdir -p /var/lib/depfile/.ssh sudo -u depfile touch /var/lib/depfile/.ssh/authorized_keys sudo chmod 700 /var/lib/depfile/.ssh sudo chmod 600 /var/lib/depfile/.ssh/authorized_keys ``` ### 2.3. Размещение скрипта развертывания Скопируйте скрипт из репозитория в каталог `/usr/local/bin/`: * Исходный файл: [`deploy_haproxy.sh`](deploy_haproxy.sh) ```bash sudo cp deploy_haproxy.sh /usr/local/bin/deploy_haproxy.sh sudo chmod +x /usr/local/bin/deploy_haproxy.sh ``` --- ### 2.4. Настройка связки systemd (Path + Service) #### Шаг 1: Юнит сервиса (`depfile-watcher.service`) Создайте файл описания процесса: ```bash sudo nano /etc/systemd/system/depfile-watcher.service ``` ```ini [Unit] Description=HAProxy Config Rollback Service After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/deploy_haproxy.sh StandardOutput=journal StandardError=journal ``` #### Шаг 2: Юнит отслеживания файловой системы (`depfile-watcher.path`) Создайте файл монитора событий: ```bash sudo nano /etc/systemd/system/depfile-watcher.path ``` ```ini [Unit] Description=Watch for deployment trigger file change.me [Path] # PathChanged срабатывает в момент завершения записи и закрытия дескриптора (IN_CLOSE_WRITE) PathChanged=/var/lib/depfile/status/change.me Unit=depfile-watcher.service [Install] WantedBy=multi-user.target ``` #### Шаг 3: Активация и запуск монитора ```bash sudo systemctl daemon-reload sudo systemctl enable --now depfile-watcher.path ``` Проверьте статус наблюдателя: ```bash systemctl status depfile-watcher.path ``` *(Должен находиться в состоянии `active (waiting)`).* --- ## 3. Настройка рабочей станции Windows ### 3.1. Генерация SSH-ключа В командной строке (`cmd`) или PowerShell выполните: ```cmd ssh-keygen -t ed25519 -f "D:\sys\C-Sharp\deployfile\key\test_key.key" -N "" ``` Будут созданы: * `test_key.key` — приватный ключ (хранится строго на рабочей станции). * `test_key.key.pub` — открытый ключ. ### 3.2. Экспорт открытого ключа на сервер Выполните команду передачи публичного ключа (потребуется однократный ввод пароля `depfile`): ```powershell type "D:\sys\C-Sharp\deployfile\key\test_key.key.pub" | ssh depfile@10.228.48.110 "cat >> /var/lib/depfile/.ssh/authorized_keys" ``` Проверьте вход по ключу: ```cmd ssh -i "D:\sys\C-Sharp\deployfile\key\test_key.key" depfile@10.228.48.110 "whoami && pwd" ``` Ожидаемый ответ: ```text depfile /var/lib/depfile ``` --- ## 4. Настройка безопасности и разграничения прав ### 4.1. Безопасность приватного ключа на рабочей станции (Windows NTFS) Встроенный клиент Windows OpenSSH (`ssh.exe`) проверяет списки управления доступом (ACL) NTFS. Если к файлу ключа или каталогу имеют доступ сторонние группы (`Users`, `Everyone`), SSH прерывает выполнение с ошибкой `Permissions for '...' are too open`. Выполните команду ограничения прав доступа в командной строке: ```cmd :: 1. Отключаем наследование разрешений родительской папки для файла ключа icacls "D:\sys\C-Sharp\deployfile\key\test_key.key" /inheritance:r :: 2. Выдаем полный доступ только текущему пользователю и учетной записи SYSTEM icacls "D:\sys\C-Sharp\deployfile\key\test_key.key" /grant:r "%USERNAME%:F" icacls "D:\sys\C-Sharp\deployfile\key\test_key.key" /grant:r "SYSTEM:F" ``` *Для защиты всей папки `key`:* ```cmd icacls "D:\sys\C-Sharp\deployfile\key" /inheritance:r icacls "D:\sys\C-Sharp\deployfile\key" /grant:r "%USERNAME%:(OI)(CI)F" icacls "D:\sys\C-Sharp\deployfile\key" /grant:r "SYSTEM:(OI)(CI)F" ``` ### 4.2. Безопасность на стороне Linux-сервера 1. **Разграничение прав на конфигурации:** * Права `700` на `/var/lib/depfile/.ssh` и `600` на `authorized_keys` исключают несанкционированное чтение или подмену ключей. * Директория `/etc/haproxy/backup` принадлежит `root:root` с правами `750`. Пользователь `depfile` **не имеет прав на запись и редактирование** в каталоге `/etc/haproxy/`, что делает невозможной прямую подмену боевого конфига или бэкапа из-под учетной записи развертывания. 2. **Ограничение SSH-сессии ключа:** * В `/var/lib/depfile/.ssh/authorized_keys` перед публичным ключом рекомендуется добавить флаги запрета интерактивного окружения: ```text no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3NzaC... ``` 3. **Изоляция привилегий исполнения:** * Пользователь `depfile` является бесправной учетной записью без доступа к `sudo`. * Замену файлов конфигурации и перезапуск службы осуществляет служба `systemd` от имени `root` исключительно после успешной валидации контрольной суммы SHA-256 и проверки синтаксиса `haproxy -c`. --- ## 5. Клиентское приложение C# (.NET Framework 4.8) ### 5.1. Исходный код * Исходный файл приложения: [`Program.cs`](Program.cs) Утилита автономна, не требует сторонних NuGet-библиотек, работает со штатным `ssh.exe` Windows 10/11 и производит автоматическую установку OpenSSH Client через PowerShell при первом обнаружении его отсутствия. ### 5.2. Сборка и создание ярлыка на рабочем столе 1. В Visual Studio в свойствах проекта (**Build** / **Сборка**) установите платформу **x64** (или снимите флаг *Prefer 32-bit*). 2. Скомпилируйте проект в конфигурации **Release** (`D:\sys\C-Sharp\deployfile\bin\Release\deployfile.exe`). 3. Создайте ярлык на рабочем столе: * **Объект:** `"D:\sys\C-Sharp\deployfile\bin\Release\deployfile.exe"` * **Название:** `Откатить конфигурацию HAProxy`. --- ## 6. Проверка работы комплекса 1. Нажмите на ярлык на рабочем столе Windows. 2. В консоли отобразится успешный статус: ```text Используется ключ: D:\sys\C-Sharp\deployfile\key\test_key.key Подключение к depfile@10.228.48.110:22... Файл status/change.me и хеш status/sha256.hash успешно созданы на сервере. ``` 3. Проверьте журнал выполнения сервиса на сервере (запуск происходит моментально по факту закрытия файла): ```bash sudo journalctl -u depfile-watcher.service -n 25 --no-pager ``` 4. Убедитесь в результатах развертывания: * Каталог `/var/lib/depfile/status` удален. * Конфигурация `/etc/haproxy/haproxy.cfg` обновлена из бэкапа. * Служба активна: `systemctl status haproxy`. * Метка времени зафиксирована в `/var/lib/depfile/deployment/success.me`: ```bash cat /var/lib/depfile/deployment/success.me ```