Reference for customer CISOs, SOC teams, and auditors. Scope: the on-prem deployment as shipped by this bundle, not the memclaw.net SaaS.
┌──── customer network ─────────────────────────────────────────────┐
│ │
│ agents / OpenClaw clients │
│ │ X-API-Key (agent or tenant scope) │
│ ▼ │
│ [ gateway (port 80) ] │
│ │ auth_request → auth-api │
│ │ inject X-Tenant-ID + X-Org-Read-Only │
│ ▼ │
│ ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │
│ │ auth-api │admin-api │storage- │audit-api │ core-api │ │
│ │ │ │ api │ │ │ │
│ └────┬─────┴────┬─────┴────┬─────┴────┬─────┴────┬─────┘ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ postgres redis rabbitmq │
│ │
│ license.key (RS256 JWT, mounted read-only into auth/admin-api) │
│ │
└───────────────────────────────────────────────────────────────────┘
▲ │
│ TLS terminated by customer's reverse │ optional daily
│ proxy (Caddy, Traefik, cloud LB) — │ phone-home to
│ gateway speaks plain HTTP internally │ ops.caura.ai
│ │ (HMAC-signed,
│ opt-out per license)
Everything inside the box is the customer's trust domain. The bundle ships no outbound dependencies except the optional phone-home (off by default on air-gap licenses).
| Store | Encryption | Notes |
|---|---|---|
| Postgres | customer-managed (filesystem encryption / cloud disk) | no app-level DB encryption |
| Redis | customer-managed | STM + read-only status cache only — no persistent data |
| RabbitMQ | customer-managed | audit event queue; messages ephemeral |
| tenant settings | Fernet (AES-128-CBC + HMAC-SHA256) | encrypted via SETTINGS_ENCRYPTION_KEY at the application layer — the key is in .env, rotate by re-keying and re-encrypting (tool shipping in a later version) |
| license.key | signed + timestamped, not encrypted | contents are not sensitive; signature is verified at every service start + hourly thereafter |
| backups | pg_dump -Fc + Redis RDB + config; customer-encrypted |
scripts/backup.sh produces a tarball; encrypt at the customer's choice of tool |
- Users — Argon2id password hashes, optional GitHub OAuth, optional TOTP 2FA.
- Agents / API clients — SHA-256-hashed API keys (prefix
mc_), scope is a single tenant. Rotated viamemclawctl issue-api-key. - License-driven read-only: when the license is expired or the org
is explicitly marked read-only, the gateway's
auth_requestsurfaces anX-Org-Read-Only: trueheader thatenforce_usage_limits()in core-api translates to HTTP 403 on every write. Reads unaffected.
Auth flow at the wire:
- Client hits
/api/*withX-API-KeyorAuthorization: Bearer <JWT>. - Gateway's
auth_requestsubrequests auth-api's/api/v1/auth/validate. - auth-api validates (SHA-256 hash lookup or JWT signature), computes read-only state (in-memory 30s cache per tenant), returns the identity headers.
- Gateway forwards the request + identity headers to the upstream; the
raw API key is stripped on the
/mcppath so core-api never sees it.
- RS256 JWT signed by CauraOps. Public key baked into every
service image at
/app/common/license/keys/license_public.pem. - Claims include:
license_id,org_name,issued_at,expires_at, per-limit caps (max_users,max_writes_per_month, etc.),featureslist,phone_home_enabledflag. - Loader fails closed on signature mismatch (service refuses to start — the customer cannot edit or forge a license).
- Expiry has a 24-hour clock-drift tolerance so NTP-adjacent glitches don't lock people out. Past 24h, the service flips to read-only until a valid license is dropped in.
- Tampering = loud failure at startup.
memclaw_writereturns 403 within 30s of the license flipping via the existing 30s read-only cache.
Only applies when license.phone_home_enabled = true. Air-gap licenses
are issued with this disabled; the on-prem client skips the scheduled
task entirely.
When enabled:
- HTTPS POST to
https://ops.caura.ai/api/onprem/heartbeatonce per 24h - Body is aggregates only: writes/searches/recalls counters, current version, host OS family — no tenant names, no memory contents, no user PII
- Body is signed with HMAC-SHA256 using a key derived from the license_id + issued_at (both also in the JWT) — receiver verifies before recording
- Failures are silent + retried with jittered backoff. Never blocks the stack.
| Threat | Mitigation |
|---|---|
| License forgery | RS256 signature (private key is in CauraOps GCP Secret Manager, never leaves that boundary) |
| License tampering | Loader refuses to load on any signature mismatch, service doesn't start |
| License replay past expiry | Expiry enforced with 24h clock-drift tolerance; after that, writes return 403 |
| Stolen API key | Keys are scoped per-tenant; rotation via memclawctl issue-api-key; revoke via admin-api |
| Token exfiltration via logs | JWTs + API keys are masked in structured logs (prefix-only) |
| Phone-home replay / spoof | HMAC-SHA256 over raw body with a key unique per-license; constant-time verify on CauraOps side |
| Malicious plugin source | install-plugin / plugin-source serve files from the committed memclaw/plugin/ tree — verify the plugin-source-hash matches on the client if you want an integrity gate |
| Gateway bypass | All /api/* routes are behind the single gateway; services are on an internal Docker network with no published ports by default (only gateway:80 is exposed) |
| Privilege escalation within tenant | RBAC: role ∈ {owner, admin, member}; admin-api enforces org_role on every mutation; superadmin is cross-tenant only via explicit super_admin JWT claim |
- Compromised customer VM: if an attacker has root on the VM, all
bets are off (they can read
.env, license, DB files). - Malicious operator with superadmin access: internal threat; rely on your own SSO / IAM controls.
- DoS: no rate limiting in the on-prem gateway by default (no L4 DDoS protection). Put it behind a Caddy/Cloudflare/nginx+fail2ban if the stack is publicly reachable.
- Supply chain: images are pulled from
ghcr.io/caura-ai/*; verify provenance withcosign verify(signatures are keyless via sigstore OIDC) — we sign + publish SBOMs per release but don't re-verify runtime.
Not formally certified. Architecture is compatible with:
- SOC 2 Type II: audit trail (
platform-audit-api+enterprise.audit_log), RBAC, at-rest encryption (customer-managed), password hashing. - HIPAA: BAA needed; on-prem removes the memclaw.net data-sharing boundary, but the customer assumes all PHI responsibilities.
- FIPS 140-2: Python
cryptography+python-joseuse OpenSSL; use a FIPS-validated OpenSSL build in the container base image if required. Not shipped as a default.
security@caura.ai — GPG key at https://caura.ai/.well-known/security.txt.
Coordinated disclosure, 90 days.