Развёртывание

Установка в Microsoft Azure

Развёртывание ScanSuite Teams в собственной подписке Azure на Container Apps с помощью Terraform, с примерами установки.

ScanSuite Teams можно развернуть не на сервере, а в собственной подписке Azure. Конфигурация Terraform из папки azure репозитория установки создаёт всё одной командой и удаляет другой. Приложение работает в Azure Container Apps вместе с управляемыми сервисами, так что обслуживать виртуальную машину не нужно.

Охват: статический анализ

В Container Apps нет демона Docker, поэтому сканеры, которые запускаются отдельными контейнерами, — динамическое сканирование веб-приложений (DAST) и сканирование инфраструктуры — здесь не работают. Анализ кода (SAST), зависимостей (SCA), инфраструктуры как кода, поиск секретов и AI-анализ кода работают полностью. Для динамических сканирований установите ScanSuite на сервер: Установка ScanSuite Teams.

Что создаётся

Всё размещается в одной группе ресурсов, которую создаёт развёртывание. Секреты генерируются при первом развёртывании и хранятся в Key Vault. База данных доступна только изнутри виртуальной сети, а хранилище артефактов — только из подсети Container Apps, без ключей хранилища.

ЧастьКак работает
Веб-интерфейс и APIПриложение-контейнер с управляемым TLS; входящий трафик пропускается только с ваших диапазонов адресов.
Фоновые воркерыПриложения-контейнеры: обслуживание и восстановление прерванных сканирований, планировщик, Redis для очереди задач и песочница для AI-проверок proof-of-concept, которая запускается по требованию.
СканированияОтдельный запуск задания Container Apps на каждое сканирование, 4 vCPU и 8 ГиБ; после сканирования он завершается.
Миграция базы данныхЗадание Container Apps, которое запускает deploy.sh.
База данныхAzure Database for PostgreSQL 16 (Flexible Server), внутренняя, с резервными копиями за семь дней.
Артефакты сканированийBlob Storage, доступ через управляемое удостоверение; прежние версии хранятся 30 дней.
ОбразыСобственный Azure Container Registry: во время работы установка ничего не загружает из интернета.
Журналы и оповещенияLog Analytics с оповещениями об ошибках, неудачных сканированиях и нагрузке на базу данных.

1. Подготовка

  • Подписка Azure, в которой у вас роль Owner или Contributor вместе с Role Based Access Control Administrator: развёртывание создаёт управляемые удостоверения, собственную роль и назначения ролей, поэтому одной роли Contributor недостаточно.
  • Инструменты на Linux, macOS или Windows с WSL или Git Bash: Azure CLI (az) 2.60 или новее, Terraform 1.6 или новее, git и bash.
  • Из поставки ScanSuite: файл лицензии (<имя>_<код>.lic; код — это и тег образов), а также имя пользователя и токен доступа к реестру образов — с ними образы копируются в вашу подписку.
  • Ваш публичный IPv4-адрес или диапазоны, с которых разрешено открывать веб-интерфейс. Запрашивайте именно IPv4, иначе многие подключения покажут IPv6-адрес: curl -4 -s https://ifconfig.me.

2. Развёртывание

Загрузите файлы установки, добавьте лицензию и перейдите в папку azure:

bash
git clone https://github.com/cepxeo/scansuite.git
cp /path/to/<имя>_<код>.lic scansuite/key/
cd scansuite/azure

Войдите в Azure и запишите подписку, в которую будете разворачивать:

bash
az login
az account list -o table

Скопируйте пример настроек и отредактируйте копию. Готовые примеры — в разделе 3.

Терминал
cp terraform.tfvars.example terraform.tfvars
ПараметрЧто указать
subscription_idID подписки из az account list.
locationРегион, например germanywestcentral, swedencentral или northeurope.
resource_group_nameИмя новой группы ресурсов. Её создаёт развёртывание, поэтому такой группы ещё не должно быть.
web_allowed_cidrsДиапазоны адресов, с которых открывается интерфейс, например ["203.0.113.10/32"].
image_tagКод вашей лицензии, <код> в <имя>_<код>.lic.
alert_emailНеобязательно. Адрес для оповещений.

