Policy rulings (#942): unique passwords, Cloudron-only SSO accounts, no reachableceo credentials, TOTP seeds MUST be captured to the vault. Cloudron admin API wrapper, cookie-jar OIDC login, RFC-6238-tested TOTP helper, per-system SSO/API references, incident log.
3.1 KiB
3.1 KiB
Cloudron admin API + OIDC (verified 2026-09-08)
Instance
- Dashboard:
https://my.knownelement.com(admin surface; this host also fronts the org's public vhosts — it is NOT the tailscale-only control box). - API token: vault item
creds/cloudron, password field, 64 chars, service userapi-token. Verified: reads full user directory.
Routes (this is a newer Cloudron — older route knowledge may not apply)
- Users are addressed by
uid-<uuid>, never username.GET /api/v1/users?limit=100→ list;GET /api/v1/users/<uid>→ object (twoFactorAuthenticationEnabledis null/absent on objects even when enforced — the OIDC interaction is the source of truth). - There is NO
POST /api/v1/login. Dashboard auth is its own OIDC browser flow; the SPA bundle (as of 2026-09-08) contains no login route. - There is NO admin route to reset another user's 2FA (PUT/PATCH/DELETE on
/users/<uid>2FA variants all 404; the dashboard UI only offers profile self-service enrollment). Consequence: TOTP seeds not captured at enrollment are unrecoverable without the founder. - Other useful routes seen in the SPA bundle:
/api/v1/tokens,/api/v1/oidc/clients,/api/v1/groups,/api/v1/eventlog,/api/v1/app_passwords. Verify behavior at runtime before relying on a specific payload shape.
OIDC interaction login (how identity SSO works)
The GLPI/Gitea/Discourse/Redmine SSO flows all redirect here:
GET <app SSO start point>→ 302 tohttps://my.knownelement.com/openid/interaction/<uid>(Cloudron runs a node-oidc-provider at/openid). Cookies matter — keep a cookie jar.POST /openid/interaction/<uid>/loginwith JSON{"username": "<login>", "password": "<unique password>"}.- Field name is
username—loginreturns"A username must be non-empty string"(400). - Success →
{"redirectTo": "..."}(or{"twoFactorRequired":true,"totpRequired":true}if 2FA is enabled). - Wrong credentials → 401
{"status":"Unauthorized","message":"Username and password does not match"}.
- Field name is
GETtheredirectTo(same cookie jar) → completes at the app.
Email-style usernames work (tsgstaff-coo@turnsys.com); bare usernames also
exist (coo). Identity emails follow tsgstaff-<login>@turnsys.com.
2FA
- TOTP enforced per user at the interaction step
(
twoFactorRequired/totpRequiredin the login response). - Enrollment is profile self-service ONLY. Capture the base32 seed into the
vault (
sm setfield "<login> Cloudron" totp_seed <seed>) at enrollment — there is no admin reset and no recovery path. - Policy RULED (founder, 2026-09-08): TOTP seeds MUST be stored in Bitwarden. Enroll 2FA only when the seed is being captured to the vault item in the same step. Legacy identities whose seeds were never captured (the whole August batch) are reset-on-sight candidates: founder clears 2FA or hands over the seed, then re-enroll with capture.
Records: Redmine #942 — https://projects.knownelement.com/issues/942 · Discourse docs home: https://community.turnsys.com (skill topic pending admin-key provisioning, tracked on #942)