Skip to content

Identity and Execution Model

The application separates UI access from storage execution. A UI role decides which workspace can be opened; the selected execution context decides which credentials perform S3, IAM, or RGW operations.

Separation of identities

Identity What it controls Examples
UI identity Workspace visibility, Admin settings, Manager tool access, and audit actor. ui_none, ui_user, ui_admin, ui_superadmin, UI groups, can_access_storage_ops, can_access_ceph_admin.
Execution context Credentials and account scope used by storage actions. RGW account, S3 connection, S3 user, session context, Ceph Admin endpoint.
Portal grant model User-facing Storage Space visibility and role. Private Owner, team Viewer/Editor grants, project Manager, Portal account links.
Backend workflow identity Explicit technical credential used for controlled orchestration. Portal IAM provisioning, healthchecks, cost, quota, key rotation.

UI sessions are represented by auth_sessions and single-use refresh_tokens. external_identities binds an immutable provider subject to a user; email collisions are held in external_identity_link_requests for superadmin approval. users.auth_version is the immediate invalidation boundary for password, role, activation, MFA, and external-identity changes.

Personal storage identity contract

  • Every human operator uses a dedicated IAM identity or owned private S3 connection; credentials are never shared between people.
  • One personal identity may temporarily have multiple keys during rotation. Every key must still identify that same person and be retired after rotation.
  • Portal already executes S3 operations with the signed-in user's personal IAM identity. Portal external access is assigned to one named person and must preserve that attribution.
  • Deactivating a UI user immediately removes any provisioned personal Portal IAM identity and its keys. Portal account roles and Storage Space ownership remain canonical in the database; reactivation provisions IAM lazily on the next Portal use.
  • Application audit identifies control-plane actors. Object-level attribution comes from provider S3 access logs. Without provider logging and retention, the application cannot reconstruct an exhaustive object audit trail.

Context and executor

RGW Account IDs are independent of Ceph tenant names. S3Account, S3User persist rgw_tenant canonically: '' is the default tenant and non-empty values are explicit Ceph tenant names. Database-backed principals never use NULL for tenant scope. Transient execution contexts may still have no tenant until an access-key identity has been resolved. RGW users are identified by endpoint, tenant and UID. Admin Ops user/key/quota and usage requests use tenant$uid; merely adding a separate tenant query parameter does not scope those operations on Ceph. Owner-scoped bucket-info and bucket quota derive the tenant from the qualified owner UID and keep the bucket name unprefixed, as required by Squid bucket statistics. Ownerless bucket identifiers and index operations use tenant/bucket. Account-ID operations keep the Account ID as their scope.

S3 Connections persist an optional structured RGW identity. rgw_user_uid stores an unqualified RGW user UID and rgw_tenant stores its Ceph tenant ('' for the default tenant); rgw_account_id independently stores an RGW Account ID when one is known. A connection may carry user identity, Account identity, or both. User-scoped Admin Ops use tenant$uid; an Account-only identity uses the Account ID for account-scoped IAM and metrics. When persisted identity is absent, Runtime Read Ops may resolve it from the connection access key. Supervision collectors never acquire Admin Ops credentials for this discovery. Administrative mutations verify the exact principal and stored key before changing it. Rotation journals preserve the tenant and reject a changed tenant on resume. Physical bucket identities and metric aggregation keys include the tenant instead of dropping UID prefixes.

For RGW buckets, the canonical physical identity is (endpoint_id, tenant, name). The stored bucket name is always unqualified. Ceph Admin converts that target only at protocol boundaries: Admin Ops receives the plain bucket name with an explicit tenant scope, while cross-tenant S3 requests use RGW's tenant:bucket request form. The Ceph Admin S3ExecutionContext remains the executor identity and does not inherit the target bucket tenant. Qualified RGW S3 names are accepted only for explicit Ceph Admin cross-tenant requests; Manager and generic S3 clients keep normal SDK bucket-name validation.