Передайте учётные данные реестра через переменные окружения — они нужны только для копирования образов и нигде не сохраняются — и запустите развёртывание:

bash
export DOCKERHUB_USERNAME='<имя пользователя реестра>'
export DOCKERHUB_TOKEN='<токен доступа к реестру>'
./deploy.sh

Первый запуск занимает 30–40 минут, большую часть из них Azure создаёт среду Container Apps. До того как что-либо создавать, скрипт проверяет инструменты, вход в Azure, лицензию и то, может ли ваша подписка создать PostgreSQL в выбранном регионе. Затем он создаёт сеть, базу данных, Key Vault, хранилище, реестр, среду Container Apps и Redis; копирует образы ScanSuite в ваш реестр; запускает веб-интерфейс и воркеры и выполняет миграцию базы данных. Когда скрипт завершается строкой Done, установка работает, а её адрес — значение вывода url. Повторно вывести значения можно в любой момент командой terraform output.

Если в Docker на этой же машине уже есть образы для кода вашей лицензии, например от установки на сервер, deploy.sh загрузит эти локальные копии вместо копирования из реестра; удалите их заранее, если они могли устареть.

3. Примеры установки

Примеры A и B — готовые файлы terraform.tfvars; C–E — строки, которые добавляются к одному из них. Учётные данные реестра всегда передаются через переменные окружения, как в разделе 2.

A. Пробная установка

Небольшие размеры dev, интерфейс открыт для одного адреса:

terraform.tfvars
subscription_id     = "00000000-0000-0000-0000-000000000000"
location            = "swedencentral"
resource_group_name = "rg-scansuite-trial"
environment         = "dev"

image_tag         = "a1b2c3"
web_allowed_cidrs = ["203.0.113.10/32"]
timezone          = "Europe/Moscow"

# Холодный старт вместо постоянно прогретого интерфейса: первый вход после
# перерыва ждёт около минуты.
web_min_replicas = 0

Когда пробный период закончится, ./destroy.sh удалит всю группу ресурсов.

B. Производственная установка

Зонально-избыточная база данных с резервной копией, зонально-избыточное хранилище, реестр Premium, защита Key Vault от окончательного удаления и выделенный профиль вычислений для сканирований, а также постоянный исходящий адрес и журналы без ограничения объёма:

terraform.tfvars
subscription_id     = "00000000-0000-0000-0000-000000000000"
location            = "germanywestcentral"
resource_group_name = "rg-scansuite"
environment         = "prod"

image_tag         = "a1b2c3"
web_allowed_cidrs = ["198.51.100.0/24", "203.0.113.10/32"]   # офис и VPN
timezone          = "Europe/Moscow"
alert_email       = "secops@acme.example"

postgres_sku       = "GP_Standard_D2ds_v5"
enable_nat_gateway = true
log_daily_quota_gb = -1

Это на несколько сотен долларов в месяц дороже, чем dev. Прежде чем развёртыванием займётся кто-то ещё, перенесите состояние Terraform в Azure Storage, как описано в backend.tf.example.

C. Постоянный исходящий адрес

Иначе исходящий трафик уходит с адреса среды, который может меняться. Если git-сервер или AI-провайдер принимает только адреса из списка, добавьте NAT-шлюз (около 35 долларов в месяц плюс трафик); адрес, который нужно разрешить, будет в выводе egress_ip:

terraform.tfvars
enable_nat_gateway = true

D. Вторая установка в той же подписке

Например, тестовая рядом с производственной. Разворачивайте её из отдельной копии папки, чтобы у неё было своё состояние Terraform (cp -r scansuite/azure scansuite/azure-test), в собственную группу ресурсов. Глобально уникальные имена получают случайный суффикс, так что больше ничего менять не нужно:

terraform.tfvars
resource_group_name = "rg-scansuite-test"

E. Регион, где PostgreSQL вам недоступен

Некоторые типы подписок, в том числе Visual Studio, не могут создать PostgreSQL в любом регионе; deploy.sh сообщает об этом, ещё ничего не создав. Выберите другой регион:

