Skip to content

Security model ​

Moʻolelo's security model has three pillars:

  • Source-system authority is canonical. The platform never grants access the source system would not grant. It can be more restrictive, never less.
  • Every authorization decision is auditable. The audit log records who asked, what they asked for, what was returned, and the source-system permission that allowed it.
  • Workload identity is verifiable. Service-to-service traffic uses SPIFFE-issued identities and mutual TLS; no service can impersonate another.

Source-system authority is canonical ​

When you search a Confluence space, the result set is whatever the calling user could see in Confluence. Same for SharePoint, GitHub, and any other source.

Moʻolelo can apply additional restrictions — a tenant may decide that certain tags are admin-only regardless of source-system permission — but it cannot relax source-system permissions. A page that's restricted in Confluence is restricted in Moʻolelo.

To make this work at search latency, Moʻolelo extracts each source's access control list at ingestion time and projects it into a per-record authority chain. Authorization decisions are made by OpenFGA over those projections; lookups are sub-millisecond.

When a per-source permission cannot be expressed in OpenFGA's relationship model — typically because it depends on runtime context — Moʻolelo falls back to a per-source policy hook that re-checks the live permission. This is rare in practice; most enterprise sources translate cleanly to OpenFGA tuples.

Authority chains ​

Every served result carries an authority chain — the trail of source-system permissions that justified the platform's authorization decision. A typical chain for a Confluence page might be:

SourceConfluence:acme {
  policy: page-restriction-CONF-12345
  granted_to: group:engineering
  granted_at: 2026-04-12
  reason: "User alice is in engineering"
}

The chain is logged with every audit row. If a compliance reviewer asks "why did Moʻolelo show alice this page?", the answer is in the audit log.

Audit logging ​

Every served query produces one audit row containing:

  • The calling user's identity (SPIFFE ID and canonical person ID).
  • The query's tenant and region.
  • The list of records returned, with their authority chains.
  • The latency and the rank profile used.
  • Any detokenize requests made to fulfill the query, with the regional vault's per-field decisions.

Audit rows are persisted both to the durable Iceberg audit_* tables and to a queryable ClickHouse replica. The Iceberg table is the source of truth — ClickHouse is a fast index for compliance dashboards.

Retention is configurable per tenant. The default is seven years.

Workload identity ​

Internal service-to-service traffic uses SPIFFE identities issued by a SPIRE server. Every service has a unique SPIFFE ID and presents a short-lived X.509 SVID for mutual TLS via Linkerd.

Operators don't manage SPIFFE-id rotation directly — SPIRE handles attestation and issuance based on Kubernetes node + pod attributes. The platform refuses to start a service whose SPIFFE attestation fails.

Secrets handling ​

  • Source-system credentials (PATs, OAuth refresh tokens, API client secrets) live in HashiCorp Vault. The connector services dereference them at startup and on rotation; they never sit in environment variables or Kubernetes Secret objects in cleartext.
  • Database passwords and similar operational secrets follow the same pattern.
  • Personal-data tokens (regional vault tokens) are unrelated to the service-secret vault — they live in their own per-region vault scoped to PII.

License key ​

Every service refuses to start without a verified license key. Keys are signed JSON Web Tokens issued by Moʻolelo; verification is offline against an embedded ed25519 public key, so no service ever phones home.

A key carries:

  • Tier: community, enterprise, or regulated.
  • Issued-to: the customer name on the contract.
  • Expiry: the date past which the platform stops accepting new ingests.
  • Limits: max employees, max events per day, max regions.

Past expiry, the platform enters a 7-day grace window during which it logs warnings and surfaces an admin-UI banner but otherwise operates normally. After the grace window, ingestion stops; queries continue against existing data so you don't lose access during a key-renewal scramble.

See License key management for the operator-side flow.

Moʻolelo — self-hosted federated enterprise knowledge platform.