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.
/managerand/browserrely on execution context selection./portalrequires 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-managerIAM 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-policyDeny. /ceph-adminuses an endpoint-scoped Ceph Admin context./storage-opslists 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_administratororNULL;portal_role:portal_user,portal_manager, orNULL.
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:
ctxfor Manager and standalone Browser,projectfor Portal, andepfor Ceph Admin./manager/browseruses the Managerctxand topbar selector. - Manager and standalone Browser keep distinct default-context preferences. If a Browser
preference or
ctxvalue 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
projectkeeps 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 usesessionStorage, 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. |