terraform.tfvars
location = "swedencentral"   # или northeurope, francecentral

4. Первый вход

Сразу откройте адрес из вывода url. Новая установка показывает страницу настройки, где создаётся первая учётная запись и задаётся имя команды, — так же, как на сервере, см. Установка ScanSuite Teams. Эта учётная запись достаётся тому, кто первым откроет страницу, поэтому web_allowed_cidrs задаётся до развёртывания.

Затем настройте поставщика ИИ в карточке Системный ИИ раздела Настройки системы → Общие сервисы (или для отдельной команды — в разделе Команды → ИИ → Поставщик ИИ), см. Поставщики ИИ и стоимость. Для Azure OpenAI выберите поставщика OpenAI, укажите адрес v1 вашего ресурса, https://<ресурс>.openai.azure.com/openai/v1, с его ключом API, а в качестве имени модели — имя развёртывания.

5. Повседневная работа

  • Изменить настройку: отредактируйте terraform.tfvars и снова запустите ./deploy.sh. Повторный запуск всегда безопасен, а пока образы не меняются, идущие сканирования продолжаются.
  • Новый выпуск: положите новый .lic в ../key/ и удалите старый, задайте в image_tag новый код, выполните git pull, а затем ./deploy.sh. Миграция отменяет незавершённые сканирования, поэтому обновляйтесь, когда сканирований нет.
  • Прерванные сканирования восстанавливаются сами: сканирование, контейнер которого остановил Azure, 90 минут не показывает прогресса, а затем запускается заново и продолжает AI-анализ с последнего сохранённого этапа.
  • Журналы: откройте рабочую область Log Analytics в группе ресурсов, выберите Logs и запросите ContainerAppConsoleLogs_CL по ContainerAppName_s (например, scansuite-web) или ContainerJobName_s (scansuite-sast для сканирований).
  • Экономия, когда установкой не пользуются: web_min_replicas = 0, а базу данных можно остановить командой az postgres flexible-server stop; через семь дней Azure запустит её сам.
  • Берегите состояние Terraform: в terraform.tfstate хранятся сгенерированные пароли и ваша лицензия. Держите файл в закрытом месте, делайте резервную копию после каждого развёртывания и перенесите его в Azure Storage, прежде чем развёртывать будет второй человек или конвейер CI.

Ориентировочная стоимость в месяц для настроек dev по умолчанию, в долларах США; цены для своего региона уточните в калькуляторе Azure:

СтатьяОриентировочно
Постоянно работающие контейнеры (веб, воркеры, планировщик, Redis)120–160
PostgreSQL B_Standard_B1ms, 32 ГБ20
Log Analytics, не больше 1 ГБ в день0–70
Реестр, Key Vault, хранилищеоколо 10
Сканирования, по 4 vCPU и 8 ГиБоколо 0,45 за час сканирования
NAT-шлюз, если включён35 плюс трафик

6. Удаление

Терминал
./destroy.sh

Скрипт просит ввести имя группы ресурсов и примерно за 15 минут удаляет всё, что создало развёртывание, включая базу данных со всеми результатами сканирований; -y отключает вопрос. После этого az group show -n <группа ресурсов> сообщает, что группа не найдена. Если скрипт остановился с сообщением polling support for the Content-Type "" was not implemented, Azure уже удалил то, что в нём названо: запустите скрипт снова, при необходимости два-три раза.

Частые сообщения

PostgreSQL Flexible Server 16 is not available to this subscription: пример E. ManagedEnvironmentCapacityHeavyUsageError: в регионе сейчас нет места для новой среды; удалите неудавшуюся (az containerapp env delete) и повторите позже или в другом регионе. no licence for image tag: положите .lic в ../key/ и приведите image_tag в соответствие с его кодом. could not import docker.io/appsec4u/...: задайте учётные данные реестра в той же оболочке. Provider produced inconsistent result after apply после повторного создания развёртывания с тем же именем группы ресурсов: возьмите новое имя или подождите 15 минут.

Проверено: 2026-10-01