Установка через Wizard¶
Wizard — официальный Go-инсталлер AppSec.GenAI v2, упакованный в Docker-образ. Управляет полным жизненным циклом: namespace, pull-secret, инфраструктура, продуктовые сервисы — в правильном порядке.
Docker Compose
Инструкция по развёртыванию на отдельном сервере через Docker Compose — в разделе Установка и запуск.
Режимы развёртывания¶
- Keycloak и Envoy Gateway не устанавливаются
- Все сервисы работают в
DEV_MODE— аутентификация отключена - Доступ через
kubectl port-forwardили ingress-nginx - TLS не требуется
- Keycloak + OIDC через Envoy Gateway
- JWT-аутентификация во всех сервисах
- Требует: wildcard TLS-сертификат и DNS на 3 хоста
Быстрый старт: интерактивный Wizard¶
docker run --rm -it \
-v ~/.kube/config:/kubeconfig:ro \
-v $(pwd):/workspace \
registry.appsec.global/appsecgenai-release/wizard:<VERSION> \
wizard
OIDC / exec-based auth
Если ~/.kube/config использует OIDC (auth-provider: name: oidc) или exec-плагин (exec: command: d8/kubelogin/...) — wizard не сможет подключиться: внешние бинари недоступны в контейнере. Нужен kubeconfig со статическим Bearer-токеном.
Получите токен из вашего OIDC-провайдера (пример для Deckhouse/dex):
TOKEN=$(d8 login get-token ... | python3 -c "import sys,json; print(json.load(sys.stdin)['status']['token'])")
Создайте ~/kube-wizard.yaml и подставьте токен в поле user.token:
apiVersion: v1
kind: Config
current-context: my-cluster
clusters:
- cluster:
server: https://api.<cluster-domain>
name: my-cluster
contexts:
- context:
cluster: my-cluster
namespace: genai
user: wizard
name: my-cluster
users:
- name: wizard
user:
token: <TOKEN>
Монтировать: -v ~/kube-wizard.yaml:/kubeconfig:ro
Токен живёт ~1h — при истечении пересоздать.
Wizard задаёт 7 вопросов и записывает values.yaml в текущую директорию:
AppSec GenAI — Setup Wizard
────────────────────────────
Domain: app.example.com
Namespace [genai]:
Enable auth (Keycloak + Envoy OIDC)? [y/N]: n
Expose via ingress-nginx? [y/N]: n
Enable persistence (required for production)? [y/N]: y
StorageClass (leave blank for cluster default):
✓ values.yaml written
Run install now? [Y/n]: y
Куда записывается values.yaml
Инсталлер внутри контейнера обнаруживает /workspace и пишет файл туда — он появляется в текущей директории хоста благодаря монтированию -v $(pwd):/workspace.
По окончании wizard выводит endpoints:
UI: https://app.example.com
Keycloak: https://keycloak.example.com
MinIO: https://minio.example.com
DNS records (все → gateway.externalIPs[0]):
app.example.com
keycloak.example.com
minio.example.com
Пароль bootstrap-пользователя genai-admin:
kubectl -n genai get secret keycloak-auth \
-o jsonpath='{.data.KEYCLOAK_BOOTSTRAP_USER_PASSWORD}' | base64 -d
Установка из готового values.yaml¶
docker run --rm \
-v ~/.kube/config:/kubeconfig:ro \
-v ./values.yaml:/values.yaml \
-e HARBOR_PASS="<пароль>" \
registry.appsec.global/appsecgenai-release/wizard:<VERSION> \
install --harbor-user "<логин>" -f /values.yaml
Команды¶
| Команда | Описание |
|---|---|
wizard |
Интерактивный ввод → values.yaml → опциональный install |
install |
Полная установка всех компонентов |
update |
Умный апгрейд — пропускает релизы без изменений |
update --force |
Принудительный апгрейд всех релизов |
delete |
Удалить все Helm-релизы (PVC сохраняются) |
check |
Pre-flight проверки без изменений |
Флаги¶
| Флаг | По умолчанию | Описание |
|---|---|---|
-f <path> |
values.yaml |
Путь к конфигурации |
--dry-run |
false |
Отрендерить без применения |
--only <a,b> |
— | Только указанные фазы |
--skip <a,b> |
— | Пропустить фазы |
--set key=value |
— | Переопределить значение |
--harbor-user |
— | Логин Harbor для pull-secret |
--harbor-pass |
$HARBOR_PASS |
Пароль Harbor |
--parallel N |
4 |
Параллельность Phase 2 |
--release-version |
вшита в образ | Переопределить версию чартов |
Пароль Harbor через env
Передавайте пароль через -e HARBOR_PASS="...", не через --harbor-pass (чтобы не светить в ps aux).
values.yaml — справочник¶
Обязательные параметры¶
| Параметр | Валидация | Описание |
|---|---|---|
domain |
required, не app.customer.com |
Базовый домен инсталляции |
namespace |
required | Kubernetes namespace (default: genai) |
Полная схема¶
# ─── Базовые ────────────────────────────────────────────────────────────────
domain: "app.example.com" # ОБЯЗАТЕЛЕН
namespace: "genai"
instance: "" # суффикс для мультиинсталляций
# ─── Аутентификация ─────────────────────────────────────────────────────────
auth:
enabled: false # false = dev, true = prod (Keycloak + Envoy)
gateway: # заполнять только при auth.enabled: true
publicScheme: "https" # http | https
externalIPs: [] # bare-metal: ["10.0.0.1"]; cloud: []
className: "genai-class" # уникален в кластере
name: "genai"
proxyName: "envoy"
controllerVersion: "v1.5.1"
autoInstall: true # false = BYOC (ваш Envoy Gateway)
managed: true # false = routes-only
# ─── Доступ извне ────────────────────────────────────────────────────────────
ingress:
enabled: false # только при auth=false
className: ""
ingressTlsSecretName: "" # при auth=true + https
imagePullSecretName: "harbor-cr"
# ─── Секреты ─────────────────────────────────────────────────────────────────
secrets:
create: true # false = создать Secret'ы вручную до запуска
# ─── Инфра-компоненты ────────────────────────────────────────────────────────
postgres:
enabled: true
auth:
username: genai_admin
database: genai_db
persistence: { enabled: false, size: "50Gi", storageClass: "" }
redis:
enabled: true
persistence: { enabled: false, size: "2Gi", storageClass: "" }
nats:
enabled: true
persistence: { enabled: false }
minio:
enabled: true
persistence: { enabled: false, size: "200Gi", storageClass: "" }
keycloak:
enabled: true # только при auth.enabled: true
persistence: { enabled: false, size: "1Gi", storageClass: "" }
# ─── Внешняя инфраструктура ──────────────────────────────────────────────────
global:
image:
registry: "registry.appsec.global"
repositoryPrefix: "appsecgenai-release"
deps:
postgres:
host: postgres
port: 5432
existingSecret: postgres-auth
username: genai_admin
database: genai_db
# bootstrap: true # создать схемы в существующей БД
redis:
host: redis
port: 6379
existingSecret: redis-auth
nats:
host: nats
port: 4222
# scheme: tls # tls:// если внешний NATS за TLS (default: nats://)
# bootstrap: true # создать 6 JetStream streams
minio:
host: minio
port: 9000
existingSecret: minio-auth
# scheme: https # https если внешний MinIO за TLS (default: http)
# bootstrap: true # создать 10 S3 buckets
keycloak:
host: keycloak
port: 8080
# scheme: https # https если внешний Keycloak за TLS (default: http)
# bootstrap: true # создать realm appsec-genai
# ─── Опционально ─────────────────────────────────────────────────────────────
license:
centerPublicKey: "" # RSA-2048 pubkey от SwordFish Security
tracing:
enabled: false # true требует otel-collector в кластере
bootstrap: идемпотентность
Операции bootstrap безопасны для повторного запуска — бакеты, потоки и realm создаются с IF NOT EXISTS / --ignore-existing (409 Conflict = пропуск). Оставить bootstrap: true на каждый update — нормально.
Когда нужен bootstrap:
| Ситуация | Нужен? |
|---|---|
Встроенный сервис (enabled: true) |
Нет — Helm hook jobs инициализируют автоматически |
Внешний сервис (enabled: false), первый install |
Да |
Внешний сервис (enabled: false), повторный update |
Оставить true (безвредно) или убрать (тоже нормально) |
Секреты инфра-компонентов¶
Что делает secrets.create¶
secrets.create |
Компонент enabled |
Кто создаёт Secret | Что делает Wizard |
|---|---|---|---|
true (default) |
true |
Infra-чарт автоматически при helm install |
Ничего дополнительно |
false |
true |
Вы — до запуска install | Preflight проверяет наличие |
| любое | false (внешний) |
Вы — всегда вручную | Preflight НЕ проверяет |
Внешний сервис — всегда ручной Secret
При postgres.enabled: false / redis.enabled: false / minio.enabled: false Wizard не создаёт никаких Secret'ов вне зависимости от secrets.create. Secret нужно создать самостоятельно до запуска.
Для чего existingSecret в global.deps.*¶
existingSecret — это имя K8s Secret'а, из которого продуктовые сервисы (jailbreak, results, orchestrator и т.д.) будут читать credentials при старте. Это не путь, не URL — просто имя объекта в namespace.
- При
secrets.create: trueинфра-чарт сам создаёт Secret с этим именем. - При
secrets.create: falseили внешнем сервисе — вы создаёте Secret с этим именем сами.
Менять existingSecret нужно только если вы хотите использовать другое имя Secret'а (например, интеграция с ESO / Vault, где секрет уже существует под другим именем).
Какие ключи должны быть в каждом Secret'е¶
| Secret | Ключ | Значение | Кто читает |
|---|---|---|---|
postgres-auth |
POSTGRES_PASSWORD |
пароль пользователя БД | все сервисы с БД |
redis-auth |
REDIS_PASSWORD |
пароль Redis | сервисы с Redis |
minio-auth |
MINIO_ROOT_USER |
access key (3–20 символов) | сервисы с S3 |
minio-auth |
MINIO_ROOT_PASSWORD |
secret key (8+ символов) | сервисы с S3 |
Postgres: пароль, не URL
В postgres-auth хранится только пароль (POSTGRES_PASSWORD). Полный DATABASE_URL продуктовые сервисы собирают сами из нескольких источников:
host,port,username,database— берутся изglobal.deps.postgres.*в values.yamlPOSTGRES_PASSWORD— читается из Secretpostgres-authчерезsecretKeyRef- Итог:
postgresql+asyncpg://{username}:{POSTGRES_PASSWORD}@{host}:{port}/{database}
Класть полный URL в секрет не нужно и не поддерживается в wizard-режиме.
Pre-create команды (при secrets.create: false или внешнем сервисе)¶
# PostgreSQL
kubectl create secret generic postgres-auth -n genai \
--from-literal=POSTGRES_PASSWORD='<strong-password>'
# Redis
kubectl create secret generic redis-auth -n genai \
--from-literal=REDIS_PASSWORD='<strong-password>'
# MinIO
kubectl create secret generic minio-auth -n genai \
--from-literal=MINIO_ROOT_USER='<access-key>' \
--from-literal=MINIO_ROOT_PASSWORD='<secret-key>'
Если используете нестандартное имя Secret'а — укажите его в global.deps.*.existingSecret.
Фазы установки¶
| Фаза | Имя | Что делает | Пропускается |
|---|---|---|---|
| Pre-flight | preflight:secrets |
Проверяет Secret'ы | при secrets.create: true |
| Pre-flight | preflight:gateway |
Проверяет Envoy Gateway | никогда |
| Phase 1 | phase1:infra |
postgres, redis, nats, minio, keycloak | — |
| Phase 1.1 | phase1.1 |
Bootstrap внешних сервисов | если *.bootstrap не задан |
| Phase 1:secrets | phase1:secrets |
Создаёт Secret'ы | при secrets.create: false |
| Phase 1.5 | phase1.5:genai-gateway |
Envoy Gateway + OIDC | при auth=false |
| Phase 2 | phase2:product |
11 продуктовых сервисов | — |
| Phase 2.5 | phase2.5 |
Ingress-ресурсы | при auth=true или ingress=false |
Частичный запуск¶
# Только продуктовые сервисы (после hotfix образа)
docker run --rm ... install --only phase2:product
# Пропустить инфраструктуру
docker run --rm ... install --skip phase1:infra,phase1.1
# Переопределить значение на лету
docker run --rm ... install --set tracing.enabled=true
Pre-flight проверки¶
docker run --rm \
-v ~/.kube/config:/kubeconfig:ro \
-v ./values.yaml:/values.yaml \
registry.appsec.global/appsecgenai-release/wizard:<VERSION> \
check -f /values.yaml
CHECK STATUS MESSAGE
----- ------ -------
gateway:envoy OK Envoy Gateway controller running
postgres WARN storageClass is empty — will use cluster default
phase1:infra OK infra config looks good
✓ all checks passed
| Статус | Значение |
|---|---|
OK |
Проверка пройдена |
WARN |
Установка продолжится, стоит обратить внимание |
FAIL |
Критическая ошибка — установка прервётся |
Обновление¶
# Умный апгрейд (пропускает релизы без изменений)
docker run --rm \
-v ~/.kube/config:/kubeconfig:ro \
-v ./values.yaml:/values.yaml \
registry.appsec.global/appsecgenai-release/wizard:<NEW_VERSION> \
update -f /values.yaml
# Принудительный апгрейд (hotfix под тот же semver)
docker run --rm ... update --force -f /values.yaml
Версия инсталлера = версия продукта
Тег образа Wizard определяет версию всех Helm-чартов. Для апгрейда достаточно поменять тег — версия в values.yaml не указывается.
Проверка установки¶
# Статус подов
kubectl get pods -n genai
# Healthcheck через port-forward (auth=false)
kubectl port-forward svc/ui 8080:8080 -n genai &
curl http://localhost:8080/
# Пароль bootstrap-пользователя (auth=true)
kubectl -n genai get secret keycloak-auth \
-o jsonpath='{.data.KEYCLOAK_BOOTSTRAP_USER_PASSWORD}' | base64 -d
Удаление¶
docker run --rm \
-v ~/.kube/config:/kubeconfig:ro \
-v ./values.yaml:/values.yaml \
registry.appsec.global/appsecgenai-release/wizard:<VERSION> \
delete -f /values.yaml
PVC сохраняются
Команда delete удаляет Helm-релизы, но не PVC. Для полного удаления:
Устранение неполадок¶
ImagePullBackOff¶
kubectl delete secret harbor-cr -n genai 2>/dev/null || true
kubectl create secret docker-registry harbor-cr -n genai \
--docker-server=registry.appsec.global \
--docker-username=<логин> --docker-password=<пароль>
FAIL: gateway:envoy-required¶
При auth.enabled: true требуется Envoy Gateway:
helm install envoy-gateway \
oci://docker.io/envoyproxy/gateway-helm \
--version v1.5.1 -n envoy-gateway-system --create-namespace