Native S3/IAM execution continues to use the selected identity's credentials. Ceph applies its implicit tenant to bucket names and policy resources; Portal's DB grants remain scoped by Account ID and its personal IAM identities remain account-local. Tenant-scoped Portal policies omit default-tenant principal aliases so a foreign same-name user cannot be exempted from the access Deny. Support for tenant metadata does not introduce tenant lifecycle operations or a new authorization model.

  • /manager and /browser rely on execution context selection.
  • /portal requires explicit Portal account access and uses Portal Storage Space metadata and grants as the source of truth.
  • One RGW account represents one Portal project. The account-local bkr-portal-manager IAM group can therefore grant the fixed Manager data-plane action set once for all project Storage Spaces; technical buckets apply an explicit principal-scoped resource-policy Deny.
  • /ceph-admin uses an endpoint-scoped Ceph Admin context.
  • /storage-ops lists and operates only over contexts the user is authorized to use.
  • Backend services resolve the executor from the requested context and reject incompatible contexts instead of silently switching to another identity.

Account-scoped Portal routes receive AccountAccess for a persisted RGW S3Account after the dependency has checked the explicit account selection and Portal role. Connection, S3-user, and Ceph Admin selectors are rejected at that boundary. Portal bucket statistics therefore read Manager snapshots using the account ID directly; current Storage Space visibility and content-access checks still determine which snapshots can be returned.

The transversal execution-context boundary uses the explicit, non-persistent S3ExecutionContext. Persistent RGW accounts selected through this boundary are copied before credentials are attached. Connections, S3 users, direct sessions, Portal Browser identities, and Ceph Admin endpoints never instantiate synthetic S3Account ORM records. context_id and context_kind are authoritative; database-like negative IDs and dynamically attached private attributes are not part of the contract.

Manager usage scans, integrity checks, purges, and bucket-deletion workflows take their target identity and name from the resolved S3ExecutionContext, never from the raw context_id query string. Usage snapshots and aggregates share that canonical context_id as their Manager scope_id; purge workflow audit metadata uses it too. A direct S3 session without a selector keeps its resolved local-account ID or explicit session:<rgw-account-id> identity. Revision 0124 normalizes historical Manager snapshot scopes and retains the newest calculation for each canonical context and bucket, without a runtime alias lookup or changes to historical audit rows.

/manager/context consumes that explicit execution context directly. Its internal dispatch uses the execution kind, never the presence of optional source IDs to infer a different kind. Source IDs identify local records for the existing access checks and limit lookups. access_mode keeps its public values admin, connection, s3_user, and session; Browser availability, Ceph operations, and private-access provisioning remain governed by their existing access services and session capabilities. Limits are loaded only when include_limits=true, both over HTTP and in direct route calls.

Manager IAM, SNS, statistics, and bucket-operation guards share the explicit S3ExecutionContext/AccountCapabilities boundary. Missing capabilities are rejected, never interpreted as unrestricted access. Statistics check bucket permission and the direct-session traffic capability before resolving a connection's RGW identity. Only the explicit connection kind triggers that lookup, and it requires a source connection matching the selected connection ID. Incidental source metadata on another execution kind cannot switch the identity. The statistics overview collects IAM counts only when can_manage_iam is granted. Existing endpoint feature flags, supervision credentials, workspace access, and native storage authorization remain independent checks.

Browser listing/detail caches and the shared Manager/Storage Ops bucket cache use the same s3_execution_cache_key fingerprint. It includes the explicit context kind and ID, credentials, session token, endpoint, region, addressing mode, and TLS verification option. Rotating credentials or changing execution configuration must not reuse a previous cached response. Cache keys store the digest, never raw credentials. Existing TTLs and mutation invalidation remain independent from authorization; a cache hit does not authorize a context or replace Portal's current Storage Space visibility checks.

The shared Manager/Storage Ops bucket cache invalidates every execution variant of the selected context_id (or the persisted account ID), without inferring a scope from source metadata or display names. Account, Portal, and bound-session contexts retain the same account invalidation scope while their cached results remain separated by execution fingerprint. Invalidation also detaches pending loads: existing callers may finish with their original result, but subsequent reads start a fresh load and an older result cannot repopulate the cache.

