Документация / Руководство по установке / Установка
Установка в Kubernetes
Установку выполняет команда SecurityFlow: кладёт образы в реестр площадки, создаёт секреты, разворачивает Core и Radar и проверяет работу. Площадка заранее готовит кластер, виртуальные машины, сеть и доступы. На этой странице - что разворачивается, в каком порядке и как проверить результат.
Перед началом
Площадка готовит:
| Что | Требование | Подробнее |
|---|---|---|
| Кластер | 3 мастера, пул app без taint, пул scan с taint dedicated=scanners:NoSchedule |
Системные требования |
| Пространства имён | securityflow-core, securityflow-radar; для securityflow-radar разрешены privileged-поды (Pod Security Admission) |
воркер сканирования запускает Docker-in-Docker |
| Хранилище | StorageClass для локальных томов брокеров; RWX-том 20 GiB для файлов Core | Хранилище |
| Ingress | ingress-nginx с client-max-body-size 100m и proxy-read-timeout 300s |
|
| Внешний прокси | терминирует TLS для имён Core и Radar и передаёт запросы в ingress | Сетевое взаимодействие |
| Хосты для ВМ | под PostgreSQL, реестр образов и служебную ВМ | Расчёт ресурсов |
| Доступы | SSH и sudo на хосты, kube-apiserver 6443, исходящий HTTPS до securityflow.ru |
|
| Ключ лицензии | выдаёт SecurityFlow | Активация лицензии |
Нужны две базы PostgreSQL 15 или новее, для Core и для Radar, и пользователи, которым разрешено создавать в них объекты: миграции создают и меняют таблицы при установке и каждом обновлении.
Что разворачивается
Имена Deployment и Service задаются при установке. В командах на страницах документации они даны в угловых скобках, например <Radar back>. Теги образов - по составу релиза, см. Релизы.
Core, пространство securityflow-core
Процессы Core работают на одном образе sf-core-back. Какой процесс поднять, решает переменная MODE.
| Компонент | Образ | Порт | Реплики | Request / limit | Данные |
|---|---|---|---|---|---|
Подготовка базы: Job sf-core-init, MODE=init |
sf-core-back |
- | разовый запуск, до 3 попыток | 250m, 512Mi / 1 CPU, 1Gi | миграции базы Core, статика, администратор |
Интерфейс и API: MODE=web, gunicorn 4 × 4 |
sf-core-back |
8000 | 2 и больше | 500m, 1Gi / 2 CPU, 2Gi | база Core, файлы media |
Приём отчётов: MODE=importer, gunicorn 2 × 4 |
sf-core-back |
8001 | 2 и больше | 500m, 2Gi / 2 CPU, 4Gi | отчёт целиком в памяти, затем в брокер |
Worker: MODE=worker, очередь appsecpanel_ |
sf-core-back |
- | 2 и больше | 500m, 1Gi / 2 CPU, 2Gi | база Core |
Планировщик: MODE=beat |
sf-core-back |
- | ровно 1, стратегия Recreate |
100m, 256Mi / 500m, 512Mi | расписания в базе Core |
Разбор отчётов, очередь importer_service |
sf-core-importer |
- | 2-4, параллельность 3 | 1 CPU, 1,5Gi / 4Gi | - |
| Помощник БД: запись находок, автовалидатор, дедупликатор, CVSS | sf-core-db-helper |
- | ровно 1 | 1 CPU, 2,5Gi / 5Gi | база Core |
Jira-помощник, очередь jira_ |
sf-core-jira-helper |
- | 1-2, параллельность 2 | 0,1 CPU, 256Mi / 1Gi | - |
| Фронт: nginx и интерфейс | sf-core-front |
80 | 2-3 | 50m, 64Mi / 256Mi | статика и файлы media только на чтение |
| RabbitMQ Core, quorum queues | RabbitMQ | 5672 | 3 | 0,5 CPU, 1Gi / 2Gi | локальный том 30 GiB на реплику |
Интерфейс и API и приём отчётов - отдельные Deployment, у каждого свой Service: на порт 8000 и на порт 8001.
Тома Core:
| Том | Куда подключается |
|---|---|
| RWX-том файлов Core (media) | /usr/src/app/media процессов Core, /var/www/media фронта |
| Статика Django | Job подготовки собирает её в /usr/src/app/static, фронт отдаёт её из общего тома в /var/www/static |
Пробы readinessProbe и livenessProbe интерфейса и API - GET /healthcheck/ на порт 8000: путь отвечает 200 без входа. Если задан ALLOWED_HOSTS, проба передаёт заголовок Host с именем из этого списка. Пробы остальных компонентов - в разделе Мониторинг и журналы.
Планировщик Core работает строго в одной реплике: две копии поставят каждое периодическое задание дважды. Стратегия Recreate не даёт двум планировщикам пересечься при обновлении.
Radar, пространство securityflow-radar
| Компонент | Образ | Порт | Реплики | Request / limit | Данные |
|---|---|---|---|---|---|
Radar back: API, API_WORKERS=4 |
sf-radar-back |
8090 | 2 | 0,55 CPU, 0,8Gi / 2,25Gi | база Radar |
| Фронт Radar | sf-radar-front |
8080 | 2 | 50m, 64Mi / 256Mi | - |
| Воркер сканирования: пайплайн-воркер, Docker-in-Docker, utils-воркер, очистка Docker | sf-radar-worker |
- | 2 на узел scan | 3,9 CPU, 10,5Gi / 20Gi | emptyDir на локальном SSD: тома пайплайнов, кэш образов сканеров |
| Планировщик Radar: ежедневная очистка | sf-radar-worker, entrypoint_ |
- | ровно 1 | 0,1 CPU, 256Mi / 512Mi | - |
| RabbitMQ Radar | RabbitMQ | 5672 | 3 | 0,5 CPU, 1Gi / 2Gi | локальный том 10 GiB на реплику |
| Redis | Redis | 6379 | 3 | 0,2 CPU, 512Mi / 1Gi | локальный том 5 GiB на реплику |
Состав пода воркера сканирования:
| Контейнер | Что делает |
|---|---|
Пайплайн-воркер, entrypoint_pipeline_worker.sh |
берёт пайплайны из pipeline_queue; слотов на под - MAX_SCALEWORKERS_COUNT=3 |
| Docker-in-Docker, privileged | запускает контейнеры сканеров |
Utils-воркер, entrypoint_utils_worker.sh, --concurrency=2 |
задачи utils_queue: остановка джоб, выдача артефактов, удаление образов |
| Очистка Docker по таймеру | удаляет старые тома и контейнеры Docker своего пода. Ежедневная очистка Radar затрагивает Docker одного пода, поэтому у каждого пода своя очистка: без неё на узле scan копится около 8 ГБ томов в сутки |
Только контейнер Docker-in-Docker работает в привилегированном режиме. Utils-воркер запускается с --concurrency=2 в команде контейнера: без флага Celery поднимает столько процессов, сколько CPU на узле.
Перезапуск Radar back прерывает сканы
Radar back при каждом старте применяет миграции базы и прерывает все пайплайны "В ожидании" и "Выполняется". Поднимайте и перезапускайте его в окно без сканов - см. Запуск, остановка и масштабирование.
Вне кластера
| Компонент | Где | Назначение |
|---|---|---|
| PostgreSQL, Patroni, etcd, PgBouncer, HAProxy и keepalived | 3 ВМ | базы Core и Radar, общий адрес на порту 5432 |
| Реестр образов | ВМ | образы платформы и сканеров |
| Служебная ВМ | ВМ | NFS-экспорт для файлов Core, репозиторий резервных копий |
| Сервер лицензий | у SecurityFlow, securityflow.ru |
активация и сверка лицензии |
Маршрутизация запросов
Ingress направляет имя Core на фронт Core (порт 80), имя Radar - на фронт Radar (порт 8080). Дальше запросы раскладывают сами фронты:
| Путь | Куда | Порт |
|---|---|---|
Core: /api/v1/scan/import/ |
приём отчётов | 8001 |
Core: /api/v1/, /admin/, /oauth2/callback |
интерфейс и API | 8000 |
Core: /static/, /media/ |
файлы из томов фронта | - |
| Core: остальное | интерфейс, index.html |
- |
Radar: /api/v1/, /admin/ |
Radar back | 8090 |
| Radar: остальное | интерфейс | - |
Swagger Core открывается по адресу /api/v1/docs/ и идёт по маршруту /api/v1/.
Фронт Core обращается к интерфейсу и API на порт 8000 и к приёму отчётов на порт 8001, фронт Radar - к Radar back на порт 8090. Имена сервисов бэкендов задаются при установке. nginx фронта не стартует, если не может разрешить имя бэкенда, поэтому сервисы бэкендов создаются раньше фронтов. Воркеры Radar обращаются к Radar back по адресу из AUDITOR_HOST - см. Параметры конфигурации.
Секреты
Секреты хранятся в Kubernetes Secrets и подключаются к подам переменными окружения. Копию секретов команда SecurityFlow передаёт владельцу площадки.
| Секрет | Пространство | Что внутри |
|---|---|---|
sf-core-env |
securityflow-core |
доступ к базе и брокеру Core, DJANGO_SECRET_KEY, пара JWT_PRIVATE_KEY и JWT_PUBLIC_KEY, LICENSE_SERVER_PUBLIC_KEY, данные первого администратора |
| секрет Radar | securityflow-radar |
доступ к базе, брокеру и Redis Radar, DOCKER_ENCRYPTION_TOKEN, ACCESS_TOKEN |
| пароли RabbitMQ и Redis | оба | пароли самих брокеров |
Полный перечень переменных, их формат и способы генерации - в разделе Параметры конфигурации.
Ключи шифрования задаются один раз
Пара JWT_PRIVATE_KEY и JWT_PUBLIC_KEY шифрует секреты интеграций в базе Core, DOCKER_ENCRYPTION_TOKEN - пароли реестров в базе Radar. После первого запуска их не меняют: сохранённые секреты станут нечитаемыми. Храните эти значения вместе с резервными копиями баз.
Порядок развёртывания
1. Пространства и хранилище
Создаются пространства securityflow-core и securityflow-radar, для Radar включается уровень privileged. Готовятся StorageClass для локальных томов и RWX-том для файлов Core.
kubectl create namespace securityflow-core
kubectl create namespace securityflow-radar
kubectl label namespace securityflow-radar pod-security.kubernetes.io/enforce=privileged
2. Секреты
Создаются секреты Core и Radar. Пример для Core:
kubectl -n securityflow-core create secret generic sf-core-env \
--from-literal=DJANGO_SECRET_KEY="$(openssl rand -hex 32)" \
--from-literal=DB_HOST=<адрес PostgreSQL> \
--from-literal=DB_PORT=5432 \
--from-literal=DB_NAME=<база Core> \
--from-literal=DB_USER=<пользователь Core> \
--from-literal=DB_PASS=<пароль> \
--from-literal=AMQP_HOST_STRING='amqp://<пользователь>:<пароль>@<RabbitMQ Core>:5672/<vhost>' \
--from-literal=DOMAIN=https://core.example.ru \
--from-literal=ALLOWED_HOSTS=core.example.ru,<внутренние имена Core> \
--from-file=JWT_PRIVATE_KEY=jwt.key \
--from-file=JWT_PUBLIC_KEY=jwt.pub \
--from-file=LICENSE_SERVER_PUBLIC_KEY=license.pub \
--from-literal=ADMIN_USER=admin \
--from-literal=ADMIN_EMAIL=<почта администратора>
Пароль первого администратора добавляется в секрет ключом ADMIN_PASSWORD. Если ключа нет, пароль генерируется при подготовке базы и выводится в её журнал один раз.
Как получить jwt.key, jwt.pub и license.pub - в разделе Формат PEM-ключей.
3. Брокеры и Redis
Разворачиваются RabbitMQ Core, RabbitMQ Radar и Redis по 3 реплики. До перехода к шагу 4 базы PostgreSQL должны быть доступны по общему адресу.
4. Подготовка базы Core
Job sf-core-init с MODE=init выполняет миграции, собирает статику, создаёт первого администратора и приводит к единому виду имена сканеров. Миграции идут отдельной задачей, а не при старте каждого пода: иначе при масштабировании мигрировал бы каждый новый под. Процессы Core разворачиваются только после завершения Job.
kubectl -n securityflow-core wait --for=condition=complete job/sf-core-init --timeout=900s
kubectl -n securityflow-core logs job/sf-core-init
Ожидаемый результат: Job в состоянии Complete, в журнале строки [admin] создан суперпользователь admin и [admin] назначена роль superuser (полный доступ). Если ADMIN_PASSWORD не задан, пароль сгенерирован и выведен в этот журнал один раз - см. Первичная настройка.
5. Процессы Core
Разворачиваются интерфейс и API, приём отчётов, worker и планировщик с их сервисами, затем разбор отчётов, помощник БД, Jira-помощник и фронт Core.
kubectl -n securityflow-core wait --for=condition=available deployment --all --timeout=600s
kubectl -n securityflow-core get pods
6. Radar
Сначала разворачивается Radar back в одной реплике. При старте он сам применяет миграции базы Radar (alembic upgrade head) и загружает встроенный каталог джоб. Затем число реплик доводится до двух, разворачиваются воркеры сканирования, планировщик Radar и фронт Radar.
kubectl -n securityflow-radar logs deploy/<Radar back> | grep -E "Alembic|Uvicorn"
kubectl -n securityflow-radar get pods -o wide
Поды воркера сканирования должны оказаться на узлах scan.
7. Ingress
Создаются правила ingress для имён Core и Radar. После этого Core открывается на экране активации лицензии.
8. Первичная настройка
Активация лицензии, вход администратора, токен Radar, связь Core и Radar, образы сканеров и первый скан - в разделе Первичная настройка.
Проверка
| Что | Как | Ожидаемый результат |
|---|---|---|
| Поды Core и Radar | kubectl -n securityflow-core get pods, kubectl -n securityflow-radar get pods |
все в Running, Job подготовки - Completed |
| Core web | kubectl -n securityflow-core port-forward deploy/<Core web> 8000:8000, затем curl -sS -o /dev/null -w '%{http_code}\n' -H 'Host: core.example.ru' http://127.0.0.1:8000/healthcheck/ |
200. Если ALLOWED_HOSTS задан, без заголовка Host из этого списка Core ответит 400 |
| Core через прокси | curl -sS -o /dev/null -w '%{http_code}\n' https://core.example.ru/admin/login/ |
200 |
| Radar через прокси | curl -sS https://radar.example.ru/api/v1/health-check/ |
{"is_healthy":true} |
| Токен Radar | curl -sS -H "Authorization: Bearer <токен Radar>" https://radar.example.ru/api/v1/auth-health-check/ |
{"is_healthy":true} |
| Воркеры Radar | curl -sS -H "Authorization: Bearer <токен Radar>" https://radar.example.ru/api/v1/workers/total/ |
pipeline_workers_total равно числу подов воркера, utils_workers_total - числу utils-воркеров |
| Связь Core и Radar | curl -sS -H "Authorization: Token <API-токен>" https://core.example.ru/api/v1/ci/health-check/ |
{"is_healthy": true, "is_authenticated": true} |
| Лицензия | Core: "Глобальные настройки" → "Лицензия" | видны компания, тариф и срок |
| Сквозной скан | первый аудит продукта | пайплайн в Radar "Завершен", в Core появился аудит |
Путь /healthcheck/ отвечает на порту 8000 процесса интерфейса и API. Через прокси проверяйте /admin/login/.
Диагностика
| Симптом | Причина | Что сделать |
|---|---|---|
| Job подготовки базы в Error | нет доступа к PostgreSQL, неверные DB_*, у пользователя нет прав на создание таблиц |
kubectl -n securityflow-core logs job/sf-core-init; проверьте доступ к 5432 и права пользователя |
Под sf-core-back сразу завершается с MODE=... не знаю |
неверное значение MODE |
допустимо all, init, web, importer, worker, beat |
Фронт Core или Radar в CrashLoopBackOff, в журнале host not found in upstream |
nginx фронта не разрешает имя сервиса бэкенда | проверьте, что сервисы бэкендов созданы и их имена совпадают с адресами бэкендов в конфигурации фронта |
| Поды интерфейса и API не переходят в Ready и перезапускаются | проба указывает не на /healthcheck/, или имя пробы не входит в ALLOWED_HOSTS и Core отвечает 400 |
переведите пробы на /healthcheck/, передайте в пробе заголовок Host из ALLOWED_HOSTS |
Страница /admin/ без стилей, /static/ отвечает 404 |
фронту не подключён том со статикой Django | подключите к /var/www/static фронта том со статикой, которую собрал Job подготовки |
| Core открывается, но активация не проходит | нет исходящего HTTPS до securityflow.ru или адрес кластера не в белом списке |
проверьте связность - Сетевое взаимодействие, ошибки активации - Активация лицензии |
| Загрузка отчёта отвечает 413 | отчёт больше лимита тела в ingress | проверьте размер отчёта; лимит ingress держите ниже max_message_size RabbitMQ |
| Под воркера не стартует, Docker-in-Docker в ошибке | privileged-поды запрещены в пространстве Radar | включите уровень privileged для securityflow-radar |
| В Radar "Нет Доступных Воркеров" | воркеры не подключились к брокеру Radar | проверьте AMQP_HOST_STRING воркеров и доступ к 5672 |
Пайплайн висит "В ожидании", в журнале воркера Aborting the pipeline |
воркер не прошёл проверку токена в Radar back | проверьте ACCESS_TOKEN и AUDITOR_HOST воркера - Первичная настройка |
| Джоба падает на скачивании образа | Docker пода не достаёт до реестра или нет учётных данных | проверьте доступ узлов scan к реестру и учётные данные реестра в Radar |
| Джоба-сканер в статусе "Джоба остановлена", отчёт не дошёл до Core | "Внутренний URL приложения" недоступен из Radar, или имя сканера в SCAN_TYPE неизвестно Core |
проверьте адрес в Core: "Глобальные настройки" → "Рабочий процесс"; имя сканера - Свой сканер |
| Аудит в Core есть, находок нет | задание не дошло до Radar: ошибки отправки Core пишет только в журнал worker | kubectl -n securityflow-core logs deploy/<Core worker>; проверьте "Статус подключения" в настройках Radar в Core |
Общая таблица ошибок - в разделе Типовые ошибки.