Static completion rules for all pkica commands, options and option values, plus unit, interactive (tmux) and --help reconciliation tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
751 lines
22 KiB
Markdown
751 lines
22 KiB
Markdown
# Скрипты управления лицензиями и службами 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.<PID>
|
||
```
|
||
|
||
Сначала формируется новая версия файла, после чего она заменяет исходный.
|
||
|
||
Это позволяет не изменять исходный файл непосредственно во время обработки.
|
||
|
||
---
|
||
|
||
# 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-файлах.
|
||
|
||
---
|
||
|
||
# 27. Автодополнение bash для `pkica`
|
||
|
||
В каталоге [`bash-completion`](bash-completion/README.md) находятся правила автодополнения (TAB) в bash для утилиты `pkica` КриптоПро УЦ и тесты к ним.
|