Ceph Admin bucket listings have two endpoint-scoped cache layers: raw RGW payloads and prepared listing snapshots. Refresh and mutation invalidation atomically discard both layers and detach their pending loads. Old loads may finish for existing callers but cannot restore invalidated entries or displace new loads. Raw requests remain serialized per endpoint within the current load generation: a payload with statistics can satisfy a request without them, while a waiter rechecks its needs after an incomplete or failed request. Coordination state is released when loads finish; no idle endpoint locks are retained. The 30-minute TTL and limits of 16 raw payloads and 64 snapshots remain unchanged.

Ceph Admin RGW account and user listings share EndpointListingCache, with a separate instance for each entity type. It owns the raw and prepared cache layers under one lock, with a 30-second TTL and limits of 16 raw payloads and 64 prepared listings. Invalidation clears both layers and detaches pending loads for the selected endpoint (or all endpoints). An older load cannot restore invalidated entries. Builders retain independent progress and cancellation callbacks; cancelling one request does not cancel another. Pending-load markers are released on success or failure. Account payload loading uses the internal client's explicit list_accounts(include_details=False) contract and never retries a TypeError through a different call signature.

RGW account creation treats an upstream 409 Conflict as a failed creation, even when an account with the requested ID can be read afterward. The returned account ID must match the requested ID before any follow-up quota mutation or local account provisioning. Account updates likewise stop on conflicts. Raw RGW extra_params cannot override account identity, names, format or fields already exposed through dedicated inputs. Account-root reconciliation rejects contradictory top-level and nested account IDs.

Ceph Admin bucket linking requires the resolved target's RGW account ID or user UID and tenant to match the selected target; missing or contradictory identifiers block the mutation. Endpoint-managed Runtime and Supervision user creation passes its explicitly generated S3 credential pair through a dedicated internal client contract, while arbitrary user extra_params cannot set keys.

Browser STS sessions reuse that execution fingerprint, together with the resolved STS endpoint and the caller's cache partition. Exported credentials remain isolated by authenticated UI session. The cache requests 900-second credentials, renews them two minutes before their provider expiration, purges expired entries across contexts, and retains at most 512 entries with least-recently-used eviction. Failure logs identify the explicit context, never its access key; the existing fallback to that context's original credentials is preserved. Provider responses must contain nonempty string credentials and an explicit timezone-aware expiration. SDK datetimes and ISO timestamps are normalized to UTC; missing, malformed, or already expired values produce a provider error, never a fabricated expiration or a cached invalid session.

Connection RGW identity lookups use a separate 60-second monotonic cache, bounded to 512 entries with expired-entry pruning and least-recently-used eviction. Identity and metrics eligibility have distinct cache scopes. Keys fingerprint the canonical persisted RGW identity and full endpoint lookup configuration, including exact update timestamps and credentials, without retaining raw credentials in cache keys. Endpoint or credential changes therefore do not reuse an older resolution even when updates occur within one second. The connection service also clears a persisted RGW identity when its endpoint or access key changes unless the same update supplies a replacement identity. Identical concurrent lookups share a single result or error, and pending coordination is released on completion.

Connection identity lookup, Portal requester enrichment, live account/user quotas and scoped bucket stats use a ready Runtime Read Ops identity exclusively. Its caps are accounts=read;user-info-without-keys=read;buckets=read, without keys in user responses. S3 healthchecks and collectors use ready Supervision Ops identities. Unavailable service identities produce explicit degraded states; neither reader nor collector may fall back to Admin Ops. S3 scope is proven before bucket metadata queries, and bucket retries never drop UID scope.

Identity requirements follow normalized endpoint features: Admin/Accounts need Runtime, while Metrics/Usage and enabled signed S3 healthchecks need Supervision. Admin Ops is required for delegated administration or requested managed bootstrap. An endpoint authorized only for Ceph Admin accepts managed or external service mode with empty Runtime/Supervision rows. Those rows persist the mode without triggering provisioning, startup recovery or remote requests. Partial credential pairs are rejected even for optional identities. Disabling features preserves configured identities, and pending lifecycle operations still recover.

Ceph Admin access and usage composition use its dedicated validated credentials. Supervision availability controls can_metrics and Storage/Traffic requests; Ceph Admin alone can have can_admin=true and can_metrics=false. The endpoint form still requires Supervision detection before enabling Metrics or Usage.

