Zone
A zone is the top-level organizational boundary in Caracal. Everything — applications, resources, policies, grants, sessions, and audit events — belongs to exactly one zone. Zones are independent: a mandate issued in one zone cannot be verified in another, and a policy in one zone has no effect on another.
What a zone contains
Section titled “What a zone contains”| Item | Scoped to zone |
|---|---|
| Applications | Yes — each application belongs to one zone |
| Resources and providers | Yes |
| Policies and policy sets | Yes — one active policy set per zone at a time |
| Grants | Yes |
| Agent sessions | Yes |
| Audit events | Yes |
| Signing key pair | Yes — each zone has its own EC P-256 key pair |
Zone attributes
Section titled “Zone attributes”A zone is stored with these attributes:
| Field | Description |
|---|---|
id | UUID; carried in every mandate as zone_id |
org_id | Organization identifier (default: "default") |
name | Human-readable label |
slug | URL-safe identifier (matches /^[a-z0-9-]+$/) |
dek_ciphertext | The zone’s data encryption key, encrypted under the KEK |
dcr_enabled | Whether Dynamic Client Registration is permitted |
pkce_required | Whether PKCE is required for authorization code flows |
login_flow | Authentication flow type for this zone |
The key hierarchy
Section titled “The key hierarchy”Each zone has its own signing key pair used to sign and verify mandates. This isolation means a compromised key in one zone does not affect others, and keys can be rotated per zone independently.
The key hierarchy has two levels:
ZONE_KEK (environment variable, 32 bytes) │ └─ encrypts → zone Data Encryption Key (DEK, stored as dek_ciphertext in DB) │ └─ encrypts → zone signing key (EC P-256 private key, stored in secrets table)ZONE_KEK is a 32-byte hex-encoded key set in the ZONE_KEK environment variable on the STS. It is the root of the key hierarchy. The STS validates on startup that ZONE_KEK is present, is 32 bytes, and is not all zeros.
Zone DEK (dek_ciphertext) is stored in the zones table. The DEK is decrypted by the STS using ChaCha20-Poly1305 with the ZONE_KEK. The decrypted DEK is then used to decrypt the zone’s signing key from the secrets table.
Zone signing key is the EC P-256 private key used to sign mandates. It is stored encrypted under the zone DEK, never in plaintext at rest.
The ZONE_KEK_PROVIDER environment variable controls where the KEK is sourced. The current supported value is "local" (reads from the ZONE_KEK env var). Future values may support external KMS providers.
JWKS endpoint
Section titled “JWKS endpoint”The STS exposes the zone’s public key(s) for verification:
GET /zones/{zoneId}/.well-known/jwks.jsonThis endpoint returns up to two recent public keys to support key rotation without breaking in-flight tokens that were signed with the previous key. JWKS responses are cached by the Gateway and SDK connectors, refreshed every 5 minutes.
One active policy set per zone
Section titled “One active policy set per zone”A zone has exactly one active policy set binding at a time. All token exchanges in the zone are evaluated against the active bundle. A zone with no active binding evaluates with the deny-all fallback.
Policy set activations are propagated to the STS immediately through the caracal.policy.invalidate Redis stream, which triggers a bundle reload for the zone.
Zone isolation in practice
Section titled “Zone isolation in practice”Two zones running on the same stack are as independent as two separate deployments. They share PostgreSQL and Redis infrastructure but maintain separate:
- Signing keys (mandates can only be verified by the issuing zone’s JWKS)
- Policy sets (an activation in zone A does not affect zone B)
- Session namespaces (agent sessions are keyed by
zone_id) - Audit ledgers (audit events carry
zone_idand are queryable per zone)
A mandate issued by zone A carries zone_id = "zone-A" in its claims. The Gateway verifies the token against the JWKS of the zone specified in the token — a token for zone A cannot be verified against zone B’s JWKS.
When to use multiple zones
Section titled “When to use multiple zones”Use separate zones when you need:
- Different policy sets for different environments (staging vs production)
- Different signing keys for different teams or services
- Audit segregation by organizational unit
- Independent key rotation schedules
A single zone is sufficient for most deployments where all services share the same policies and trust boundary.
Next steps
Section titled “Next steps”- Resource and Grant — resources and grants within a zone
- Policy — activating a policy set in a zone
- Mandate — how zone signing keys produce mandates