Documentation
¶
Overview ¶
Package iam is Hanzo's identity provider: users, organizations, applications, and the OIDC/OAuth2 endpoints every Hanzo service authenticates against.
It folds Hanzo IAM into the unified hanzoai/cloud binary as an in-process subsystem (HIP-0106) — the LAST binary-consolidation piece: "one Go binary (hanzoai/cloud) embeds IAM + KMS + o11y".
CLEAN IAM (v2). This subsystem embeds github.com/hanzoai/iam — the clean-room identity rewrite on the native Hanzo stack (zip + hanzoai/orm + hanzoai/sqlite). The retired Beego fork (github.com/hanzoai/iam-v1) is GONE from cloud's graph: there is no beego process-global to corrupt, no InitEmbed, no session-manager hook, no shared-AppConfig co-residence hazard with the sibling `ai` legacy fork. The whole IAM v2 surface (OIDC discovery/JWKS, oauth authorize/token/userinfo/introspect/revoke, get-app-login, signin, the v2 entity CRUD, and the legacy verb-alias compat layer) is served by iamserver.Handler — that standalone app adapted to net/http and hung on the wildcards this file registers (safeMount, which says why Handler and not iamserver.Route). The specific self-service routes layered in front (account, agentskills) still win, because zip matches the most specific pattern, so the fold is collision-free.
It is therefore OPAQUE to cloud's document: the nested app holds 94 typed ops and cloud's route table holds five wildcards, so none of the 35 operations the iam subset publishes can become a typed op. apps/iam/typed_wire_test.go gates that, and cloud's LLM.md ("apps/iam (0 of 25, and why)") records what closing it needs.
The store is embedded SQLite under {DataDir}/iam (server.OpenSQLite, WAL) — this embed owns its OWN orm.DB outright, so the old fork's "ai bootstrap unable to open database file (14)" crash is gone. Config (orgs/apps/providers/signing certs) is seeded from the same init_data.json the deployment already provides (server.Seed, new-only + idempotent), so hanzo.id's OAuth/OIDC semantics are preserved.
IN-PROCESS STORE ACCESS. DB() exposes the opened orm.DB to sibling subsystems that REFLECT the IAM-owned Project resource in-process (clients/platform, clients/deploy) via github.com/hanzoai/iam/pkg/store — no HTTP hop to /v1/iam. It is nil until Mount runs (the same lifecycle the retired iam-v1 object-store global ormer had), so those callers guard a nil DB and degrade to a clean 503 until IAM is mounted.
FAIL-CLOSED, NOT FAIL-LOUD. A broken/misconfigured IAM does NOT crash the consolidated binary: an open/seed/mount failure degrades THIS subsystem to a 503 fail-closed on every IAM prefix (mountFailClosed) while every co-resident subsystem (KMS, o11y, …) stays up — the blast-radius isolation the whole consolidation exists for, mirroring the KMS "no master key → health-only" pattern.
Mounted in-process (the whole IAM v2 surface, registered at its canonical paths):
/v1/iam/* OIDC/OAuth2 (/v1/iam/oauth/{authorize,token,userinfo,introspect,
revoke,...}) + OIDC discovery (/v1/iam/.well-known/*) + signin +
get-app-login + the v2 entity CRUD + the legacy verb-alias compat
/login/oauth/* browser authorize surface (the /v1/iam/oauth/authorize 302 target)
STAGING (security-critical): activation is the standard enable-list gate — the operator adds "iam" to the cloud deployment's --enable only AFTER the v2 config (init_data + KMS signing keys) is present and the fold is verified (login/authorize/token/jwks + the operator SSO chain). Until then hanzo.id is served by the standalone iam pod via ingress. If a broken config slips through, the subsystem serves 503 fail-closed rather than crashing cloud.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Prefixes = []string{
"/v1/iam",
"/login/oauth",
}
Prefixes are the canonical absolute prefixes the IAM identity surface owns — this subsystem's own list, from which patterns() derives every address it registers, both the real routes (safeMount) and the fail-closed 503 (mountFailClosed). Everything outside them belongs to cloud, so the console catch-all keeps serving the SPA.
The host has a SECOND list and that is deliberate, the same split apps/commerce documents: manifest.Apps' iam row states what the light host's ROUTER may hand this binary (manifest/apps.go), while this states what the binary itself serves and fail-closes. Importing one into the other would re-fatten the host, which links manifest and zip and nothing else. They are not required to be equal, and today are not: the router does not name /.well-known, which manifest/router_test.go records in its `unreachable` ledger.
The bare /healthz is deliberately excluded — it is a shared-liveness path, not an auth surface, so 503-ing it would mask the binary's own health rather than an identity outage. It is also why iam2 must not be co-mingled: iam2 serves its OWN /healthz, which silently took over the shared binary's.
Functions ¶
func DB ¶
DB returns the embedded IAM store's orm.DB for in-process readers (clients/platform, clients/deploy) that reflect the IAM-owned Project resource via github.com/hanzoai/iam/pkg/store. It is nil until Mount has run (IAM not enabled, or a boot failure that fail-closed the subsystem); callers MUST nil-guard and degrade to 503 rather than dereference it.
Types ¶
This section is empty.