Admin Ops remains operator-supplied. Service identity rows store encrypted secrets, mode, UID, durable ownership provenance, lifecycle state, and pending rotation. Provisioning persists the intended key before RGW mutations; endpoint operation leases serialize reconciliation and rotation. A UID collision is never adopted. Revocation blocks local access before deleting an owned RGW user without purge. Ceph Admin requires global activation, persistent endpoint allowed, and a ready external admin identity validated with its manually supplied key pair. Ceph Admin users are operator-owned and never provisioned, revoked or rotated by BucketReef. Disabling access preserves their stored pair. ENV synchronization preserves generated DB credentials.

Usage-history subjects are local RGW accounts or S3 users, scoped to their storage endpoint. Trend filters use the explicit execution kind and the corresponding local subject ID. A direct S3 session bound to a local account can read that account's history; an unregistered session has no local history and returns empty baselines or an unavailable trend response. Connections and Ceph Admin contexts must not be reinterpreted as local history subjects, and missing IDs must never broaden a query to other subjects.

Canonical UI roles

users.role stores exactly one role: ui_none, ui_user, ui_admin, or ui_superadmin. The database constraint, backend request models, and frontend API types share this contract.

ui_none is the explicit no-workspace role.

Account access axes

Account associations carry two independent, nullable rights:

  • manager_role: account_administrator or NULL;
  • portal_role: portal_user, portal_manager, or NULL.

At least one axis must be present. Direct and UI-group associations are combined separately: Manager access is the union of administrator grants, while Portal access takes the highest Portal role only. The effective-access response exposes separate direct and group provenance for both axes. There is no conversion between Manager and Portal roles.

Account-association API payloads require both fields, using null for an absent right. The removed role and is_root fields, missing role fields, empty associations, and Manager Browser access without manager_role are rejected. Ceph's technical account-root identity and RGW account credentials remain execution details; they do not grant a BucketReef Portal role.

Workspace authorization matrix

EffectiveAccessService is the authority for catalogue construction and execution of a selected context.

Manager tool guards always resolve persisted direct and UI-group grants through this service; there is no user-only fallback without a database session. A migration API request reuses that resolution to build its complete BucketMigrationAccessScope, including administrator account contexts, rather than querying the grants independently for each subset. The migration worker uses the same scope builder but performs a fresh resolution at every existing creator-access checkpoint. No access snapshot is cached between requests or across migration execution checks; group revocations and expired connections remain effective before further work.

ManagerToolAccess defines the tool list. The shared manager_tool_access module maps those fields to the same can_access_manager_ columns on users and UI groups for persistence, public projections, effective-access aggregation, and sensitive-change detection. Public direct grants remain separate from group-derived effective grants. An omitted or null manager_tool_access preserves direct grants, unless a user's role no longer supports Manager; demotion to ui_none clears the user's direct tool grants. An explicit empty object resets all tools to false. A real change to a user's direct tools still requires the configured recent-authentication check, including revocation.

Workspace Allowed UI-user contexts
Manager account_administrator accounts, assigned RGW users, assigned shared Manager connections, and the owner's active private Manager connections.
Manager Browser The active Manager context only. Accounts require account_administrator and allow_manager_browser_data_access = true on the same direct or group link and execute as root. RGW users require the flag on any direct or group link and execute with that RGW user's credentials. Owned private connections require both Manager and Browser access. Shared connections are rejected.
Browser The owner's active, unexpired private connections with access_browser = true, plus compatible Portal projects whose effective portal.browser_access_enabled setting is true. Portal project execution uses the personal Portal IAM identity and Portal profile.
Portal Explicit portal_user or portal_manager account membership only. Execution always uses the user's personal Portal IAM identity.
Ceph Admin Browser The explicit endpoint-wide Ceph Admin branch.
Direct S3 session The explicit session principal and its session capabilities.

Generic account contexts, RGW users, and shared connections are rejected by standard Browser before credential resolution. An enabled Portal project is published as the distinct portal_account context and resolved through the Portal authorization branch, never through account administrator credentials. The embedded Manager Browser has no catalogue or selection of its own. It reuses the active Manager identity and ctx, and every /api/browser request uses X-S3-Workspace: manager-browser. Account permission cannot be assembled from separate links: the administrator role and data-access flag must coexist on one direct or group association. Authorization is revalidated before any credential resolution so forged and revoked contexts return 403.

