Multi-Tenant Isolation Model
Target Audience: Solution Architects, Security Architects, Operations Engineers
Reading Time: 12 minutes
Prerequisites: Understanding of multi-tenancy, access control, data isolation
Executive Summary
ANKASecure implements complete tenant isolation through multiple security layers:
- Authentication: JWT-based identity with mandatory
tenantIdclaim - Authorization: Role-Based Access Control (RBAC) scoped to tenant
- Data isolation: Tenant-scoped database queries and references, per-tenant key encryption keys
- Policy boundaries: Per-tenant algorithm availability and lifecycle policies
- Usage tracking: Independent license and operation metrics
Security guarantee: Tenant A cannot access, decrypt, or tamper with Tenant B's keys, data, or policies.
Table of Contents
- What is Multi-Tenancy?
- Tenant Hierarchy
- Authentication Layer
- Authorization Layer
- Data Isolation
- Policy Boundaries
- Network Isolation
- Audit & Compliance
What is Multi-Tenancy?
Definition
Multi-tenancy: An architecture where a single instance of software serves multiple customers (tenants) while keeping their data completely isolated.
ANKASecure deployment models:
| Model | Tenants | Infrastructure | Use Case |
|---|---|---|---|
| SaaS | Multiple | Shared, ANKATech-managed | ANKATech cloud offering |
| Private Cloud | Single | Dedicated, in the customer's cloud account | Customer-managed private deployment |
| On-premise | Single | Dedicated, in the customer's data center | Customer-managed deployment, air-gapped supported |
Key Principles
1. Isolation:
- Tenant A cannot see or access Tenant B's data
- Security boundary enforced at multiple layers
-
Defense-in-depth architecture
Two operations cross the boundary, and each is bounded by what it can disclose
A platform administrator may act as a tenant — on a SaaS deployment, only while that tenant has authorised it. This is a consent-bounded exception to the boundary, not a hole in it: it is declared by the tenant, time-boxed, revocable, and recorded on both planes. See Consent-Bounded Platform Access below.
A forgotten-password request resolves an email address across every tenant. It is unauthenticated, by necessity — it runs before anyone has proved anything — and it is the only unauthenticated crossing on the platform. See Cross-Tenant Account Recovery below.
Tenant A still cannot reach Tenant B by any means, through either of them.
2. Customization:
- Per-tenant policies (algorithms, key lifecycles)
- Per-tenant branding (future feature)
- Per-tenant licensing and usage limits
3. Efficiency:
- Shared infrastructure (compute, network, storage)
- Reduced operational overhead
- Economies of scale
4. Security:
- All tenants benefit from security updates simultaneously
- Centralized monitoring and threat detection
- Standardized compliance controls
Tenant Hierarchy
Structure
Global (Platform Level)
├── Deployment-Level Policies (default for all tenants)
│
├── Tenant A (UUID: tenant-a-uuid)
│ ├── Tenant-Level Policies (override deployment defaults)
│ ├── Memberships (people: one identity each, shared across tenants)
│ │ ├── Membership of identity I1 (ACTIVE, roles in A: TENANT_ADMINISTRATOR)
│ │ └── Membership of identity I2 (PENDING, roles in A: TENANT_VIEWER)
│ ├── Applications (business entities)
│ │ ├── App A1
│ │ │ ├── Cryptographic Actors (machine principals)
│ │ │ │ ├── Default Actor (auto-provisioned)
│ │ │ │ └── Specialised Actors (VISA, AMEX, BPO, ...)
│ │ │ └── Exchange Contexts (governed interaction scenarios)
│ │ │ ├── VISA-embossing-2026
│ │ │ └── AMEX-embossing-2026
│ │ └── App A2
│ ├── Capability Grants (5-dim: Actor × Capability × Asset × Context × Policy)
│ ├── Constraint Policies (max_usage, rate_limit, revoke_on_use, ...)
│ ├── Keys/Keystores
│ │ ├── encryption-key-1
│ │ └── signing-key-1
│ └── Usage Metrics (independent tracking)
│
└── Tenant B (UUID: tenant-b-uuid)
├── Tenant-Level Policies
├── Memberships (I1 may also be a member here, with B's own roles) / Applications / Actors / ExchangeContexts / Grants / Policies
└── Keys/Keystores (wrapped under Tenant B's own KEK)
People: one identity, one membership per tenant
A person is one identity across the deployment — one email, one password, one display name, one set of MFA factors — and belongs to a tenant through a membership: its status (PENDING, ACTIVE, SUSPENDED), its roles in that tenant and its federated links to that tenant's identity providers. The identity is not owned by any tenant; the membership is.
What a tenant sees and controls:
- Only its own memberships. The tenant user surface (
/api/v3/admin/tenants/{tenantId}/users) reaches an identity only through a membership of that tenant. Each item shows the identity's email and display name with this tenant's status and roles — never a field, count or link derived from another membership. A person who belongs to A and B looks, in A, exactly like a person who belongs to A only. A user id with no membership in A is404, and nothing is read from other tenants. - Invitations reveal nothing. Adding an email creates a PENDING membership. The answer is identical whether the address names a new identity or one that already exists elsewhere — no display name, activation state or credential flag is shown until the person accepts — so a tenant administrator cannot learn that a person is registered in another tenant. Only the mail the person receives differs: an activation link (new identity) or an invitation link accepted by signing in (existing identity).
- Memberships and roles, never the identity. A tenant administrator suspends, removes and re-roles memberships. The password, display name and email belong to the identity and are changed by the person or on the platform plane (
/api/v3/admin/platform/identities/{identityId}); a tenant caller is refused (403). Removing a membership leaves the identity and its other memberships untouched; an identity with no membership left can sign in to nothing and is deleted only by a platform administrator. - Revocation is per membership. Suspending or removing a membership, or changing its roles, revokes the tokens issued for that membership: the person's tokens for that tenant stop working and their tokens for other tenants keep working.
- A tenant's identity provider authenticates the person for that tenant only. A session federated through a provider is admitted only to memberships linked to that provider, while it is one of the tenant's effective providers (its own, or the deployment provider it inherits), so tenant A's provider never yields a session in the same person's tenant-B membership. A tenant whose mode is
LOCAL_ONLYadmits no session federated through an OIDC or SAML provider. - Each tenant's authentication posture holds for its own memberships. In a
FEDERATED_ONLYtenant, a membership linked to the tenant's identity provider is admitted only by a session federated through that provider, even when the person holds a password for other tenants, and so is a member the tenant restricted to federation in any mode — disabling the person at the tenant's provider ends their access to that tenant. A session that enters another tenant by a switch is decided against that tenant's posture, and steps up there instead of carrying one tenant's admission into another. See Authentication Posture*. - The platform tenant is exclusive. A platform administrator's identity never holds a tenant membership, and a tenant member's identity never holds the platform membership (
root-membership-exclusive); a platform administrator reaches a tenant only through consented, audited support access.
Secondary isolation dimensions inside a Tenant
Cryptographic isolation does NOT stop at the Tenant boundary. The Cryptographic Control Plane introduces two further dimensions that scope every crypto operation:
| Dimension | Purpose | Isolation guarantee |
|---|---|---|
| Cryptographic Actor | Sole subject of S2S authentication inside an Application. Replaces per-Application credentials. | Two Actors under the same Application that hold grants for different Assets cannot cross-use each other's keys, even within the same tenant. |
| Exchange Context | Governed interaction scenario (e.g. "VISA embossing", "BPO Alpha collections") bound to an Application. | A single Actor can participate in multiple Exchange Contexts without its grants leaking across them — the JWT's exchangeContextId claim must match the grant's context at runtime. |
These are defense-in-depth layers within a tenant. The Tenant boundary remains the outermost and most strictly enforced isolation surface: the authenticated tenantId claim, tenant-scoped database queries and references, tenant-scoped cache entries, and tenant-attributed audit records.
See Cryptographic Control Plane* for the complete entity model and 5-dimensional authorisation flow.
Tenant UUID
Every tenant has a unique UUID:
Purpose:
- Global unique identifier (no collisions)
- The value of the JWT
tenantIdclaim - Audit trail correlation
Authentication Layer
JWT-Based Identity
Every API request requires JWT with tenantId claim. For a person, sub is the identity id — the same in every tenant they belong to — and tenantId names the membership the session is signed in to; a tenant switch issues a new token with the same sub and the target tenantId.
JWT structure:
{
"iss": "https://auth.ankatech.co",
"aud": "https://api.ankatech.co",
"sub": "user-123",
"exp": 1737048000,
"nbf": 1737044400,
"iat": 1737044400,
"jti": "token-uuid-abc123",
// Tenant isolation claim (MANDATORY)
"tenantId": "tenant-a",
// User context
"userId": "user-123",
"email": "[email protected]",
// Authorization
"scopes": ["secure.encrypt", "secure.decrypt", "admin.keys.read"],
"roles": ["TENANT_KEY_MANAGER"]
}
Validation (every request): a token without a tenantId claim is rejected, and every operation the request performs is scoped to that claim's tenant. A tenant named anywhere else — a header, a host name — confers nothing.
Token Issuance
Authentication flow:
1. A person signs in through the authentication transaction (passkey, password + TOTP,
or the tenant's identity provider); an actor or workload presents client credentials
↓
2. The platform verifies the proofs, the password ONCE when one is presented
↓
3. The platform reads the identity's admitted memberships
(ACTIVE, tenant permits login, the membership admits the session's method)
↓
4. One membership → JWT with that tenantId
Several → the person chooses one in the transaction (select-tenant)
↓
5. Client includes JWT in all API requests
↓
6. APIs validate JWT and extract tenantId
↓
7. Operations scoped to extracted tenantId
Tenant resolution: the tenant is chosen from the person's memberships, never from the credential. The sign-in asks which membership to enter when several are admitted; once signed in, a refresh_token grant carrying another tenant_id switches to another ACTIVE membership of the same identity, and GET /api/v3/auth/account/memberships (listAccountMemberships) lists the switch targets. See Authentication — One identity, many tenant memberships*.
Service-to-Service Authentication
Calls between platform services are mutually authenticated (mTLS) and act within the tenant of the request that caused them; a service-to-service call confers no access to another tenant.
Authorization Layer
Role-Based Access Control (RBAC)
Authorization inside a tenant is carried by the platform's SYSTEM composite roles. There are nine, and none of them is prefixed ROLE_:
- Platform plane:
PLATFORM_SUPER_ADMIN,PLATFORM_OPERATOR(SaaS only),PLATFORM_AUDITOR,PLATFORM_VIEWER. - Tenant plane:
TENANT_ADMINISTRATOR,TENANT_ACCESS_ADMINISTRATOR,TENANT_KEY_MANAGER,TENANT_AUDITOR,TENANT_VIEWER.
A tenant may also define custom roles, which bundle scopes it already holds and are assignable only inside that tenant.
What each role may do is decided by the scopes it carries, and those are published rather than restated here — read Authentication — System Role Catalog* for each role, its category and the command that re-derives its scope count.
There is no per-operation permission matrix on this page, deliberately
Whether a role may perform an operation is a scope check, and the catalog above is where it is stated.
Scope Validation
Scopes in JWT:
Scope names are dotted, never colon-separated: secure.encrypt, not crypto:encrypt. The colon form appears nowhere in the platform and a token carrying it authorizes nothing.
Endpoint authorization: each endpoint declares the scope it requires — POST /api/v3/crypto/encrypt requires secure.encrypt. A token without that scope is refused before the operation runs, and an admitted operation is scoped to the token's tenantId.
Authorization flow:
1. Request received
↓
2. Validate JWT signature
↓
3. Extract tenantId claim
↓
4. Extract scopes claim
↓
5. Check required scope present
↓
6. Execute operation (tenant-scoped)
Data Isolation
Tenant-Scoped Queries
Every read and write of tenant data is scoped to the caller's tenant — keys, users, applications, policies and audit records alike. Every tenant-owned record carries its tenant, and identifiers are unique within a tenant rather than across the deployment: a kid is unique within its tenant, so two tenants may each hold a key named payment-key without either learning of the other.
Benefits:
- ✅ No cross-tenant queries possible
- ✅ An identifier from another tenant resolves to nothing (
404), disclosing nothing - ✅ Data export scoped to single tenant
Tenant-Scoped References
A query filter keeps a tenant from reading another tenant's rows. It does not, on its own, keep a row from pointing at another tenant's row: a foreign key on the referenced id alone would accept an Exchange in tenant A that names an actor of tenant B. The database closes that gap itself. Every reference from one tenant-scoped row to another is a composite foreign key that carries the tenant together with the referenced id, so the referenced row must belong to the same tenant. A write naming another tenant's row is refused by the database, whichever service or tool attempts it.
Where it applies. The references between the Cryptographic Control Plane entities — an application's actors, credentials and Exchange Contexts; a Capability Grant's actor, Exchange Context and Constraint Policy; every reference of an Internal Crypto Use Case and of a Cryptographic Exchange, including its composed grant and its clone source — plus an identity provider's group mappings, admission rules and login domain guards, a federated link intent's account, a workload-identity binding's actor, and a tenant's administrator account.
Optional references stay optional. A reference that may be absent — a DRAFT Exchange has none yet, a grant may have no Exchange Context — is left unchecked while it is empty and checked in full once it is set. Deleting a referenced row clears only the reference column; the row keeps its tenant.
The one shape a composite key cannot express. A reference whose target may be either the tenant's own row or a platform-wide one cannot carry the tenant, because a platform-wide row has no tenant. Two references have that shape: an Exchange Context's counterparty type (a platform catalog entry is visible to every tenant) and a workload-identity binding's trusted issuer (a deployment-wide issuer serves every tenant). For those two the rule "own tenant or platform-wide" is enforced by the service that writes them.
The services still check first. A write resolves every id it is given inside the caller's tenant before storing anything, which is what produces a clean 404 that discloses nothing about other tenants. The composite keys are the backstop behind that check: they make a cross-tenant reference impossible to store even for a writer that omits it.
Key Material Isolation
Each tenant's key material is wrapped under that tenant's own KEK (key encryption key), and the wrap binds the tenant identifier as authenticated data (AES-256-GCM AAD). Material presented under another tenant fails authentication and is never decrypted, so isolation does not rest on access control alone. The KEK itself stays in the HSM or Cloud KMS that holds it; see Per-Tenant Integration Overrides & Secret Custody below for the custody options.
Cache Isolation
Cached data that belongs to a tenant is cached for that tenant alone: policies, capability grants and their usage counters, tenant and application status, the reference to the tenant's KEK, and the tenant's token revocations. One tenant's entries are never served to another, and a tenant's entries can be invalidated without touching anyone else's.
The cached policies, capability grants, tenant status and KEK reference are signed by the Admin API and verified by the service that reads them; an entry that does not verify is never used.
A few cached items are not tenant-scoped — the PQC transport session, for example, which protects the channel — and none of them confers tenant access, which always comes from the token.
Benefits:
- ✅ No cache pollution across tenants
- ✅ Selective cache invalidation per tenant
Policy Boundaries
Deployment-Level Policies (Global Defaults)
Applied to all tenants by default:
{
"policyName": "deployment-default",
"allowedAlgorithms": [
"ML-KEM-768", "ML-DSA-65",
"RSA-2048", "ECDSA-P-256",
"AES-256-GCM"
],
"minSecurityLevel": 128,
"maxKeyAge": "365 days"
}
Tenant-Level Policies (Overrides)
Tenant can override deployment defaults:
{
"policyName": "tenant-a-policy",
"allowedAlgorithms": [
"ML-KEM-1024", "ML-DSA-87" // More restrictive (Level 5 only)
],
"minSecurityLevel": 256, // Override: higher than deployment
"maxKeyAge": "90 days" // Override: shorter than deployment
}
Resolution order:
A policy that cannot be resolved is never replaced by a permissive one: the governed operation is refused.
Policy Enforcement
Key generation is checked against the tenant's effective policy. The tenant is the tenantId claim of the validated token; a requested algorithm that the tenant's policy does not admit is refused with 400 algorithm-not-admitted, and no key is created.
Benefits:
- ✅ Tenant-specific compliance requirements (FIPS, CNSA 2.0)
- ✅ Granular control (stricter than platform defaults)
- ✅ Centralized policy management
See: Policy System Design*
Per-Tenant Integration Overrides & Secret Custody
Beyond crypto policy, a tenant may override an integration (the TSA connection is the settings-plane case; delivery providers are their own rows; Identity Federation, TSA usage, and SIEM/XDR forwarding are per-tenant too) — a first-class isolation dimension. Two isolation properties come with it:
- Override plane per tenant. A per-tenant integration override is stored for that tenant alone, mirroring the deployment / tenant pair of the policy plane, and resolved live — tenant override, then deployment default, then built-in default — never a copy frozen when the tenant is created. The platform decides, per setting, whether a tenant may override it at all; Licensing and Geolocation are platform-only and never gain a tenant dimension.
- Per-tenant secret custody. An override that carries a secret is sealed under a KEK of the tenant's own, one KEK per tenant. Each tenant's secrets are sealed under their own KEK, so destroying that KEK would make only that tenant's secrets unrecoverable. No operation in this release destroys a tenant's KEK, and closing a tenant does not. A tenant-scoped AAD fails a cross-tenant presentation closed at the GCM tag. That KEK is distinct from the tenant's key-material KEK — a tenant's integration secrets and its key material sit on separate custody roots. The key-material KEK is per tenant on every custody option: on the deployment backend, on the tenant's own BYOK backend, and on an ANKA-managed Edition tier, where the HSM or KMS holding the tier's per-tenant KEKs is operated by ANKATech for every tenant of that tier and each tenant's KEK remains its own. Non-secret override fields never store a plaintext secret.
Platform operators can set a tenant's override from the platform plane, including on SaaS; that write configures the override without reading the tenant's data.
See: Per-Tenant Integrations Foundation and Deployment Secret Custody.
Consent-Bounded Platform Access
The boundary admits exactly one crossing, and the tenant opens it. A support-access grant is a row a tenant administrator creates for its own tenant; while it exists and has not expired, an ANKATech platform administrator may act as that tenant. Nothing else lifts the SaaS refusal, and no platform role can create the row.
Five properties keep this an exception rather than an erosion:
- Declared by the tenant, never by the platform. No platform-plane endpoint creates a grant. A platform administrator can see that a tenant has authorised, never grant it to themselves.
- Bounded by the tenant. The tenant chooses the window, up to a hard 24-hour ceiling, and a request above the ceiling is refused rather than clamped. Cross-tenant access therefore has a latest possible end, chosen by the party being crossed into.
- Revocable at any moment, and revoking ends any session in progress immediately.
- Admission only, never authority. A grant decides whether a platform administrator may be inside; it widens nothing once they are. Import of key material and irreversible destruction stay refused under impersonation on SaaS deployments — the refusal is deployment-scoped, because on a customer-operated deployment the operator is the deployment's own owner and there is no third party for it to protect. The full denied set, and the manifest that pins it, are in Consent and Support Access*.
- Visible to both parties, from their own planes. The tenant reads what was done in a session it authorised — including after revoking, because the record derives from signed audit events rather than from the grant row.
The exception is scoped to the platform → tenant direction. Tenant A still cannot reach Tenant B by any mechanism, consented or otherwise; there is no tenant-to-tenant grant.
See: Consent and Support Access*.
Cross-Tenant Account Recovery
POST /api/v3/auth/account/password/forgot takes an email address and nothing else. The address names one identity, and the password belongs to that identity, not to a tenant — so recovery is not a per-tenant operation at all. It is still the platform's only unauthenticated operation that reaches past a tenant boundary, so it is worth being precise about what it does and does not expose.
Why no tenant is asked for. Password recovery runs before anyone has proved anything. Asking the person for a tenant identifier would either demand something a locked-out person does not have, or turn the request into a tenant-enumeration surface — precisely what the post-authentication tenant picker exists to prevent.
What bounds it. The crossing is a lookup whose result never reaches the caller:
- However many tenants the person belongs to, exactly one reset link and one notification are sent, bound to the identity. The reset sets the one credential and revokes the person's tokens in every tenant (identity revocation epoch).
- The HTTP response is the identical generic
202for an unknown and a known address. The caller learns nothing about existence or tenancy — the disclosure goes to the mailbox owner, who already controls the address (OWASP ASVS 2.1.11). - The lookup is a read used to address an email. It confers no session, no token and no authority in any tenant; the reset token that follows is single-use, short-lived and bound to one identity.
Its audit row carries tenantId = null, for the same reason. auth.password.reset-requested is attributed when the request arrives, and the request names an identity, not a tenant. null is the honest value for a field the request genuinely does not determine; fabricating one would be worse than leaving it absent. The consequence is explicit: this one event type is not returned by a tenant-scoped audit query and is read from the platform plane. The six other auth.password.* types are tenant-attributed and tenant-queryable.
Network Isolation
Edge Routing (SaaS)
The edge routes a request by host name to an environment, never to a tenant. Nothing at the edge — a host name, a path, a header — selects or asserts a tenant. The tenant of every request is the tenantId claim of its validated token, so a request cannot reach another tenant by changing where it is sent or what it declares about itself.
Dedicated Environments (Private Cloud and On-premise)
A customer-operated deployment runs its own environment: its own services, its own encrypted network between them and its own storage, with no other customer on that infrastructure. Tenants inside it remain isolated from one another by every layer described on this page.
Benefit: Physical isolation at infrastructure level.
Audit & Compliance
Audit Trail Isolation
All audit logs tagged with tenantId:
{
"timestamp": "2025-01-15T10:30:00Z",
"tenantId": "tenant-a",
"userId": "user-123",
"operation": "encrypt",
"kid": "payment-encryption-key",
"algorithm": "ML-KEM-768",
"status": "success",
"requestId": "req-uuid-abc123"
}
Query audit logs (tenant-scoped):
GET /api/v3/audit/tenants/{tenantId}/admin/timeline?from=2025-01-01&to=2025-01-31
Headers:
Authorization: Bearer {jwt} # tenantId: "tenant-a"
Response:
[
{
"timestamp": "2025-01-15T10:30:00Z",
"operation": "encrypt",
"kid": "payment-key"
},
...
// Only Tenant A's logs returned
]
Benefits:
- ✅ Per-tenant evidence for GDPR, HIPAA and SOC 2 assessments
- ✅ Independent audit exports
- ✅ No cross-tenant information leakage
Usage Tracking Isolation
Independent usage metrics per tenant: every metered operation is attributed to the tenant that performed it, so usage is counted per tenant and one tenant's consumption is never counted against another.
License validation per tenant: the licence verdict for a request is evaluated for its tenant and client.
See: License Validation Strategy*
Quick Reference
Isolation Layers
| Layer | Mechanism | Protection |
|---|---|---|
| Authentication | JWT with tenantId claim | Identifies tenant for all requests |
| Authorization | RBAC + scopes | Controls what tenant users can do |
| Database | Tenant-scoped queries | Prevents cross-tenant queries |
| Database references | Composite foreign keys that carry the tenant | A row cannot reference another tenant's row |
| Key material | Per-tenant KEK + tenant-bound AAD | One tenant's material cannot be unwrapped as another's |
| Cache | Tenant-scoped, signed entries | No cache pollution |
| Network | Host routing to an environment; tenant from the token only | A request cannot select a tenant by host or header |
| Policies | Tenant-level overrides | Independent compliance rules |
| Audit | Tenant-tagged logs | Independent audit trails |
Security Checklist
For every API endpoint:
- [ ] JWT validation (signature, expiration)
- [ ] Extract
tenantIdclaim - [ ] Database query scoped to
tenantId - [ ] Key material wrapped under the tenant's own KEK
- [ ] Cache entries scoped to the tenant
- [ ] Audit log includes
tenantId - [ ] Error messages don't leak cross-tenant info
Related Documentation
Prerequisites
- Key Concepts - Entry point and terminology
- Deployment Organization Model - Hierarchy and governance (canonical source)
Foundational Concepts
- KID System Explained
- Policy-Driven Crypto-Agility
- CAPA — Crypto Agility Posture Architecture - the canonical definition of the five pillars, one page each
Architecture
- Authentication System*
- Component Architecture*
- Platform Architecture*
Administration
- Tenant Management*
- User Management*
- Policy Management*
Security
- Default Users & Policies*
- Permissions Matrix*
- Policy System Design*
Compliance
- Security Audit - Authentication, Authorization & Tenant Isolation*
Document Status: ✅ ACTIVE
Last Updated: 2026-10-15
Document Location: 02-concepts/tenant-isolation-model.md
Target Audience: Solution Architects, Security Architects, Operations Engineers
An action ON a tenant is filed UNDER that tenant
Tenant isolation governs which rows a tenant may READ. It does not, by itself, decide which tenant a row BELONGS to. A platform administrator acting on a tenant (changing its policies, assigning its key backend, its Edition, its timestamping override, its observability or event-forwarding destinations) produces an audit row, and every tenant-scoped query filters on the tenant, so a row attributed to the platform tenant would be structurally invisible to the tenant it describes.
The rule is therefore: a row records the tenant it was performed ON, and a second field records the plane the actor acted from.
tenantId— the tenant acted upon. Never the caller's own tenant when those differ.actorPlane—PLATFORM(an operator acting on this tenant) orTENANT(the tenant's own administrator).
The plane is the plane of the principal who acted. A principal of the platform tenant — a platform administrator, a platform workload, a service or an operator acting through impersonation — is always PLATFORM, also when it acts on the platform tenant itself; only a regular tenant's own principal acting on its own tenant is TENANT. A platform principal's actions therefore appear in the platform audit trail, with their origin, and not in the platform tenant's tenant-scoped view.
The platform tenant remains correct for an action on the deployment itself, which has no owning tenant.
Disclosure is a deployment decision, not a tenant one
Whether a tenant may READ its PLATFORM-plane rows depends on who the operator is:
- Customer-operated (
PRIVATE_CLOUD,ON_PREMISE) — the platform operator IS the customer's own staff, so both planes are theirs to read. - SaaS (
SAAS,DEDICATED_SAAS) —PLATFORMrows are withheld from the tenant surface. They are still written, still signed, and still readable on the platform plane; the rule decides where they are FILED, not whether they exist.
The decision follows the deployment type the deployment was installed with, and fails closed: an absent or unrecognized deployment type withholds the platform plane. A client-supplied actorPlane filter can only NARROW that set, never widen it.
"Both planes are theirs to read" includes the operator's REASON. On a customer-operated deployment the governance surface projects actionReason — the operator's own stated justification for the platform-plane action — beside the row itself, so a tenant administrator reads why an action was taken and not merely that it was. The argument for the row does not distinguish it from the justification inside it, and disclosing the action while withholding the reason leaves the customer with the alarm and without the explanation. On SAAS and DEDICATED_SAAS, where the operator genuinely is a third party, the whole PLATFORM-plane row is withheld before that projection runs, so the question does not arise there and there is no separate rule for the reason.
Two boundaries this does NOT move, and both matter:
- The deployment-type filter. Every unrecognized spelling falls on the withheld side, and SaaS withholds the whole row.
- The unified Activity feed is a different surface and excludes every
PLATFORM-plane row from the tenant feed, its aggregates and its export, under every deployment type. So does the per-entity and per-actor history. This concerns the governance surface only.
A platform-plane read that does not filter by tenant
Everything above rests on the same mechanism: the row set a caller sees is narrowed by a tenant identity. Ordinary reads narrow to the caller's own tenant; a consent-bounded support session narrows to the tenant that authorised it. In both, the tenant filter is the isolation.
A third isolation model exists for a small family of platform-plane reads whose subject is the fleet rather than one tenant — the integration topology aggregates, which answer which of my tenants departs from this deployment default. A result set spanning tenants is the entire question there, so those reads carry no tenant filter and isolation is carried by other means. That model, its controls and its disclosure floor are documented for platform operators and delivery engineering in the internal integration-topology reference; they are deliberately not restated here.
It is an exception in one direction only, and a narrow one. It grants no authority beyond reading, and nothing in it lets one tenant see another: every read on a tenant path still filters by tenant.
Closing a tenant disposes of what it owns
The hierarchy above is an ownership tree, and isolation keeps every branch of it inside its tenant. Closing the tenant itself is a separate question. A closed tenant refuses authentication, so its users cannot log in and its actors cannot obtain a token. But a row that asserts something deployment-wide — a trusted issuer, a verified email domain, an issuer binding — would keep asserting it after its owner is gone, and the platform would then refuse actions that have no owner left to justify them: a deployment-wide trusted issuer that can never be withdrawn, an email domain no other tenant can ever verify.
Closing a tenant therefore disposes of the tree, and each row's treatment follows what the row is:
- An assertion — a trust declaration, a verified domain, a consent grant, an issuer binding, an exchange context — means "this is true now". It is removed, or moved to a state its readers already exclude.
- A subject — a user, an application, a cryptographic actor, an administrative workload — is retained and left non-
ACTIVE. It is never deleted, because the retained audit trail must still resolve the principal it names. - Evidence — the audit trail, key aliases, KEK custody metadata, policy-sync events — is retained untouched. Closure drives no key lifecycle transition; destroying a custody record would make the retained events that reference it unverifiable.
Those three categories are also what a platform operator is shown before the closure, not only what the platform does after it. A read-only closure pre-flight projects the tenant's measured inventory into exactly these three categories (assertionsRemoved, subjectsDisabled, evidenceRetained) and states no fourth taxonomy. That is a deliberate coupling: the operator's screen and this model are two renderings of one classification, so if the projection's category members and this section ever disagree, one of them is wrong and the disagreement is the defect. The pre-flight reads only; it disposes of nothing, and every one of its counts is scoped to the tenant exactly like the disposal writes described here.
None of this widens the tenant boundary. Every disposal write is scoped to the tenant exactly like any other write, and one tenant's closure never reads or touches another tenant's rows — deployment-scoped records, which belong to no tenant, included.