# Скрипты управления лицензиями и службами CryptoPro ## 1. Назначение Набор Bash-скриптов предназначен для централизованного выполнения операций на удалённых Linux/Astra Linux-серверах: * установки лицензий CryptoPro CSP; * изменения параметров лицензии в JSON-конфигурациях приложений; * перезапуска служб после изменения лицензии; * проверки успешности выполненных операций; * создания резервных копий изменяемых конфигурационных файлов; * ведения локального журнала выполнения. Работа выполняется по SSH под указанной учётной записью. Для выполнения административных операций используется `sudo`. Пароли не хранятся в конфигурационных файлах, не передаются в параметрах командной строки и не записываются в журнал. --- # 2. Формат конфигурационного файла Основной конфигурационный файл использует формат: ```text host;file;company;serial_number ``` Пример: ```text # host;file;company;serial_number 10.11.1.11;csp;;50500-03010-03MCZ-921DC-HGLK4 10.11.1.12;/etc/cprocsp/app/appsettings.json;ООО Ромашка;50500-03010-03MCZ-921DC-HGLK5 ``` Поля: | Поле | Описание | | --------------- | ------------------------------------------------- | | `host` | IP-адрес или DNS-имя удалённого сервера | | `file` | Специальное значение `csp` либо путь к JSON-файлу | | `company` | Наименование организации для JSON-конфигурации | | `serial_number` | Серийный номер лицензии | Разделителем является символ `;`. Для строк с JSON-файлом поле `company` обязательно; для `csp` оно игнорируется. Файл может быть с окончаниями строк CRLF (Windows) и BOM. Компания может содержать пробелы: ```text 10.11.1.12;/etc/app/appsettings.json;ООО Тестовая Организация;50500-03010-03MCZ-921DC-HGLK5 ``` Символ `;` внутри значения компании использовать нельзя, поскольку он является разделителем полей. --- # 3. Комментарии и пустые строки В конфигурационном файле разрешены пустые строки. Также разрешены комментарии, начинающиеся с `#`: ```text # Серверы УЦ 10.11.1.11;csp;;50500-03010-03MCZ-921DC-HGLK4 ### Сервер приложений 10.11.1.12;/etc/app/appsettings.json;ООО Ромашка;50500-03010-03MCZ-HGLK5 ``` Комментарии и пустые строки не обрабатываются. --- # 4. Скрипт `license_update.sh` ## 4.1. Назначение `license_update.sh` выполняет установку или изменение лицензии на удалённых серверах. Запуск: ```bash ./license_update.sh -u administrator -c ./licenses_local_test.csv ``` где: * `-u` — SSH-пользователь; * `-c` — путь к конфигурационному файлу. Например: ```bash ./license_update.sh \ -u administrator \ -c ./licenses_local_test.csv ``` --- # 5. Подключение к серверу Для каждого сервера скрипт устанавливает SSH-соединение: ```text administrator@10.11.1.11's password: ``` Пароль SSH вводится интерактивно. Пароль не передаётся в командной строке: ```text НЕ используется: sshpass -p password ``` и не записывается в лог. --- # 6. Авторизация sudo После успешного подключения сформированный скрипт операций передаётся на сервер (в командной строке ssh, в кодировке base64, без использования stdin) и запускается: ```bash sudo bash /tmp/tmp.XXXXXX ``` Пароль `sudo` запрашивается непосредственно на удалённом сервере, один раз на хост: ```text [sudo] password for administrator: ``` Для этого SSH-соединение создаётся с TTY (`ssh -tt`), а локальный stdin остаётся терминалом и используется только для ввода паролей SSH и `sudo`. После успешной авторизации выполняются все административные операции текущего сеанса. При первом подключении к серверу ssh стандартно спросит подтверждение ключа хоста (`Are you sure you want to continue connecting (yes/no)?`). Пароль `sudo`: * не передаётся через stdin; * не хранится в переменной Bash; * не записывается в лог; * не находится в конфигурационном файле. --- # 7. Обработка `file=csp` Если в конфигурации указано: ```text 10.11.1.11;csp;;50500-03010-03MCZ-921DC-HGLK4 ``` скрипт не изменяет JSON-файлы. Выполняется: ```bash /opt/cprocsp/sbin/amd64/cpconfig \ -license \ -set "50500-03010-03MCZ-921DC-HGLK4" ``` Команда выполняется с правами `sudo`. При успешной установке лицензии выполняется перезапуск службы: ```bash systemctl restart cprocsp ``` После перезапуска проверяется состояние службы: ```bash systemctl is-active --quiet cprocsp ``` Ожидаемый результат: ```text cprocsp is active ``` Если служба не перешла в состояние `active`, в журнал дополнительно выводится: ```bash systemctl status cprocsp --no-pager --full ``` Операция считается ошибочной. --- # 8. Обработка JSON-файлов Если вместо `csp` указан путь к JSON: ```text 10.11.1.12;/etc/app/appsettings.json;ООО Ромашка;50500-03010-03MCZ-HGLK5 ``` скрипт выполняет следующие операции. ## 8.1. Проверка файла Проверяется существование файла: ```bash test -f "$FILE" ``` Если файл отсутствует, операция завершается ошибкой. --- ## 8.2. Сохранение атрибутов До изменения файла сохраняются: * UID владельца; * GID владельца; * права доступа. Например: ```text Owner: 1000:1000 Mode : 640 ``` --- ## 8.3. Создание резервной копии Перед изменением создаётся backup: ```text /etc/app/appsettings.json.license_backup_20260918_123456_12345 ``` Резервная копия создаётся с сохранением исходных атрибутов: ```bash cp -p ``` Путь к backup записывается в журнал. --- # 9. Изменение JSON Скрипт изменяет только два параметра внутри объекта: ```json "License": { "SerialNumber": "...", "Company": "..." } ``` Изменяются: ```text License.SerialNumber License.Company ``` Например, было: ```json "License": { "SerialNumber": "OLD-LICENSE", "Company": "Старая организация" } ``` становится: ```json "License": { "SerialNumber": "50500-03010-03MCZ-921DC-HGLK5", "Company": "ООО Ромашка" } ``` Остальные параметры JSON не должны изменяться скриптом. --- # 10. Временный файл Изменение выполняется через временный файл: ```text appsettings.json.tmp. ``` Сначала формируется новая версия файла, после чего она заменяет исходный. Это позволяет не изменять исходный файл непосредственно во время обработки. --- # 11. Восстановление атрибутов После замены файла восстанавливаются исходные: ```text owner permissions ``` Используются: ```bash chown chmod ``` Таким образом, изменение содержимого файла не должно приводить к изменению его владельца или прав доступа. --- # 12. Проверка результата После изменения выполняется повторная проверка параметров: ```text License.SerialNumber License.Company ``` Проверяется наличие установленных значений. Если проверка не пройдена, операция считается ошибочной. При ошибке изменения JSON скрипт пытается восстановить исходный файл из backup. Итог по каждой операции выводится строкой: ```text [REMOTE] OP_RESULT OK /opt/app/appsettings.json [REMOTE] OP_RESULT FAIL csp ``` По этим строкам формируется итоговая статистика (успешно / ошибок). --- # 13. Обработка нескольких записей одного сервера Если один сервер встречается в конфигурации несколько раз: ```text 10.11.1.11;csp;;LICENSE-001 10.11.1.11;/etc/app/appsettings.json;ООО Ромашка;LICENSE-002 ``` операции группируются по хосту. Для одного хоста используется один SSH-сеанс. После подключения выполняется авторизация `sudo`, затем последовательно обрабатываются все операции этого сервера. Это позволяет не выполнять повторное подключение для каждой строки конфигурации. --- # 14. Журнал работы Основной журнал: ```text license_update.log ``` Пример: ```text [2026-09-18 09:23:08] [INFO] Запуск license_update.sh [2026-09-18 09:23:08] [INFO] SSH user: administrator [2026-09-18 09:23:08] [INFO] Config: ./licenses_local_test.csv [2026-09-18 09:23:08] [INFO] Host: 10.11.1.11 ``` В журнале фиксируются: * начало выполнения; * используемый SSH-пользователь; * конфигурационный файл; * обрабатываемые серверы; * результаты операций; * ошибки; * путь к backup; * итоговая статистика. Пароли в журнал не записываются. --- # 15. Итоговая статистика В конце выполнения выводится: ```text ============================================== Результат выполнения Всего операций : 10 Успешно : 9 Ошибок : 1 Log : ./license_update.log ============================================== ``` Если хотя бы одна операция завершилась ошибкой, скрипт возвращает код: ```text 1 ``` При полном успешном выполнении: ```text 0 ``` Это позволяет использовать скрипт в других Bash-скриптах или системах автоматизации. --- # 16. Скрипт `restart_services.sh` `restart_services.sh` предназначен для централизованного перезапуска служб на серверах. Формат конфигурации: ```text host;services ``` Пример: ```text # host;services ip_ca_tech;cp.ca-tech ip_ca_tls;cp.ca-tls ip_ca_digrub;cp.ca-digrub ip_ra_tech;cp.ra-tech,cp.ra-web-tech ip_ra_tls;cp.ra-tls,cp.ra-web-tls,cp.cr-tls,cp.cr-web.tls ip_ra_digrub;cp.ra-digrub,cp.ra-web-digrub,cp.cr-digrub,cp.cr-web.digrub ``` --- # 17. Запуск `restart_services.sh` Пример: ```bash ./restart_services.sh \ -u administrator \ -c ./services.csv ``` Подключение и авторизация `sudo` выполняются так же, как в `license_update.sh` (см. разделы 5 и 6): пароль SSH спрашивает ssh, пароль `sudo` запрашивается на удалённом сервере через TTY, один раз на хост. Пароль в переменных скрипта не хранится. Затем службы перезапускаются последовательно. --- # 18. Перезапуск службы Для каждой службы выполняется: ```bash systemctl restart SERVICE ``` Например: ```bash systemctl restart cp.ca-tech ``` После перезапуска выполняется небольшая пауза и проверяется состояние: ```bash systemctl is-active --quiet cp.ca-tech ``` Если служба успешно запущена: ```text cp.ca-tech is active ``` Если запуск не удался, выводится подробная информация: ```bash systemctl status cp.ca-tech --no-pager --full ``` --- # 19. Несколько служб на одном сервере Службы разделяются запятыми: ```text ip_ra_tech;cp.ra-tech,cp.ra-web-tech ``` Скрипт преобразует эту запись в две операции: ```bash systemctl restart cp.ra-tech systemctl restart cp.ra-web-tech ``` Службы перезапускаются последовательно. --- # 20. Журнал `restart_services.sh` Для отдельного скрипта используется собственный журнал: ```text restart_services.log ``` В журнале фиксируются: * сервер; * служба; * результат `systemctl restart`; * состояние службы после перезапуска; * диагностический вывод при ошибке; * итоговая статистика. --- # 21. Общая схема работы Общая последовательность для удалённого сервера: ```text ┌──────────────────────┐ │ Конфигурационный │ │ файл │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Группировка по host │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ SSH connection │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ sudo -v │ │ интерактивный пароль │ └──────────┬───────────┘ │ ┌─────────┴─────────┐ │ │ ▼ ▼ file = csp JSON-файл │ │ ▼ ▼ cpconfig -license backup │ │ ▼ ▼ restart cprocsp изменение │ │ ▼ ▼ проверка active проверка │ ▼ восстановление owner/mode │ ┌───────────────────┘ ▼ Результат │ ▼ Локальный log ``` --- # 22. Требования Для работы скриптов необходимы: ### На управляющей машине * Bash; * OpenSSH client; * стандартные Unix-утилиты (coreutils): * `base64`; * `grep`; * `sed`; * `mktemp`; * `date`; * `tee`. ### На удалённых серверах * SSH-сервер; * `sudo`; * `systemd`; * `bash`, `awk` (gawk или mawk), `base64`, `mktemp`; * для установки CSP-лицензии: `/opt/cprocsp/sbin/amd64/cpconfig`; * для JSON-конфигураций: доступ к указанному файлу. Пользователь SSH должен иметь возможность выполнять соответствующие команды через `sudo`. --- # 23. Безопасность Скрипты не должны содержать пароли в конфигурации. Не рекомендуется использовать: ```bash ./license_update.sh -u administrator -p password ``` Пароль SSH вводится стандартным механизмом OpenSSH. Пароль `sudo` вводится стандартным механизмом `sudo`. Пароли не должны попадать: * в командную строку; * в конфигурационные файлы; * в переменные скрипта; * в `license_update.log`; * в `restart_services.log`. --- # 24. Рекомендации по эксплуатации Перед массовым запуском рекомендуется: 1. Проверить подключение по SSH: ```bash ssh administrator@10.11.1.11 ``` 2. Проверить возможность выполнения `sudo`: ```bash ssh -tt administrator@10.11.1.11 'sudo -v' ``` 3. Проверить наличие CryptoPro: ```bash ssh -tt administrator@10.11.1.11 \ 'sudo /opt/cprocsp/sbin/amd64/cpconfig -license -view' ``` 4. Проверить конфигурационный файл. 5. Сначала выполнить скрипт на одном тестовом сервере. 6. Проверить backup и журнал. 7. После успешной проверки выполнить обработку остальных серверов. --- # 25. Коды завершения | Код | Значение | | --: | ----------------------------------------------- | | `0` | Все операции выполнены успешно | | `1` | Одна или несколько операций завершились ошибкой | Пример использования в другом скрипте: ```bash ./license_update.sh -u administrator -c licenses.csv if [[ $? -eq 0 ]]; then echo "Лицензии успешно обновлены" else echo "При обновлении лицензий произошли ошибки" fi ``` --- # 26. Результат В результате работы: * лицензии CryptoPro CSP устанавливаются централизованно; * JSON-конфигурации изменяются только в части параметров `License.SerialNumber` и `License.Company`; * перед изменением JSON создаётся резервная копия; * исходные права и владелец файла сохраняются; * службы после необходимых изменений проверяются; * операции выполняются с административными правами через `sudo`; * пароли не сохраняются и не попадают в журналы; * все результаты доступны в локальных log-файлах.