MAQPNADocs

Tenants#

A tenant (kind Tenant, short name tn, cluster-scoped) is one customer of a service provider that runs MAQPNA for others: an ISV, a managed service provider, a neocloud or a data-centre company. One installation can host many tenants; each gets its own slice of identity, evidence and spend, enforced by the identity broker, the gateway and the operator.

Teams inside one organisation do not need tenants: they use namespaces, which already scope agents, policies, sessions, budgets and namespace roles.

What a tenant owns#

Owned How it is enforced
Namespaces (spec.namespaces) The operator labels them maqpna.com/tenant=<name>. When two tenants claim a namespace, the older tenant wins and the other reports NamespacesOwned=False
Trust domain (spec.trustDomain, default <name>.maqpna.local) Session identities in tenant namespaces are spiffe://<tenant trust domain>/ns/…
Signing key (spec.signingKeySecretRef, generated when unset) The identity broker signs tenant tokens with the tenant's Ed25519 key; the gateway refuses a tenant token signed with any other key, and a tenant key for any other namespace (tenant_mismatch)
Audit ledger Every platform record of a tenant namespace is copied into an independent hash chain for that tenant, verifiable on its own
WORM prefix (spec.auditWormPrefix, default tenants/<name>/audit) The tenant ledger ships to its own key prefix in write-once storage
Admin login (spec.admin: oidcIssuer, oidcAudience, roles) Tokens for the tenant's audience get the mapped roles as namespace roles in the tenant's namespaces only, never globally
Quotas (spec.quotas) Rendered into a BudgetPolicy named tenant-<name> with the limits for each owned namespace
MCP server sharing (spec.allowSharingWith) A tenant's MCP server serves another tenant's namespace only when sharing allows it; otherwise cross_tenant_server
flowchart TB
    subgraph SP["Installation run by a service provider"]
      subgraph TA["Tenant acme"]
        NA["namespaces acme-dev, acme-prod"]
        KA["key acme.pem · trust domain acme.maqpna.local"]
        LA[("ledger tenant/acme")]
      end
      subgraph TB2["Tenant globex"]
        NB["namespace globex"]
        KB["key globex.pem · trust domain globex.maqpna.local"]
        LB[("ledger tenant/globex")]
      end
      IB["Identity broker<br/>signs per tenant"] --> KA
      IB --> KB
      GW["Gateway<br/>key binding · per-tenant ledgers"] --> LA
      GW --> LB
      PL[("platform ledger")] -- "copied by seq" --> LA
      PL -- "copied by seq" --> LB
    end

How tenant isolation works, step by step#

  1. You create a Tenant listing its namespaces. The operator labels the namespaces, writes the tenant's key into the Secret maqpna-tenant-keys (<tenant>.pem), creates the BudgetPolicy tenant-<name> and publishes tenants.json in the ConfigMap maqpna-tenants.
  2. The identity broker reloads tenants.json (every 10 seconds) and signs tokens for tenant namespaces with the tenant key and trust domain. If the key is missing or does not match the published key ID, it answers 503 rather than signing with the platform key.
  3. The broker's JWKS publishes the platform key and every tenant key, so the gateway can verify all of them.
  4. Right after token verification, the gateway checks the binding: a token for a tenant namespace must carry that tenant's key ID and trust domain. Anything else is refused with HTTP 401.
  5. Every ledger record of a tenant namespace is appended to the tenant's own chain (ext.tenant, ext.platformSeq). With Postgres, one elected replica copies the records in sequence, without gaps or duplicates across a leader change.
  6. Tenant admins sign in through their own identity provider and see only their namespaces' approvals, audit and memory.

Service providers and billing#

Service providers buy the Operator edition. Usage is metered per tenant per hour (sandbox seconds, governed calls, model tokens, approvals), signed usage reports cover a billing period, and the operator counts billable nodes. See usage metering and editions.

What you see#

maqpna tenants list prints NAME NAMESPACES TRUST DOMAIN KEY ID HEAD SEQ HEAD HASH: each tenant with its trust domain, signing key ID and the head of its ledger. maqpna audit verify --postgres DSN-FILE --chain tenant/<name> verifies one tenant's chain in the shared database. See maqpna tenants list and maqpna usage buckets.