GET /api/me/workspace-access returns availability, context counts, and the backend-selected default workspace. Password login, LDAP, OIDC, redirects, and the workspace selector consume this contract instead of reconstructing access from a cached user profile.

Practical impact

A single UI user can have access to multiple accounts, connections, and endpoints while keeping execution explicit and attributable. Granting a menu item or Manager tool access does not grant native storage permission by itself; S3, IAM, RGW Admin Ops, or Portal grants still decide whether the storage action is allowed.

Multi-tab context contract

  • The visible query parameter is the authority for each tab: ctx for Manager and standalone Browser, project for Portal, and ep for Ceph Admin. /manager/browser uses the Manager ctx and topbar selector.
  • Manager and standalone Browser keep distinct default-context preferences. If a Browser preference or ctx value is no longer authorized, the client removes both, shows a warning, and requires an explicit selection. It never falls back to the first available context.
  • Portal follows the same rule for project selection. Internal navigation that omits project keeps the current tab's project and restores it in the URL.
  • Browser bucket and prefix position, Bucket Ops row selections, and the Bucket Ops configuration clipboard are operational tab state. They are not shared through localStorage; bucket/prefix position and the clipboard use sessionStorage, while row selections start empty after a remount.
  • Cookie refresh is serialized across tabs with Web Locks and a storage lease fallback. After one tab rotates the single-use refresh cookie, waiting tabs reuse the resulting server session and call /api/auth/session; no access token is stored in browser storage.

Server-managed private access

Manager exposes two specialized provisioning branches that never return the new secret to the frontend:

  • an authorized, IAM-capable RGW Account or S3 Connection creates a dedicated deterministic IAM user, applies validated groups and policies, creates the access key last, then stores it in an owned private S3 Connection;
  • an assigned RGW User with Ceph key-management permission creates a distinct RGW key and immediately stores it in an owned private S3 Connection.

S3 Connection identity is stored only in the structured rgw_user_uid / rgw_tenant / rgw_account_id fields. Managed RGW-user access stores the actual RGW UID and tenant. Managed IAM access never treats its IAM username as an RGW UID; it stores the source RGW Account ID when that identity is known. The durable provisioning saga may retain its storage-side principal kind (iam_user or rgw_user) because that field describes the remote resource that must later be cleaned up; it is not copied into the connection identity. Migration 0158 performs the one-time conservative conversion from historical credential_owner_type / credential_owner_identifier shapes and drops those columns. Runtime code does not parse the historical syntaxes.

The identity is independent of AccountIAMUser and every Portal identity. A shared connection is only an administration context; its credentials, associations, capabilities, and tags are never copied. Endpoint data is derived server-side from the selected Manager context.

managed_private_accesses records the UI owner, immutable source context, remote principal, access key ID, private connection, applied IAM resources, and saga state. It deliberately contains no secret. A partial unique index permits only one provisioning, active, deleting, or cleanup_pending row per UI user and source context. Remote mutations are checkpointed, compensated in reverse order on failure, and retained as cleanup_pending when compensation cannot finish.

Connections created through this flow have server_managed = true. Generic connection APIs may change only their name, tags, active state, and workspace flags. Endpoint, credentials, principal, provenance, rotation, and deletion are owned by the orchestrator. IAM/RGW key inventories expose the managed link and reject direct status or delete operations.

Quick troubleshooting matrix

Symptom Check first
Workspace is missing Global feature flag, UI role, user or group entitlement.
Context is missing Explicit Manager or Portal account role, assigned RGW user/shared Manager connection, owned private connection flags/activity/expiry, or endpoint availability.
Menu item is hidden in Manager Global Manager tool setting, user or group Manager tool access, endpoint capability, and selected context type.
Portal Storage Space is missing Portal account link, Storage Space metadata, access mode, collaborator grant, and archived state.
Action is visible but returns AccessDenied Storage-side IAM/S3/RGW permission and the selected execution identity.