You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(unified-identity): run self-hosted ZITADEL as the MCTL human identity provider #1499
Epic MCTL Unified Identity and Agent Identity Broker — manifest roadmap/epics/unified-identity.yaml, work item zitadel-deployment, phase federation.
Epic goal
Decouple MCTL principals from GitHub identity by introducing stable canonical identities for humans, agents and services, with linked external identities, swappable federation, CIMD-aware MCP OAuth and delegated agent identity.
Decision context
On 2026-10-03 the owner chose self-hosted ZITADEL as the MCTL human identity provider (mctlhq/.github#157). It enters as one more OIDC provider in the mctl-api federation registry (MCTL_OIDC_PROVIDERS, mctl-api#374 slice A, docs/federation.md), not as a broker in front of every request: static service tokens, local MCP OAuth JWTs and GitHub PATs stay verified by mctl-api itself. It replaces Argo CD's embedded Dex (ops.mctl.ai/api/dex) as the source of human sign-in.
Scope of this work item
Run self-hosted ZITADEL on the mctl cluster as the human identity provider: Postgres-backed (database provisioned like other platform services), secrets held in Vault, backups with a tested restore, health alerting, and its own hostname behind the existing ingress. Check the current ZITADEL release for its deployment shape (separate login UI service) and license (AGPL-3.0 since v3) before choosing the chart. Sign-in depends on it, so define the recovery path for an outage: break-glass admin and how existing GitHub/static-token access keeps working.
This issue binds the work item so the roadmap control plane (ready.py, health.py, the mctl-api wave planner) can observe it. Refine the scope on this issue; the manifest carries the dependency graph, not the prose.
Depends on
nothing: this item is a root of its phase
Completion
Required by the epic's allRequired rule. Closing this issue as completed marks zitadel-deployment done; closing it as not planned or duplicate keeps the epic incomplete by design.
/debug/metrics and /debug/healthz return 403 at the edge.
ArgoCD zitadel and shared-pg Synced/Healthy; zitadel-init (10s) and zitadel-setup (17s) completed as Sync hooks; Database zitadel-db applied.
VictoriaMetrics: probe_success{job="zitadel-public"} = 1 for both targets, up{namespace="zitadel"} = 1 (the scrape works without a Host header).
Vault seeded by bootstrap-platform-bfc8s (only the two zitadel paths were new). The first sync failed before the seed and recovered through the Application's retry.
Remaining operator step (runbook step 6): sign in as the break-glass admin and enrol a second factor.
Follow-ups in the epic: #1503 (reserve platform hostnames, before mctl-api#434), #1504 (tenant domain separation).
Activity
mashkovd commentedon Oct 3, 2026
Deployed by #1502 (merge 5ea36d4), verified 2026-10-03 ~14:50 UTC:
https://auth.mctl.ai/.well-known/openid-configuration200, issuerhttps://auth.mctl.ai;/ui/v2/login/healthy200;/ui/console200./debug/metricsand/debug/healthzreturn 403 at the edge.zitadelandshared-pgSynced/Healthy;zitadel-init(10s) andzitadel-setup(17s) completed as Sync hooks; Databasezitadel-dbapplied.probe_success{job="zitadel-public"}= 1 for both targets,up{namespace="zitadel"}= 1 (the scrape works without a Host header).Vault seeded by
bootstrap-platform-bfc8s(only the two zitadel paths were new). The first sync failed before the seed and recovered through the Application'sretry.Remaining operator step (runbook step 6): sign in as the break-glass admin and enrol a second factor.
Follow-ups in the epic: #1503 (reserve platform hostnames, before mctl-api#434), #1504 (tenant domain separation).