feat(hermes): API-сервер и маршрут на него, OIDC дашборда через Zitadel, readOnlyRootFilesystem #70
Loading…
Reference in a new issue
No description provided.
Delete branch "refs/pull/70/head"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что это
Второй шаг переноса агента: наружу через Envoy отдаётся API-сервер, у дашборда basic-auth заменяется на Zitadel, контейнер переводится на
readOnlyRootFilesystem.Файлы
app/helmrelease.yamlreadOnlyRootFilesystem,/runкак emptyDir + initContainer, readiness на 8642app/externalsecret.yamlhermes-oidcиз Vaultkv/ai/hermesapp/httproute.yamlhermes.${SECRET_DOMAIN}:/v1и/health→hermes-app:8642, остальное →hermes-dashboard:9119app/kustomization.yamlks.yamldependsOn: external-secrets-stores/securityМаршрутизация: почему по путям, а не отдельным хостом
API живёт на том же домене (правило владельца), а бэкенды у двух сервисов пересекаются только частично:
/api/*:/api/auth/*,/api/status,/api/health,/api/sessions,/api/config/*,/api/tools/*,/api/logs,/api/cron/*,/api/plugins/*,/api/ws, плюс свой UI и колбэк/auth/callback;/v1/*(chat/completions,responses,models,skills,toolsets,health) и/health.Непересекающиеся префиксы
/v1и/healthуходят на 8642, всё остальное — на дашборд. Служебные эндпоинты API/api/sessionsи/api/jobs(у дашборда есть свои одноимённые) снаружи не публикуются — они остаются доступны внутри кластера наhttp://hermes-app.grachevko.svc.cluster.local:8642. Если понадобятся снаружи — отдельная задача сURLRewriteпо префиксу.Что проверено по исходникам, а не по документации
gateway/platforms/api_server.py:3844— «Return True when API_SERVER_KEY is present and strong enough to start»,:3847— «Refusing to start: API_SERVER_KEY is required for the API server». Ключ остаётся (он есть в.env, 64 символа), поэтому на/v1и/healthOIDC не вешаем: браузерный логин машинным клиентам не подходит.plugins/dashboard_auth/self_hosted/__init__.py:270-276читаетHERMES_DASHBOARD_OIDC_ISSUER+HERMES_DASHBOARD_OIDC_CLIENT_ID(илиdashboard.oauth.self_hosted.*).redirect_uriобязан заканчиваться на/auth/callback(plugins/dashboard_auth/_shared.py:100).hermes_cli/web_server.py:471иhermes_cli/main_dashboard.py:428. Вариант «выключить встроенную аутентификацию и повесить SecurityPolicy OIDC на маршрут» недостижим: либо OIDC-провайдер самого Hermes (этот PR), либо двойной логин.client_id/client_secretподставляются черезsecretKeyRef … optional: true: пока ключа в Vault нет, провайдер не регистрируется и работает basic-auth из.env. СтрокиHERMES_DASHBOARD_BASIC_AUTH_*убираются из.envтолько после успешного входа через Zitadel.readOnlyRootFilesystem: у s6-overlay вне тома есть ровно одно изменяемое место —/run; оно отданоemptyDir, владельца возвращает initContainer. Паттерн (RO rootfs +drop: ALL+/runи/tmpкак emptyDir) взят из публичного home-ops на 119 звёзд, а не выдуман.Что нужно сделать вне GitOps
hermes config set network.force_ipv4 trueиhermes config set dashboard.public_url https://hermes.grachevko.ru.https://hermes.grachevko.ru/auth/callback; в Vaultkv/ai/hermesдобавленoidc-client-id(секрет не нужен — PKCE).HERMES_DASHBOARD_BASIC_AUTH_*из/opt/data/.env.Проверка после мрежа
kubectl -n grachevko get pods— подReady 1/1, 0 рестартов; initContainerfix-runотработал.HERMES_DASHBOARD_READY port=9119; при заполненномhermes-oidcдашборд регистрирует self-hosted OIDC-провайдер.https://hermes.${SECRET_DOMAIN}/— вход через Zitadel;https://hermes.${SECRET_DOMAIN}/healthи/v1/models— сAuthorization: Bearer $API_SERVER_KEY.Откат
Реверт PR возвращает basic-auth-режим и прежний маршрут: провайдер не регистрируется,
.envдо отдельного шага не меняется.hermes referenced this pull request2026-09-24 15:32:30 +00:00