Files
a.gritsenkoandClaude Opus 5.5 11283c573a Add bash completion for pkica
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>
2026-09-28 23:22:43 +03:00

751 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Скрипты управления лицензиями и службами 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` КриптоПро УЦ и тесты к ним.