Skip to content

feat(unified-identity): run self-hosted ZITADEL as the MCTL human identity provider #1499

Closed

Description

@mashkovd

Parent roadmap: mctlhq/.github#91

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.

Activity

  1. mashkovd commented on Oct 3, 2026

    @mashkovd
    MemberAuthor

    Deployed by #1502 (merge 5ea36d4), verified 2026-10-03 ~14:50 UTC:

    • https://auth.mctl.ai/.well-known/openid-configuration 200, issuer https://auth.mctl.ai; /ui/v2/login/healthy 200; /ui/console 200.
    • /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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions