Skip to content

Instance access contract

Runtime/API contract

Optional AppInstance.spec.access.sharing:

access:
  authentication: sso
  role: user
  exposure: local
  sharing:
    mode: selected
    users: [11111111-1111-4111-8111-111111111111]
    groups: [22222222-2222-4222-8222-222222222222]

mode is all or selected. Each list has at most 100 unique IDs. all must have empty lists. Omitting sharing preserves the role-based behavior. An older client that omits the field while updating a restricted instance cannot erase its policy. Restricted-instance updates, deletion and sharing-policy changes require a live admin.

Route Access/meaning
GET /api/my-instances Any Magic Stick user; minimal granted instance names, phases and links
GET /api/instance-principals?kind=users\|groups&search=&first=0 Live admin; directory IDs/names, paginated in batches of 50
GET /api/instances/{name}/access Live admin; current sharing, labels, revision, guard readiness
PUT /api/instances/{name}/access Live admin + CSRF; {sharing, expectedRevision}; atomic Kubernetes resourceVersion update

Shared /api/instances, /api/appliance, /api/modules, /api/status and /api/events reads remove hidden instances and derived links/workload references. Credential requests independently check the grant. The CLI/TUI use the same filtered backend; assignment is offered in the React dashboard and CLI.

magicstick instance principals --kind users --search example --json
magicstick instance principals --kind groups --search team --json
magicstick instance access hermes-example --json
magicstick instance share hermes-example --file /path/to/policy.json --yes

The policy file contains only mode, users and groups. The CLI reads the current revision and sends it with the change; it never silently retries a conflict. Updates through the dedicated sharing endpoint emit a magicstick.instance-sharing audit event with actor ID, instance name, mode and result, without tokens or full membership lists. Kubernetes audit configuration is required for a complete lifecycle record, including initial instance creation and direct cluster writes.

Enforcement and rollout

The operator installs an Envoy HTTP external-authorization check for every instance route, including currently unrestricted routes. This avoids an old public route remaining usable when a restriction is first added. The check is bound to the AppInstance name and UID; a reused name does not reuse a grant. A restricted request verifies authenticated identity, live enabled status, effective role and current groups. Arbitrary identity headers from the browser are not trusted. Neither restricted nor unrestricted decisions require a license.

EnvoyProxy.spec.filterOrder places external authorization after JWT/OIDC authentication. SecurityPolicy.spec.extAuth.failOpen is false. The check is a ClusterIP-only internal route, not a public /api operation. Header/cookie authentication is validated by the API against Keycloak, even after Envoy auth. The guard returns an empty 200 OK only on success, as required by the Envoy HTTP authorization contract; other status codes, including 204, are not an authorization success.

The operator waits for the current, accepted guard policy before connecting its routes to an application backend. status.accessGuardReady reports that state; sharing changes return 409 while it is false. Update the packaged API image (including instance_access.py), backend ConfigMap, gateway filter order, CRD and controller together. Merely changing the frontend cannot enable this feature.

Coordinated runtime requirement: deployment pins must reference a published API containing instance_access.py and magicstick_core.sharing, with matching ConfigMap, CRD, controller and gateway policy. Update these together. A full Flux upgrade of a physical appliance is a separate acceptance check.

Failure Behavior
Keycloak/group lookup or API unavailable Private request denied; no fail-open fallback
No selected principals No app access, including for admin unless explicitly granted later
API outage Instance edge checks fail closed, including unrestricted routes; restore API availability
User/group grant removed Subsequent requests denied; no stored ACL membership cache
Policy missing (ordinary instance) Existing SSO/role/exposure behavior; no entitlement requirement

License expiry does not affect Resource Sharing. An identity or ACL change does not interrupt an already accepted streaming HTTP request or WebSocket; enforcement is on new requests. Never remove policies as an automatic recovery action.

This is not Kubernetes tenant isolation. Cluster administrators and operators with direct workload/Secret/CR permissions, port-forward access or network access to a backend can bypass the HTTP entry point. Existing arbitrary-code/agent workloads are not made mutually isolated by these UI ACLs. Do not grant such privileges to mutually untrusted tenants; network/workload isolation requires a separate design. External identity federation is also not added here.