Identity and security¶
Magic Stick uses a local-first identity architecture. Keycloak is the local OpenID Connect (OIDC) provider and identity broker. Envoy Gateway enforces the login before a protected HTTP route reaches an application. The appliance can therefore authenticate users while fully disconnected from cloud services.
Envoy Gateway is the only installed application gateway. The dashboard, all
operator-managed AppInstances, LiteLLM, AnythingLLM, and the KubeOpenCode
server use authenticated Gateway API resources. The bundled installation
contains no application Ingress resources.
Target Architecture¶
Browser
-> Envoy Gateway
-> OIDC login at local Keycloak
-> local user database (offline)
-> optional upstream Entra ID, Google, AWS, or another OIDC/SAML IdP
-> authenticated request to dashboard or application
kubectl
-> OIDC exec credential plugin
-> the same local Keycloak login and optional upstream broker
-> short-lived ID token with direct Magic Stick Kubernetes groups
-> Kubernetes API server OIDC authentication and RBAC
magicstick CLI or TUI
-> public Keycloak device-flow client
-> browser verification or a URL plus one-time code
-> short-lived access token with the same Magic Stick realm roles
-> Envoy JWT policy on api.<mDNS-domain>
-> dashboard control-plane API authorization
Applications trust one stable local issuer. External enterprise identity providers are configured as upstream identity providers in Keycloak rather than integrated separately into every application. Replacing an upstream provider therefore does not change application routes or their OIDC clients.
Supported operating modes are:
| Mode | Login path | Internet required |
|---|---|---|
| Local standalone | Keycloak local account | No |
| Brokered enterprise | Keycloak forwards to Entra ID, Google, AWS, or another supported IdP | Only for the selected upstream IdP |
| Direct external provider | A deployment overlay replaces the OIDC provider settings at the gateway | Yes; intended as an escape hatch |
The recommended production mode is local Keycloak with optional upstream brokering. Keep at least one protected local break-glass administrator account so an upstream outage does not lock administrators out of the appliance.
Authorization Model¶
The local realm defines four initial roles:
| Role | Intended access |
|---|---|
magicstick-user |
Authenticated application user; minimal dashboard My instances launchpad |
magicstick-viewer |
Read-only dashboard and status access |
magicstick-operator |
Runtime application and model operations |
magicstick-admin |
Identity, security, and appliance administration |
Authentication and authorization remain separate. Envoy proves the identity
and forwards the OIDC access token only to backends that consume it. The
dashboard API validates that token with Keycloak and checks the relevant role
before every operation. LiteLLM remains protected by the same edge login and
role policy, but does not receive the OIDC token in Authorization because that
header belongs to LiteLLM's own Bearer sk-... API authentication. Upstream
groups should be mapped to the local Magic Stick roles in Keycloak.
Dashboard access is hierarchical: viewer permits read-only endpoints, operator
also permits module, instance, model, and credential operations, and admin also
permits appliance-wide settings and human-user administration. magicstick-user
alone receives only the dashboard My instances launchpad and its minimal
session/instance API; it does not grant control-plane or status access.
AppInstance access uses the same hierarchy at the Envoy edge. OIDC stores the
Keycloak access token in the shared MagicStickAccessToken cookie; Envoy's JWT
filter validates that token and authorizes the selected minimum
realm_access.roles value before forwarding to the application. A route can be
made unauthenticated only with explicit spec.access.authentication: none.
The core instance-sharing capability adds allow-lists of stable Keycloak user and group IDs. For restricted instances, the API and gateway guard also verify live user status, effective minimum role, group membership (including subgroups). No license file is required for instance sharing. Administrators retain management visibility, but require an explicit grant to use the app or retrieve its private credentials. These are HTTP access controls, not Kubernetes tenant/network isolation.
Human browser sessions use OIDC Authorization Code Flow. Human kubectl
sessions use a separate public PKCE client and an exec credential plugin. The
Magic Stick CLI and TUI use a third public client with Device Authorization
Flow and send its Bearer access token to the dedicated control-plane API route.
None of these clients reuse browser cookies, client secrets, or each other's
client ID. Unattended machine integrations still need their own policy and
credential lifecycle; a renewable human device session is not a service
account.
Implemented Scope¶
The current implementation provides:
- Envoy Gateway
v1.8.2as the primaryLoadBalancerdata plane - Keycloak with PostgreSQL in namespace
identity-system - runtime-generated database, bootstrap-admin, and OIDC client secrets
- a first-run wizard that creates the first human and recovery administrators without storing their passwords in Kubernetes
- a scoped Keycloak setup service account for first-run and callback reconciliation
- a separate
magicstick-user-adminservice account for dashboard user administration; it has user-query and user-management roles but no client, realm, impersonation, or identity-provider administration role - a separate
magicstick-federation-adminservice account for licensed dashboard federation; it has only identity-provider view/manage plusview-realm, and no user, client, realm-management, or impersonation role - an appliance-local identity CA and a CA-signed certificate for local
.localhostnames; the public CA can be embedded in OIDC kubeconfigs - an unprotected Keycloak route and a protected
auth-pilottest route - protected local and public dashboard
HTTPRouteresources - operator-generated local and public AppInstance
HTTPRouteresources with default SSO and optional user/viewer/operator/admin minimum roles - removal of edge-managed OIDC cookies before requests reach the Hermes API
gateway; authorization is completed at Envoy and the access token is
forwarded in the
Authorizationheader - per-instance callback routes on the shared dashboard hosts, so the same Keycloak client and browser session protect dynamically created instances
- a non-blocking Keycloak startup reconciliation that adds the callback path patterns needed by existing installations
- dashboard API token validation, a minimal user launchpad and viewer/operator/admin authorization
- a public
magicstick-clidevice-flow client and the JWT-protected, mDNS-publishedapi.<mDNS-domain>route used by the CLI and TUI - protected local and public routes for LiteLLM, AnythingLLM, and KubeOpenCode
with a minimum
magicstick-userrole - LiteLLM-specific OIDC token forwarding disabled after edge authorization, so
its UI and API retain their own virtual-key
Authorizationheader - removal of the bundled dashboard and AI application
Ingressresources - no human default password on new installations
- a public PKCE client
magicstick-kubernetes, agroupstoken mapper, and direct Viewer/Operator/Administrator groups for human Kubernetes access
The dashboard API accepts access tokens only when their azp is the browser
gateway client or magicstick-cli, their issuer matches the local realm, they
are unexpired, Keycloak still accepts them through userinfo, and the required
realm role is present. The edge JWT policy is an additional validation layer,
not a replacement for API authorization.