Monolit / Архив 1.3.2
Руководство администратора
Установка в Docker Compose и Kubernetes, пользователи, REST API, CI/CD, резервное копирование, мониторинг.
Monolit
Это документация Monolit 1.3.2. Актуальная версия — 1.3.4.
Открыть актуальнуюАрхивная версия · Monolit v1.3.2
Это снимок документации на момент релиза 1.3.2. Описанное здесь поведение может отличаться от текущей версии продукта.
Актуальная документация
Введение
Monolit — программная платформа для организации процесса безопасной разработки на стороне заказчика. Она объединяет шесть типов анализа — статический анализ кода (SAST), анализ зависимостей (SCA), поиск секретов (Secret), проверку конфигураций (Config), правила кодирования (Linters) и динамический анализ (DAST), предоставляет веб-интерфейс для управления результатами сканирования, приложениями и уязвимостями, а также помогает формализовать выполнение требований ГОСТ Р 56939-2024.
Инструкция по установке
Требования к системе
Минимальные и рекомендуемые системные требования:
- Операционная система: Linux (Ubuntu 24.04.1 LTS или выше)
- Процессор: 4 ядра
- Оперативная память: 8 ГБ
- Свободное место: 50 ГБ
- Сетевое подключение: Требуется для установки и получения обновлений
Установка в Docker (Docker Compose)
Установку и обновление выполняет один скрипт install.sh. Запустите его из каталога, в котором должна появиться установка, — скрипт создаст в нём подкаталог sdlplatform/:
curl -fsSL -o install.sh https://sdlplatform.ru/sdlplatform/install.sh && sudo bash install.sh
Скрипт открывает меню продуктов: Monolit и Triage LLM (сервис AI-триажа уязвимостей). Номера вводятся через пробел, если нужны оба. По умолчанию выбран Monolit.
Дальше скрипт различает установку и обновление по файлу sdlplatform/.env: если файла нет — ставит платформу, если есть — обновляет (см. раздел Обновление Monolit).
При установке скрипт:
- Проверяет Docker и Docker Compose. Если Docker не найден — предлагает установить его с
get.docker.com. - Запрашивает адрес registry (по умолчанию
registry.sdlplatform.ru) и выполняетdocker login. - Запрашивает параметры установки:
- Версия (TAG) — обязательное поле, например
1.3.2; - PORT — порт, на котором платформа будет доступна снаружи (по умолчанию 80);
- Пользователь и база PostgreSQL — по умолчанию
monolit; - Пользователь MinIO — по умолчанию
monolit; - Email-уведомления — при согласии запрашивает
SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASSWORD,SMTP_FROM_EMAIL,SMTP_FROM_NAME,SMTP_CONNECTION_TYPE(по умолчаниюSTARTTLS); - Интеграции —
APPSCREENER_URLиAPPSCREENER_TOKEN,PTAI_URLиPTAI_TOKEN. Пустой ввод пропускает интеграцию.
- Версия (TAG) — обязательное поле, например
- Скачивает
docker-compose.ymlверсии TAG сhttps://sdlplatform.ru/sdlplatform/<TAG>/. Если версионного файла нет, берёт последний опубликованный и предупреждает об этом. Если не доступен ни один — установка прерывается, каталог не создаётся. - Генерирует
SECRET_KEY, пароль PostgreSQL и пароль MinIO и записывает конфигурацию вsdlplatform/.env. Прежний.env, если он был, сохраняется как.env.bak.<метка времени>. - Загружает образы (
docker compose pull) и запускает платформу (docker compose up -d). При ошибке загрузки предлагает повторную авторизацию в registry.
Копия install.sh сохраняется в sdlplatform/ — обновление запускается уже оттуда.
При установке номер версии не проверяется: опечатка в TAG не остановит скрипт. Он возьмёт последний опубликованный
docker-compose.yml, запишет ошибочный TAG в.envи упрётся только в загрузку образов — такого тега в registry нет. Сверяйте версию с поставщиком до запуска. При обновлении версия проверяется заранее, до трёх попыток ввода.Скрипт вызывает
dockerчерезsudo. Учётная запись, от имени которой он выполняется, должна иметь право повышения привилегий.
Платформа включает следующие сервисы:
postgres— база данных PostgreSQLminio— S3-совместимое объектное хранилище (бакеты: PDF-отчёты, свидетельства и шаблоны документов соответствияcompliance-evidence)nats— брокер сообщений для асинхронной коммуникацииredis— кеш и хранилище временных данныхmigrate— разовое применение миграций БД перед стартом бэкендаbackend— FastAPI-приложение с REST APIfrontend— веб-интерфейсnginx— обратный прокси-серверml_triage_producer,ml_triage_analyzer,ml_triage_writer,ml_triage_janitor— конвейер AI-триажа уязвимостей (постановка задач, вызов AI-сервиса, запись результата, обслуживание очереди)worker_ml_extractor— извлечение фрагмента кода вокруг места срабатывания для передачи в AI-сервисbutler_service— сервис управления задачами сканированияpdf_generation_outbox— обработка очереди заданий на формирование PDF-отчётовpdf_generator— сервис генерации PDF-отчётовfile_cleaner— удаление устаревших загруженных файловlicense_notifier— рассылка уведомлений об истечении лицензииworker_*— воркеры сканеров, 19 сервисов (semgrep, bandit, gosec, codeql, trivy и другие)
Обновление Monolit
Обновление выполняет тот же install.sh. Запускать его нужно из того же каталога, что и установку — из родительского по отношению к sdlplatform/:
cd /путь/где/лежит/sdlplatform
sudo bash sdlplatform/install.sh
Путь к установке в скрипте задан относительно текущего каталога. Если запустить скрипт изнутри
sdlplatform/, он не найдётsdlplatform/.env, сочтёт установку новой и развернёт вторую копию платформы во вложенный каталогsdlplatform/sdlplatform/.
Скрипт находит sdlplatform/.env, показывает установленную версию и запрашивает новую. Пустой ввод оставляет текущую версию и просто перекачивает файлы поставки.
Что происходит дальше:
- Скрипт проверяет, опубликован ли
docker-compose.ymlзапрошенной версии. Ненайденную версию можно ввести заново, всего до трёх попыток; после третьей обновление отменяется. .envкопируется в.env.bak.<метка времени>, в нём меняется толькоTAG. Остальные параметры (порт, учётные записи, секреты, SMTP, интеграции) сохраняются.- Прежний
docker-compose.ymlкопируется вdocker-compose.yml.bak, затем скачивается файл новой версии. Если скачать не удалось, скрипт возвращает прежний файл. - Загружаются образы новой версии и перезапускаются контейнеры (
docker compose pull,docker compose up -d). - Неиспользуемые образы удаляются (
docker image prune -af), чтобы диск не заполнялся прежними версиями.
Миграции базы данных применяет отдельный сервис migrate: он отрабатывает до старта бэкенда, который дожидается его успешного завершения. Отдельной команды не требуется.
Если после обновления платформа отвечает 502 Bad Gateway, перезапустите nginx:
cd sdlplatform && sudo docker compose restart nginx
Откат на прежнюю версию: верните TAG в .env из резервной копии, восстановите docker-compose.yml.bak и выполните docker compose up -d.
Перед обновлением снимите резервную копию базы данных (см. раздел Резервное копирование базы данных). Миграции необратимы.
Установка в Kubernetes
Helm chart и образы размещены в Harbor registry.sdlplatform.ru.
Требования:
- Kubernetes кластер
kubectl- Helm 3 с поддержкой OCI (Helm 3.8+)
- Ingress controller: NGINX
- Storage: используется default StorageClass кластера
- Доступ к
registry.sdlplatform.ru(учётные данные robot account с правами pull в projectsdlplatform)
Подготовка доступа к registry
Для скачивания образов и chart используйте учётные данные robot account, которые вам предоставил поставщик:
<name>— имя robot account (часть послеrobot$sdlplatform+, напримерpull-client)<ROBOT_PASSWORD>— токен robot account, выданный при создании учётной записи
- Выполните логин в registry (для Helm OCI):
helm registry login registry.sdlplatform.ru -u 'robot$sdlplatform+<name>' -p '<ROBOT_PASSWORD>'
Если токен содержит спецсимволы:
printf '%s' '<ROBOT_PASSWORD>' | helm registry login registry.sdlplatform.ru -u 'robot$sdlplatform+<name>' --password-stdin
- Создайте
imagePullSecret(чтобы kubelet мог загружать образы):
kubectl create namespace sdlplatform || true
kubectl -n sdlplatform create secret docker-registry registry-secret \
--docker-server=registry.sdlplatform.ru \
--docker-username='robot$sdlplatform+<name>' \
--docker-password='<ROBOT_PASSWORD>'
- Если в кластере возникает ошибка
429 Too Many Requestsиз-за ограничений DockerHub, добавьте учётные данные DockerHub отдельным secret:
<DOCKERHUB_USER>— логин на hub.docker.com<DOCKERHUB_TOKEN_OR_PASSWORD>— access token или пароль от Docker Hub
kubectl -n sdlplatform create secret docker-registry dockerhub-secret \
--docker-server=docker.io \
--docker-username='<DOCKERHUB_USER>' \
--docker-password='<DOCKERHUB_TOKEN_OR_PASSWORD>'
Установка релиза
Релизная версия соответствует git-тегу, например 1.2.0. Установка и все последующие обновления выполняются через файл values-prod.yaml.
Подготовьте values-prod.yaml:
cat > values-prod.yaml <<'YAML'
global:
imageRegistry: registry.sdlplatform.ru/sdlplatform/
imageTag: "1.2.0"
imagePullSecrets:
- registry-secret
- dockerhub-secret
ingress:
host: sdlplatform.example.com
config:
data:
NOTIFICATIONS_ENABLED: "false"
SMTP_HOST: ""
SMTP_PORT: ""
SMTP_USER: ""
SMTP_CONNECTION_TYPE: ""
APPSCREENER_URL: ""
PTAI_URL: ""
CODESCORING_URL: ""
PORT: "8000"
secrets:
stringData:
SMTP_PASSWORD: ""
APPSCREENER_TOKEN: ""
PTAI_TOKEN: ""
CODESCORING_TOKEN: ""
YAML
Запустите установку через helm:
helm upgrade --install sdlplatform oci://registry.sdlplatform.ru/sdlplatform/sdlplatform \
--version 1.2.0 \
--namespace sdlplatform \
--create-namespace \
-f values-prod.yaml
Во время установки/обновления backend автоматически применяет миграции БД (Alembic) через initContainer. Первый запуск может занять 1–2 минуты.
Переменные окружения
Backend получает переменные из ConfigMap sdlplatform-config и Secret sdlplatform-secrets.
В ConfigMap задайте:
NOTIFICATIONS_ENABLED(true/false)SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_CONNECTION_TYPE(tls/ssl)APPSCREENER_URL,PTAI_URL,CODESCORING_URL(опционально)PORT— порт бэкенда внутри кластера,8000. Совпадает сcontainerPortи портом сервисаbackend-service; менять его без правки chart нельзя. Порт, по которому платформа доступна снаружи, задаётся вingress.hostи сервисе nginx.
В Secrets задайте:
SMTP_PASSWORDAPPSCREENER_TOKEN,PTAI_TOKEN,CODESCORING_TOKEN(опционально)
ConfigMap и Secret создаются chart'ом. Для изменения настроек отредактируйте values-prod.yaml и выполните helm upgrade с этим файлом.
Обновление релиза
Укажите версию:
RELEASE_VERSION=1.3.1
sed -i -E 's/^( imageTag: ).*$/\1"'"$RELEASE_VERSION"'"/' values-prod.yaml
Выполните обновление:
helm upgrade --install sdlplatform oci://registry.sdlplatform.ru/sdlplatform/sdlplatform \
--version "$RELEASE_VERSION" \
--namespace sdlplatform \
-f values-prod.yaml
Удаление
helm uninstall sdlplatform -n sdlplatform
Управление пользователями
Учётные данные по умолчанию
После первого запуска в базе данных создаётся тестовая учётная запись суперпользователя:
| Поле | Значение |
|---|---|
demo@example.com | |
| Пароль | demo |
Используйте эти данные для первоначального входа и проверки работоспособности платформы. После настройки окружения замените тестовую учётную запись на рабочую или создайте новых пользователей.
Управление через веб-интерфейс
Рекомендуемый способ управления пользователями — раздел «Пользователи» в веб-интерфейсе платформы. Доступен Администратору и Суперадминистратору.
Позволяет:
- создавать учётные записи и задавать тип (
regular,admin,super_admin) - редактировать данные (имя, тип учётной записи)
- блокировать и разблокировать пользователей
- выполнять массовые операции (смена типа, блокировка группы)
Подробное описание операций — в Руководстве пользователя, раздел «Управление пользователями».
Управление через API
Для автоматизации (скрипты onboarding, CI/CD) управление пользователями доступно через REST API. Требуется токен Суперадминистратора. Доступны операции: создание, редактирование, массовая блокировка, смена типа и сброс типа до regular.
Примеры запросов приведены в разделе «Пользователи» → REST API.
Аварийные операции через БД
Внимание. Операции через БД предназначены только для аварийных ситуаций: утери доступа суперадминистратора, недоступности бэкенда или миграции данных. В штатной работе используйте веб-интерфейс или API.
Создание пользователя
Для добавления пользователя напрямую в базу данных PostgreSQL выполните следующие шаги:
- Сгенерируйте bcrypt-хеш пароля:
docker compose exec backend python -c "from passlib.context import CryptContext; pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto'); print(pwd_context.hash('ВАШ_ПАРОЛЬ'))"
Хеш должен быть длиной ~60 символов и начинаться с $2b$12$. Пример: $2b$12$yPhCZhH.wtAFPri2o2xJPOGulZ8U0WXPmKWzVWmebc1xzBbBE7RQm
- Добавьте пользователя в БД:
# Экранируйте символы $ в хеше: замените $ на \$
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
INSERT INTO \"user\" (email, hashed_password, is_active, type, full_name)
VALUES ('user@example.com', '\$2b\$12\$ОСТАЛЬНАЯ_ЧАСТЬ_ХЕША', true, 'regular', 'Полное Имя');
"
Важно.
- Символы
$в хеше нужно экранировать обратными слешами:\$ - Bcrypt-хеш
$2b$12$abc...должен превратиться в\$2b\$12\$abc... - Без экранирования bash интерпретирует
$как переменные, и хеш будет неполным
Для создания суперадминистратора установите type в super_admin:
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
INSERT INTO \"user\" (email, hashed_password, is_active, type, full_name)
VALUES ('admin@example.com', '\$2b\$12\$ОСТАЛЬНАЯ_ЧАСТЬ_ХЕША', true, 'super_admin', 'Администратор');
"
Полный пример:
# 1. Генерируем хеш
docker compose exec backend python -c "from passlib.context import CryptContext; pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto'); print(pwd_context.hash('mypassword123'))"
# Получаем: $2b$12$sze/sfRE5RiG8KEFh42.QOwT8hgyipXVsBqt8qb3paWuDxwJpA4gu
# 2. Вставляем с экранированием $ → \$
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
INSERT INTO \"user\" (email, hashed_password, is_active, type, full_name)
VALUES ('newuser@example.com', '\$2b\$12\$sze/sfRE5RiG8KEFh42.QOwT8hgyipXVsBqt8qb3paWuDxwJpA4gu', true, 'regular', 'New User');
"
Структура таблицы user:
id— автоинкрементный первичный ключemail— уникальный email пользователяhashed_password— bcrypt-хеш пароляis_active— флаг активности (true/false)type— тип пользователя:super_admin,admin,regular(по умолчаниюregular)full_name— полное имя пользователя (опционально)created_at— дата и время создания
Просмотр пользователей
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "SELECT id, email, is_active, type, full_name, created_at FROM \"user\";"
Удаление пользователя
Перед удалением пользователя необходимо проверить, есть ли у него связанные данные (приложения, комментарии и т.д.).
Проверка связанных приложений:
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
SELECT id, name, owner_id FROM application WHERE owner_id = (SELECT id FROM \"user\" WHERE email='user@example.com');
"
Вариант 1: Удаление со всеми связанными данными
Удаляет пользователя вместе со всеми его приложениями и сканами (используйте с осторожностью!):
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
BEGIN;
-- Удаляем приложения пользователя (каскадно удалятся все связанные сканы)
DELETE FROM application WHERE owner_id = (SELECT id FROM \"user\" WHERE email='user@example.com');
-- Удаляем комментарии пользователя
DELETE FROM comments WHERE user_id = (SELECT id FROM \"user\" WHERE email='user@example.com');
-- Удаляем пользователя
DELETE FROM \"user\" WHERE email='user@example.com';
COMMIT;
"
Вариант 2: Переназначение приложений другому пользователю
Передаёт все приложения пользователя другому владельцу перед удалением:
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
BEGIN;
-- Переназначаем приложения на другого пользователя
UPDATE application
SET owner_id = (SELECT id FROM \"user\" WHERE email='new_owner@example.com')
WHERE owner_id = (SELECT id FROM \"user\" WHERE email='user@example.com');
-- Удаляем комментарии пользователя
DELETE FROM comments WHERE user_id = (SELECT id FROM \"user\" WHERE email='user@example.com');
-- Удаляем пользователя
DELETE FROM \"user\" WHERE email='user@example.com';
COMMIT;
"
Вариант 3: Деактивация пользователя (рекомендуется)
Вместо удаления можно деактивировать пользователя, сохранив историю:
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
UPDATE \"user\" SET is_active = false WHERE email='user@example.com';
"
Исправление пароля пользователя
Если при входе возникает ошибка hash could not be identified, значит пароль был сохранён неправильно (не как bcrypt-хеш).
Исправление пароля:
# 1. Сгенерируйте новый хеш
docker compose exec backend python -c "from passlib.context import CryptContext; pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto'); print(pwd_context.hash('НОВЫЙ_ПАРОЛЬ'))"
# 2. Обновите пароль в БД (не забудьте экранировать $ → \$)
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
UPDATE \"user\" SET hashed_password = '\$2b\$12\$ОСТАЛЬНАЯ_ЧАСТЬ_ХЕША' WHERE email='user@example.com';
"
Проверка правильности хешей всех пользователей:
docker compose exec postgres psql -U sdlplatform -d sdlplatform -c "
SELECT id, email, length(hashed_password) as hash_length, substring(hashed_password, 1, 7) as hash_start
FROM \"user\";
"
Правильный bcrypt-хеш должен иметь длину 60 символов и начинаться с $2b$12$.
REST API: примеры запросов
Все запросы к API требуют JWT-токена. Задайте переменные окружения один раз и используйте их во всех командах ниже:
BASE_URL="https://<ваш-хост>"
# Получить токен (username — email пользователя)
TOKEN=$(curl -s -X POST "$BASE_URL/api/v1/login/access-token" \
-d "username=demo@example.com&password=demo" | jq -r .access_token)
Healthcheck
# Проверить состояние сервиса
curl -s "$BASE_URL/api/v1/healthcheck"
Пользователи
# Текущий пользователь
curl -s "$BASE_URL/api/v1/users/me" \
-H "Authorization: Bearer $TOKEN"
# Список всех пользователей (только администраторы)
curl -s "$BASE_URL/api/v1/users" \
-H "Authorization: Bearer $TOKEN"
# Создать пользователя (только суперадминистратор)
curl -s -X POST "$BASE_URL/api/v1/users" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "newuser@example.com",
"password": "securepassword",
"full_name": "Иван Иванов",
"type": "regular"
}'
# type: "regular" | "admin" | "super_admin"
# Редактировать пользователя (только суперадминистратор)
curl -s -X PATCH "$BASE_URL/api/v1/users/<USER_ID>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"full_name": "Новое Имя", "type": "admin"}'
# Массово заблокировать пользователей (только суперадминистратор)
curl -s -X POST "$BASE_URL/api/v1/users/bulk/is-active" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": [2, 3], "is_active": false}'
# Массово изменить тип пользователей (только суперадминистратор)
curl -s -X POST "$BASE_URL/api/v1/users/bulk/type" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": [2, 3], "type": "admin"}'
# Массово сбросить тип пользователей до regular (только суперадминистратор)
curl -s -X POST "$BASE_URL/api/v1/users/bulk/type/reset" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": [2, 3]}'
Лицензия
Жизненный цикл лицензии
Платформа проверяет состояние лицензии автоматически. Возможные статусы:
| Статус | Описание |
|---|---|
active | Лицензия действительна |
warning | До окончания лицензии осталось менее 30 дней |
grace_period | Срок действия истёк, доступен льготный период (14 дней) |
blocked | Льготный период истёк — API заблокировано (кроме суперадминистратора) |
no_license | Лицензия не внесена |
При статусах blocked и no_license все эндпоинты возвращают 402 Payment Required, кроме:
POST /api/v1/login/access-tokenGET /api/v1/license/get_licensePOST /api/v1/license/importGET /api/v1/users/me
Суперадминистратор может войти в систему и внести лицензию при любом статусе.
При статусах warning и grace_period платформа автоматически рассылает email-уведомления всем суперадминистраторам (не чаще одного раза в 24 часа).
Лимит приложений
Лицензия ограничивает максимальное количество приложений (max_applications). При превышении лимита создание нового приложения вернёт 402 с кодом license_app_limit_exceeded. Значение -1 означает отсутствие ограничений.
# Просмотр текущего статуса лицензии
curl -s "$BASE_URL/api/v1/license/get_license" \
-H "Authorization: Bearer $TOKEN"
# Пример ответа:
# {
# "status": "warning",
# "license_data": { "license_id": "...", "owner": "...", "valid_until": "2026-03-01T00:00:00Z", ... },
# "days_remaining": 12,
# "grace_period_ends_at": "2026-03-15T00:00:00Z"
# }
# Импорт лицензии (требует прав суперадминистратора)
curl -s -X POST "$BASE_URL/api/v1/license/import" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"license_data": "<ВАШ_КЛЮЧ>"}'
# Удалить лицензию
curl -s -X POST "$BASE_URL/api/v1/license/import" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"license_data": null}'
API-токены
API-токен — долгоживущий токен для CI/CD-пайплайнов и скриптов. В отличие от JWT, он не истекает автоматически: его можно отозвать только явным запросом. Токен показывается один раз при создании — сохраните его.
# Создать API-токен (требует активной сессии JWT)
# Возвращает JSON с полем access_token
curl -s -X POST "$BASE_URL/api/v1/tokens" \
-H "Authorization: Bearer $JWT_TOKEN"
Полученный access_token используйте в дальнейших запросах через заголовок X-Integration-Key:
# Пример запроса с API-токеном
curl -s "$BASE_URL/api/v1/applications/" \
-H "X-Integration-Key: Bearer $API_TOKEN"
Заголовок X-Integration-Key: Bearer <token> принимается всеми защищёнными эндпоинтами API наравне со стандартным Authorization: Bearer <jwt>.
Приложения
# Список приложений
curl -s "$BASE_URL/api/v1/applications/" \
-H "Authorization: Bearer $TOKEN"
# Создать приложение
curl -s -X POST "$BASE_URL/api/v1/applications/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "My App", "description": "Описание приложения"}'
# Удалить приложение
curl -s -X DELETE "$BASE_URL/api/v1/applications/<APP_ID>" \
-H "Authorization: Bearer $TOKEN"
Загрузка архива и сканирование
# Загрузить архив исходного кода (ZIP) — создаёт ревизию, сканирование не запускает
curl -s -X POST "$BASE_URL/api/v1/applications/<APP_ID>/scan_upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@/путь/к/архиву.zip"
# Запустить сканирование по последней ревизии приложения
curl -s -X POST "$BASE_URL/api/v1/scans/start?application_id=<APP_ID>" \
-H "Authorization: Bearer $TOKEN"
# Прогресс сканирования
curl -s "$BASE_URL/api/v1/scans/<SCAN_ID>/progress" \
-H "Authorization: Bearer $TOKEN"
# Ошибки сканирования
curl -s "$BASE_URL/api/v1/scans/<SCAN_ID>/errors" \
-H "Authorization: Bearer $TOKEN"
Уязвимости
# Список уязвимостей по приложению (первые 50)
curl -s "$BASE_URL/api/v1/vulnerability/?application_id=<APP_ID>&limit=50&skip=0" \
-H "Authorization: Bearer $TOKEN"
# Количество уязвимостей
curl -s "$BASE_URL/api/v1/vulnerability/count" \
-H "Authorization: Bearer $TOKEN"
# Лента «Активность» по уязвимости (изменения статуса и критичности)
curl -s "$BASE_URL/api/v1/vulnerability/<VULN_ID>/history?limit=50&skip=0" \
-H "Authorization: Bearer $TOKEN"
# Опциональный фильтр по типу события: ?type=STATUS или ?type=SEVERITY
# Перевод статуса уязвимости (FSM)
curl -s -X POST "$BASE_URL/api/v1/vulnerability/<VULN_ID>/transition" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status":"CONFIRMED"}'
# Массовый перевод статуса (атомарно для всего набора)
curl -s -X POST "$BASE_URL/api/v1/vulnerability/bulk/transition" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids":[1,2,3],"status":"FALSE_POSITIVE","comment":"Обоснование"}'
# Массовое изменение критичности
curl -s -X POST "$BASE_URL/api/v1/vulnerability/bulk" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids":[1,2,3],"data":{"severity":"high"}}'
Ответ эндпоинта списка уязвимостей содержит ключ
"vulnerabilities"(массив) и"count"(общее число).Допустимые значения
status:UNDER_REVIEW,CONFIRMED,IN_PROGRESS,REQUIRES_VERIFICATION,REJECTED_FIX,FIXED,FALSE_POSITIVE,ACCEPTED_RISK,DUPLICATE. Для ряда переходов требуется обязательноеcomment— иначе вернётся400.403— у пользователя нет права на данный переход;404— уязвимость не найдена или недоступна.
Отчёты
# Создать PDF-отчёт по приложению
curl -s -X POST "$BASE_URL/api/v1/reports" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"app_id": <APP_ID>,
"title": "Отчёт 2026-01-24",
"vuln_filters": {
"statuses": ["UNDER_REVIEW", "CONFIRMED"],
"severities": ["critical", "high"]
}
}'
# statuses — значения единого статуса жизненного цикла: UNDER_REVIEW, CONFIRMED,
# IN_PROGRESS, REQUIRES_VERIFICATION, REJECTED_FIX, FIXED, FALSE_POSITIVE,
# ACCEPTED_RISK, DUPLICATE.
# Список отчётов
curl -s "$BASE_URL/api/v1/reports" \
-H "Authorization: Bearer $TOKEN"
# Отменить генерацию отчёта (доступно пока статус created или processing)
curl -s -X POST "$BASE_URL/api/v1/reports/<REPORT_ID>/cancel" \
-H "Authorization: Bearer $TOKEN"
# 400 — если отчёт уже завершён, упал или отменён
# Скачать PDF-отчёт
curl -s -OJ "$BASE_URL/api/v1/reports/<REPORT_ID>/download" \
-H "Authorization: Bearer $TOKEN"
Ответ эндпоинта списка отчётов содержит ключ
"reports"(массив). Статусы отчёта:created→processing→completed/failed/cancelled.
Соответствие ГОСТ (Compliance)
# Получить дашборд соответствия
curl -s "$BASE_URL/api/v1/compliance/dashboard" \
-H "Authorization: Bearer $TOKEN"
Пример ответа:
{
"total": 25,
"compliant": 5,
"partial": 3,
"non_compliant": 15,
"not_applicable": 2,
"score_percent": 21.7,
"categories": [
{
"category": "planning",
"total": 5,
"compliant": 1,
"partial": 1,
"non_compliant": 3,
"not_applicable": 0
}
],
"requirements": [
{
"id": 1,
"code": "5.1",
"title": "Планирование процессов разработки безопасного программного обеспечения",
"category": "planning",
"sort_order": 1,
"is_automatable": false,
"has_template": true,
"evidence_count": 2,
"status": {
"status": "partial",
"auto_status": null,
"manual_status": "partial"
}
}
]
}
score_percent— процент выполненных требований (compliant / (total - not_applicable) * 100), округлён до одного знака.
AI-интеграции
# Создать AI-интеграцию и сразу привязать к приложениям
curl -s -X POST "$BASE_URL/api/v1/ml-integration/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "ML Prod", "url": "https://ml.example.com", "app_ids": [1, 2]}'
# Список AI-интеграций (фильтры: name, is_active)
curl -s "$BASE_URL/api/v1/ml-integration/?is_active=true" \
-H "Authorization: Bearer $TOKEN"
# Проверить доступность произвольного URL без сохранения
curl -s -X POST "$BASE_URL/api/v1/ml-integration/check-access" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://ml.example.com"}'
# Привязать или отвязать AI-интеграцию у приложения (null — отвязать)
curl -s -X POST "$BASE_URL/api/v1/applications/<APP_ID>/link-ml-integration" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ml_integration_id": 1}'
Создание и обновление интеграции проверяют доступность AI-сервиса по
GET /health. Ответcheck-access:{"id": null, "access": "available"|"unavailable"}.
Параметры конвейера AI-триажа задаются переменными окружения backend-сервисов:
| Переменная | Назначение |
|---|---|
ML_API_TIMEOUT | Таймаут HTTP-запроса к AI-сервису (по умолчанию 180 с) |
ML_TRIAGE_BATCH_SIZE | Размер пачки задач, забираемых из очереди за один опрос |
ML_TRIAGE_ANALYZER_CONCURRENCY | Число параллельных вызовов AI-сервиса в одной реплике |
ML_STUCK_AGE_MIN | Возраст «зависшей» задачи, после которого она возвращается в очередь |
ML_MAX_ATTEMPTS | Максимальное число попыток обработки задачи |
ML_OUTBOX_TTL_DAYS | Срок хранения завершённых задач до удаления |
Ограничение:
ML_STUCK_AGE_MIN(в секундах) должен быть больше3 × ML_API_TIMEOUT, иначе backend не запустится. При значениях по умолчанию условие выполняется (1800 с > 540 с).
Jira-интеграции
# Проверить доступность Jira до сохранения интеграции (token обязателен)
curl -s -X POST "$BASE_URL/api/v1/integrations/check_url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://jira.example.com", "token": "<PAT>", "auth_type": "pat"}'
# Создать Jira-интеграцию (перед записью проверяется доступность; сохраняется
# только при успехе)
curl -s -X POST "$BASE_URL/api/v1/integrations/" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"integration_type": "jira", "name": "Monolit-Jira", "url": "https://jira.example.com", "token": "<PAT>", "config": {"auth_type": "pat"}}'
# Список интеграций (фильтр по типу: ptai | appscreener | codescoring | jira)
curl -s "$BASE_URL/api/v1/integrations/?integration_type=jira" \
-H "Authorization: Bearer $TOKEN"
# Перепроверить доступ к сохранённой интеграции (опционально с project_key)
curl -s -X POST "$BASE_URL/api/v1/integrations/<INTEGRATION_ID>/check_access" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"project_key": "SDL"}'
# Список Jira-проектов, видимых интеграцией
curl -s "$BASE_URL/api/v1/jira/<INTEGRATION_ID>/projects" \
-H "Authorization: Bearer $TOKEN"
# Типы задач для проекта
curl -s "$BASE_URL/api/v1/jira/<INTEGRATION_ID>/issue_types?project_key=SDL" \
-H "Authorization: Bearer $TOKEN"
# Создать тестовый тикет и сразу удалить его (проверка прав и полей)
curl -s -X POST "$BASE_URL/api/v1/integrations/<INTEGRATION_ID>/test_ticket" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"project_key": "SDL", "issue_type": "Bug"}'
# Массовое удаление интеграций
curl -s -X POST "$BASE_URL/api/v1/integrations/bulk_delete" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": [1, 2, 3]}'
# Отвязать все приложения от интеграции
curl -s -X POST "$BASE_URL/api/v1/integrations/<INTEGRATION_ID>/detach_applications" \
-H "Authorization: Bearer $TOKEN"
Привязка приложения к Jira выполняется обновлением приложения (PUT /api/v1/applications/<APP_ID>) с полями task_tracker_integration_id, task_tracker_enabled и task_tracker_settings:
# Включить баг-трекинг для приложения
curl -s -X PUT "$BASE_URL/api/v1/applications/<APP_ID>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"task_tracker_integration_id": 1, "task_tracker_enabled": true, "task_tracker_settings": {"type": "jira", "project_key": "SDL", "issue_type": "Bug"}}'
# Фоновый экспорт всех уязвимостей приложения в Jira (202 Accepted, job_id)
curl -s -X POST "$BASE_URL/api/v1/application/<APP_ID>/export_to_task_tracker" \
-H "Authorization: Bearer $TOKEN"
# Перенести тикеты приложения в другой проект той же интеграции
curl -s -X POST "$BASE_URL/api/v1/applications/<APP_ID>/migrate_task_tracker_project" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"new_project_key": "SDL2", "new_issue_type": "Bug"}'
# Отвязать приложение от трекера
curl -s -X POST "$BASE_URL/api/v1/applications/<APP_ID>/detach_task_tracker" \
-H "Authorization: Bearer $TOKEN"
# Создать тикет в Jira для отдельной уязвимости вручную
curl -s -X POST "$BASE_URL/api/v1/vulnerability/<VULN_ID>/task_tracker_ticket" \
-H "Authorization: Bearer $TOKEN"
# Удалить тикет, привязанный к уязвимости
curl -s -X DELETE "$BASE_URL/api/v1/vulnerability/<VULN_ID>/task_tracker_ticket" \
-H "Authorization: Bearer $TOKEN"
Токен Jira (PAT) должен содержать только ASCII-символы и иметь права на просмотр проекта, создание и редактирование тикетов, добавление комментариев и переходы по статусам. Для аутентификации поддерживаются
pat(по умолчанию) иbasic(требуетusernameвconfig).
Полная документация по API доступна в Swagger UI: $BASE_URL/api/v1/docs
Интеграция с CI/CD
Monolit поддерживает интеграцию с CI/CD для автоматического запуска анализа безопасности при сборке кода. Это позволяет внедрить анализ кода в каждую сборку и обнаруживать уязвимости до развёртывания приложения.
Для аутентификации в CI/CD используйте API-токен (см. раздел API-токены). Передавайте его через заголовок X-Integration-Key: Bearer <API_TOKEN>. Переменную API_TOKEN рекомендуется хранить в секретах пайплайна, а не в тексте конфигурации.
Интеграция с GitLab CI
Для интеграции с GitLab CI необходимо вызвать API Monolit и передать исходный код для сканирования. Пример файла .gitlab-ci.yml:
stages:
- build
- security
variables:
MONOLIT_HOST: "https://<MONOLIT_HOST>"
APPLICATION_ID: "<APPLICATION_ID>"
build:
stage: build
script:
- zip -r /tmp/sources.zip .
security_scan:
stage: security
script:
- |
curl -s -X POST \
-H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "file=@/tmp/sources.zip" \
"$MONOLIT_HOST/api/v1/applications/$APPLICATION_ID/scan_upload"
- rm /tmp/sources.zip
- |
curl -s -X POST \
-H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
"$MONOLIT_HOST/api/v1/scans/start?application_id=$APPLICATION_ID"
allow_failure: true
Переменную MONOLIT_API_TOKEN добавьте в настройки проекта GitLab → Settings → CI/CD → Variables (тип: Masked).
- build — этап сборки, на котором код архивируется для дальнейшей отправки на анализ.
- security_scan — отправка ZIP-архива с исходным кодом на сервер Monolit и запуск сканирования.
Интеграция с Jenkins
Для интеграции с Jenkins можно использовать команду curl, чтобы отправить код на анализ в Monolit:
- Создайте задачу (job) в Jenkins для запуска сканирования.
- Добавьте переменную
MONOLIT_API_TOKENв Jenkins Credentials (тип: Secret text). - В разделе Build Steps добавьте выполнение следующего shell-скрипта:
#!/bin/bash
# Архивирование исходного кода
zip -r /tmp/sources.zip .
# Отправка в Monolit
curl -s -X POST \
-H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "file=@/tmp/sources.zip" \
"https://<MONOLIT_HOST>/api/v1/applications/<APPLICATION_ID>/scan_upload"
# Очистка временных файлов
rm /tmp/sources.zip
# Запуск сканирования
curl -s -X POST \
-H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
"https://<MONOLIT_HOST>/api/v1/scans/start?application_id=<APPLICATION_ID>"
Интеграция с другими CI/CD-системами
Для других систем (CircleCI, Travis CI, TeamCity) используйте аналогичные команды. Пример для CircleCI:
version: 2.1
jobs:
security_scan:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: Архивирование исходного кода
command: zip -r /tmp/sources.zip .
- run:
name: Отправка в Monolit
command: |
curl -s -X POST \
-H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "file=@/tmp/sources.zip" \
"https://<MONOLIT_HOST>/api/v1/applications/<APPLICATION_ID>/scan_upload"
- run:
name: Запуск сканирования
command: |
curl -s -X POST \
-H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
"https://<MONOLIT_HOST>/api/v1/scans/start?application_id=<APPLICATION_ID>"
- run:
name: Очистка
command: rm /tmp/sources.zip
Переменную MONOLIT_API_TOKEN добавьте в настройки проекта CircleCI → Project Settings → Environment Variables.
Получение результатов сканирования
После выполнения сканирования результаты доступны в интерфейсе приложения, а также через API:
# Прогресс сканирования приложения
curl -s -H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
"https://<MONOLIT_HOST>/api/v1/applications/<APPLICATION_ID>/scan_progress"
# Перечень уязвимостей приложения
curl -s -H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
"https://<MONOLIT_HOST>/api/v1/applications/<APPLICATION_ID>/vulnerabilities?type=sast&skip=0&limit=50"
curl -s -H "X-Integration-Key: Bearer $MONOLIT_API_TOKEN" \
"https://<MONOLIT_HOST>/api/v1/applications/<APPLICATION_ID>/vulnerabilities?type=sca&skip=0&limit=50"
Резервное копирование и восстановление данных
Резервное копирование базы данных
- Ручное резервное копирование базы данных PostgreSQL из контейнера Docker с помощью
pg_dump:
Чтобы выполнить резервное копирование базы данных, работающей в контейнере Docker, выполните следующую команду:
docker compose exec -T postgres \
pg_dump -U sdlplatform sdlplatform > monolit_backup.sql
-
postgres— имя сервиса PostgreSQL вdocker-compose.yml. -
sdlplatform— имя пользователя и базы данных по умолчанию (исторически совпадают). -
monolit_backup.sql— путь к файлу резервной копии на хосте. -
Автоматическое резервное копирование: Настройте Cron для регулярного выполнения резервного копирования базы данных. Пример для выполнения резервного копирования каждый день в 2:00:
0 2 * * * cd /path/to/sdlplatform && docker compose exec -T postgres pg_dump -U sdlplatform sdlplatform > /backups/monolit_db_$(date +\%F).sql
Резервное копирование файлов конфигурации
Кроме базы данных, важно регулярно сохранять конфигурационные файлы системы. Эти файлы включают:
- Файлы конфигурации Docker (
docker-compose.yml,docker-compose.override.yml) - Переменные окружения (
.env) - Файлы конфигурации Nginx (
nginx.conf,nginx-dev.conf) - SSL-сертификаты (
keys/ssl/) - Файлы аутентификации (
keys/.htpasswd)
Пример команды для резервного копирования конфигурационных файлов:
tar -czvf /backups/config_backup_$(date +\%F).tar.gz /path/to/configs/
Восстановление базы данных
Чтобы восстановить базу данных из резервной копии, выполните команду psql внутри контейнера Docker:
docker compose exec -T postgres psql -U sdlplatform -d sdlplatform < monolit_backup.sql
Эта команда восстановит данные из резервной копии базы данных sdlplatform.
Восстановление файлов конфигурации
Для восстановления файлов конфигурации выполните следующую команду:
tar -xzvf /path/to/backup/config_backup.tar.gz -C /path/to/configs/
Дополнительные рекомендации
-
Периодичность резервного копирования: Определите частоту резервного копирования в зависимости от объёма данных и критичности системы. Рекомендуется выполнять ежедневные резервные копии базы данных и еженедельные полные резервные копии системы.
-
PDF-отчёты: Сформированные отчёты хранятся в MinIO (отдельный бакет для PDF). При необходимости сохранения отчётов включите соответствующий бакет или том MinIO в процедуру резервного копирования (например, копирование тома
minio_storageили содержимого бакета). -
Свидетельства соответствия: Загруженные пользователями документы-свидетельства и предзагруженные шаблоны для модуля «Соответствие ГОСТ» хранятся в бакете MinIO
compliance-evidence. Включите этот бакет в процедуру резервного копирования наряду с бакетом PDF-отчётов. -
Внешние хранилища: Храните резервные копии на внешних носителях или в облаке для защиты от сбоев на сервере (например, AWS S3, Google Cloud Storage).
-
Шифрование резервных копий: Для безопасности рекомендуется шифровать резервные копии с помощью таких инструментов, как gpg:
gpg --encrypt --recipient your_email@example.com /path/to/backup.sql
Мониторинг и диагностика
Журналирование
Сервисы платформы пишут журнал в стандартный вывод контейнера. Общий поток по всем сервисам:
docker compose logs -f
Для просмотра логов конкретного сервиса:
docker compose logs -f backend
docker compose logs -f ml_triage_analyzer
docker compose logs -f worker_semgrep
Проверка доступности
Бэкенд отвечает на запрос состояния без аутентификации — этот адрес подходит для внешнего мониторинга и проб Kubernetes:
curl -s -o /dev/null -w "%{http_code}\n" "https://<ваш-хост>/api/v1/healthcheck"
Ответ 200 означает, что бэкенд поднят и отвечает.
Собственного эндпоинта метрик в формате Prometheus платформа не отдаёт. Загрузку контейнеров по процессору, памяти и диску снимайте стандартными экспортёрами уровня хоста (cAdvisor, node_exporter).
Диагностика ошибок
Ошибки обращений к платформе видны в журнале nginx, ошибки обработки — в журнале того сервиса, который выполнял операцию: сканирование — butler_service и соответствующий worker_*, отчёты — pdf_generator, AI-триаж — ml_triage_analyzer.
Сбор логов для диагностики
При обращении в техническую поддержку или самостоятельной диагностике проблем соберите логи ключевых контейнеров. Имена контейнеров зависят от вашей поставки — в примерах ниже используются имена по умолчанию.
Backend (основной сервис):
docker logs --tail=2000 sdlplatform-backend-1 > backend.log 2>&1
Butler (воркер сканирования):
docker logs --tail=2000 sdlplatform-butler_service-1 > butler.log 2>&1
Генератор PDF-отчётов:
docker logs --tail=2000 sdlplatform-pdf_gen-1 > pdf_gen.log 2>&1
Все сервисы сразу:
docker compose logs --tail=2000 > sdlplatform-all.log 2>&1
Если используется кастомный
docker-compose.yml, имена контейнеров могут отличаться. Актуальный список запущенных контейнеров можно получить командойdocker ps --format '{{.Names}}'.
Обновления и патчи
Обновление приложения Monolit
Платформа поставляется собранными образами: обновление сводится к смене версии и перезапуску контейнеров, собирать ничего не нужно.
Для Docker Compose обновление выполняет install.sh из каталога установки — порядок действий и откат описаны в разделе Обновление Monolit:
sudo bash sdlplatform/install.sh
Для Kubernetes версия меняется в values-prod.yaml — см. раздел Обновление релиза.
Перезапустить отдельный сервис без смены версии:
cd sdlplatform
sudo docker compose restart backend
sudo docker compose restart ml_triage_analyzer
Установка патчей безопасности
Патчи безопасности необходимы для предотвращения уязвимостей в системе. Обычно они могут включать обновления операционной системы, баз данных и серверного ПО.
- Обновление операционной системы:
На сервере, где запущен Docker, регулярно устанавливайте обновления безопасности операционной системы (например, на Ubuntu):
sudo apt update && sudo apt upgrade -y
Это обеспечит актуальность пакетов и установку критических патчей безопасности.
- Автоматическое обновление безопасности:
Включите автоматическое обновление безопасности для критических пакетов:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Проверка состояния после обновлений
После применения любых обновлений выполните следующие шаги для проверки работоспособности системы:
- Проверьте статус контейнеров:
docker compose ps
Убедитесь, что все контейнеры запущены и работают корректно.
- Проверьте логи системы: Используйте следующую команду для просмотра логов контейнеров и поиска возможных ошибок:
docker compose logs -f
-
Тестирование функциональности: Пройдите по основным функциям системы, чтобы убедиться, что обновления не вызвали проблем в работе.
-
Восстановление из резервной копии:
Если откат образов или кода не помогает, выполните восстановление базы данных и файлов конфигурации из резервной копии (см. раздел Восстановление базы данных и Восстановление файлов конфигурации).
Безопасность
Настройка брандмауэра
Рекомендации по настройке брандмауэра: Откройте только необходимые порты для работы платформы, например, порты для Docker, Nginx, и SSH. Все другие порты должны быть закрыты.
Пример команды для настройки правил брандмауэра на основе UFW (Uncomplicated Firewall):
sudo ufw allow OpenSSH
sudo ufw allow 443/tcp
sudo ufw enable
Политики паролей
Платформа принимает пароли длиной от 4 до 40 символов и не проверяет их состав. Требования к сложности задаются организационно и контролируются администратором при создании учётных записей.
Учётную запись demo@example.com с паролем demo после первичной проверки заблокируйте или удалите: она создаётся при первом запуске и известна всем, кто читал это руководство.
Аудит безопасности
Регулярный аудит безопасности:
Используйте инструменты для анализа безопасности системы, такие как Lynis или OpenSCAP, для выявления уязвимостей и несоответствий конфигурации.
Пример выполнения аудита с помощью Lynis:
sudo lynis audit system
Часто задаваемые вопросы
Техническая поддержка
В случае возникновения проблем свяжитесь с технической поддержкой: support@cybear.ru
