The reconcile path was dead three ways, so no IAM change could ship at all and
console.lux.cloud stayed unreachable behind "invalid redirect_uri".
1. image sha-9e7cc0c predates `owner:` and rejected the document outright
("unknown field owner"). v1.34.40 is the semver the live IAM itself runs and
accepts every field here. Preferring the semver over a sha means the writer
and the store cannot silently drift apart.
2. the binary is /iam, not /iam2 — the old entrypoint failed as
"stat /iam2: no such file or directory".
3. --url pointed at iam.hanzo.svc, whose Deployment is scaled to 0: every write
died on "connection refused". id.hanzo.svc is not the answer either — it is
the STATIC white-label login site and answered the admin path with 200 and a
page of HTML ("invalid character '<'"). A 200 from a static site proves the
host is up, never that the API is there.
IAM is embedded natively in `cloud`; api.hanzo.ai/v1/iam is its public face.
That endpoint answers the admin path with JSON — 401 "a valid service token is
required" — so the route is real and only the credential was missing.
Converge now reports 13 app(s), 0 failed, and console.lux.cloud reaches the Lux
sign-in page instead of an authorization error.
Co-authored-by: Hanzo Dev <[email protected]>
107 lines
4.8 KiB
YAML
107 lines
4.8 KiB
YAML
# Applies Lux's IAM app graph (provision.yaml) to the live IdP.
|
|
#
|
|
# ONE source of truth: the ConfigMap this Job reads is generated FROM
|
|
# provision.yaml by `make iam-provision`, never hand-written, so the document
|
|
# in git is always what converged.
|
|
#
|
|
# It runs the OSS mechanism (`iam2 provision`, hanzoai/iam internal/provision)
|
|
# against Lux's data. The image is pinned — a Job that floats on :latest is not
|
|
# a deterministic deployment.
|
|
#
|
|
# The tag is sha-<7>, not v<X.Y.Z>, because that is what hanzoai/iam main
|
|
# actually publishes: its builder is .hanzo/workflows/image.yml on git.hanzo.ai
|
|
# (the canonical forge) and it tags by commit. The v<X.Y.Z> images come from a
|
|
# DIVERGED v1.33.x release line whose builder is deliberately disabled, so a
|
|
# v-tag cut on main produces no artifact at all — pinning one here would leave
|
|
# this Job permanently unschedulable.
|
|
#
|
|
# Runs in ns hanzo on hanzo-k8s because that is where the IAM that answers
|
|
# lux.id lives, and where the service token it authenticates with is stored.
|
|
# Re-running is a no-op: the upsert keys on <org>-<app> and preserves each
|
|
# client secret IAM already issued.
|
|
apiVersion: batch/v1
|
|
kind: Job
|
|
metadata:
|
|
name: lux-iam-provision
|
|
namespace: hanzo
|
|
labels:
|
|
app.kubernetes.io/name: lux-iam-provision
|
|
app.kubernetes.io/part-of: lux
|
|
spec:
|
|
# Keep the pod briefly so `kubectl logs job/lux-iam-provision` shows what
|
|
# converged; the run report IS the audit record.
|
|
ttlSecondsAfterFinished: 600
|
|
backoffLimit: 2
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app.kubernetes.io/name: lux-iam-provision
|
|
spec:
|
|
restartPolicy: Never
|
|
imagePullSecrets:
|
|
- name: ghcr-secret
|
|
containers:
|
|
- name: provision
|
|
# A pin is not free: it caps the vocabulary this repo may write in.
|
|
# sha-bb7eff5 predated `redirects:`/`grants:`; sha-9e7cc0c in turn
|
|
# predated `owner:` and rejected this document outright — the whole
|
|
# reconcile path was dead, so no IAM change could ship at all.
|
|
# v1.34.40 is the semver the live IAM itself runs and accepts every
|
|
# field here (plan: 13 apps, 0 failed). Prefer the semver over a sha:
|
|
# it is the tag the deployment is already pinned to, so the writer and
|
|
# the store can no longer drift apart silently.
|
|
# The binary is /iam here — /iam2 was its name before the rename, and
|
|
# the old entrypoint fails as "stat /iam2: no such file or directory".
|
|
image: ghcr.io/hanzoai/iam:v1.34.40
|
|
command: ["/iam"]
|
|
args:
|
|
- provision
|
|
- --config=/etc/iam-provision/provision.yaml
|
|
# The IAM SERVICE, not a public hostname. A public host resolves
|
|
# through DNS/CDN and may reach a different instance than the one
|
|
# the token endpoint reads — writing Lux's clients to a store the
|
|
# login never consults is silent and total: every converge reports
|
|
# success while every login keeps failing.
|
|
#
|
|
# `cloud` is that service. IAM is embedded in it natively, and
|
|
# api.hanzo.ai/v1/iam is its public face — the one the login reads.
|
|
#
|
|
# Two wrong targets were tried first and both are instructive.
|
|
# `iam.hanzo.svc` has NO endpoints (Deployment scaled to 0), so every
|
|
# write died on "connection refused" — loud, harmless. `id.hanzo.svc`
|
|
# is the STATIC white-label login site: it answered the admin path
|
|
# with 200 and a page of HTML, which decoded as
|
|
# `invalid character '<'`. A 200 from a static site proves the host
|
|
# is up, never that the API is there.
|
|
#
|
|
# The real backend is unambiguous: it answers this exact path with
|
|
# JSON — 401 {"msg":"a valid service token is required"} — so the
|
|
# route exists and only the credential is missing.
|
|
- --url=http://cloud.hanzo.svc:8000
|
|
env:
|
|
# The same unified service token the admin upsert endpoints
|
|
# validate. Never inlined — it is a credential.
|
|
- name: IAM_SERVICE_TOKEN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: iam-service-token
|
|
key: IAM_SERVICE_TOKEN
|
|
volumeMounts:
|
|
- name: doc
|
|
mountPath: /etc/iam-provision
|
|
readOnly: true
|
|
resources:
|
|
requests: { cpu: 10m, memory: 32Mi }
|
|
limits: { cpu: 200m, memory: 128Mi }
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
runAsNonRoot: true
|
|
runAsUser: 65532
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
volumes:
|
|
- name: doc
|
|
configMap:
|
|
name: lux-iam-provision
|