Security Integration
Dual-Model Security Architecture
ContextUnity enforces a strict “Token as Single Point of Truth (SPOT)” security model based on Per-Project Signing & Token Isolation.
There are two operation modes, automatically detected at startup:
1. Open Source Mode (HMAC Keystream)
Used when deploying independent projects without the centralized Enterprise Shield.
- Config:
CU_PROJECT_SECRET(unique per project). - Backend:
HmacBackend(stdlib HMAC-SHA256). - Flow: The project’s ContextUnity SDK hashes its manifest against
CU_PROJECT_SECRETto mint an ephemeral registration token. The Router verifies this using its ownCU_PROJECT_SECRET. No Redis lookup of project secrets is performed.
2. Enterprise Mode (Shield Session Tokens)
Used in large, multi-tenant deployments managed by contextunity.shield.
- Config:
CU_SHIELD_GRPC_URLis set. - Backend:
SessionTokenBackend(Ed25519). - Flow: Projects establish a zero-trust binding to Shield. A project’s tools and permissions are registered out-of-band by an Infrastructure Operator using the Admin CLI (
uv run python -m contextunity.core.cli.admin sync-policy manifest.yaml). At runtime, Shield issues a short-lived Session Token signed with its private Ed25519 node key. All services verify the token instantly using Shield’s public key, without database lookups. Permissions are strictly controlled by the Shield Policy Engine, not self-declared by the project.
There is no UnsignedBackend or SECURITY_ENFORCEMENT toggle. Security is always enforced.
Universal Capability Stripping (Manifest-Driven ABAC)
ContextUnity implements zero-trust execution boundaries at the node level via Universal Capability Stripping. When a LangGraph node or tool is executed by contextunity.router:
- Manifest Parsing: The router reads the node’s declarative
contextunity.project.yamldefinition. - Scope Derivation: It calculates the absolute minimum permissions needed (e.g.,
shield:secrets:read:<tenant>/api_keys/MY_MODEL_KEY,privacy:anonymize,tool:my_tool). - Token Attenuation: The router invokes
TokenBuilder().attenuate()right before calling the node’s function, stripping all other privileges from the in-memory ContextToken and appending the node’s name (>node:model_executor) to the cryptographically signedprovenancechain.
This guarantees that even if an execution node is compromised via prompt injection, it cannot read other project secrets via contextunity.shield or execute unauthorized tools, enforcing a true Least-Privilege Architecture inside the router.
Derived Permissions
Under the Manifest-First architecture, permissions are Derived Permissions.
If a project’s contextunity.project.yaml declares that it uses a specific LLM and a specific federated tool, the SDK’s ProjectBootstrapConfig and the Router’s registration compilation automatically compute the required permission scopes and grant them to the ContextToken. You do not need to manually configure or document these low-level string grants unless you are developing a new core platform service.
Token Handling & Interceptors
Server-side: SecurityGuard + ServicePermissionInterceptor
Each service constructs its own ServicePermissionInterceptor with a service-specific RPC_PERMISSION_MAP. See contextunity.router.service.interceptors or contextunity.brain.service.interceptors for examples.
import grpcfrom contextunity.core import ( ServicePermissionInterceptor, # Server-side: checks per-RPC permissions get_security_guard, # Token validation, Shield firewall TokenMetadataInterceptor, # Client-side: injects token into metadata)
# In handler: validate token and Shield checksguard = get_security_guard()async def MyMethod(self, request, context): token = guard.validate_token(context) result = await guard.check_input(user_input) if result.blocked: context.abort(grpc.StatusCode.PERMISSION_DENIED, result.reason)Client-side: TokenMetadataInterceptor
from contextunity.core import TokenMetadataInterceptor
interceptor = TokenMetadataInterceptor(token)channel = grpc.aio.insecure_channel("brain:50051", interceptors=[interceptor])Auth Backends
The SDK uses AuthBackend for token attachment. Verification happens service-side.
from contextunity.core import ( AuthBackend, # Protocol HmacBackend, # Open Source: HMAC-SHA256 SessionTokenBackend, # Enterprise: Ed25519 signed by Shield get_signing_backend, set_signing_backend,)
# Backend is set at bootstrap (bootstrap_django / bootstrap_standalone)backend = get_signing_backend()metadata = backend.create_grpc_metadata(token) # For gRPC calls| Backend | Mode | Config Trigger |
|---|---|---|
HmacBackend | Open Source | Shield disabled + CU_PROJECT_SECRET |
SessionTokenBackend | Enterprise | services.shield.enabled in manifest + CU_SHIELD_GRPC_URL |
Redis Integrity Protection (Encrypt-then-MAC)
ContextUnity uses Redis for service discovery, ephemeral registration state,
caching, and session coordination. Redis itself does not store project HMAC
or session secrets in v1alpha8; those are resolved from environment variables
(CU_PROJECT_SECRET) or fetched from contextunity.shield at verification time.
Required Configuration for all ContextUnity platform services (Router, Brain, Worker, View, etc.):
REDIS_URL=redis://localhost:6379/0For externally hosted Redis, use TLS:
REDIS_URL=rediss://redis.example.com:6379/0Note on legacy
REDIS_SECRET_KEY: Earlier versions supported at-rest encryption of project secrets stored in Redis. v1alpha8 retires that store; project key material now comes from env or Shield. The old key variable is ignored by platform services and should be removed from deployment templates.
Service Discovery & Project Registry
To prevent tenant spoofing (“Tenant B claiming to be Project A’s owner”), ContextUnity relies on cryptographically signed ContextTokens and Shield policy.
- Token Verification (Anti-Spoofing): Every gRPC request carries a signed token. Services verify the signature against
CU_PROJECT_SECRET(HMAC) or Shield’s Ed25519 public key, then enforce that the token’sallowed_tenantscover the requested resource. - Service Discovery: Allows gRPC nodes to find each other dynamically via Redis without hardcoded IPs.
For the full implementation guide, fallback mechanisms, and Redis configuration, see Project Registry & Discovery.
Migrating from Open-Source (HMAC) to Enterprise (Shield)
To upgrade a project to the contextunity.shield zero-trust architecture:
- Deploy the contextunity.shield service and point
CU_SHIELD_GRPC_URLin the Router/Brain/Worker templates to it. - Create the project in Shield. This generates the Ed25519 keypair and an admin token:
Terminal window contextshield project-create my-project \--permissions "brain:read,brain:write,router:execute"# Output includes admin_token — save it to Ansible vault - Use the admin token to manage project permissions remotely (no
SHIELD_MASTER_KEYneeded):Terminal window contextshield project-policy my-project \--admin-token "shield-admin:my-project:Token..." \--permissions "brain:read,brain:write,router:execute" - Set
CU_SHIELD_GRPC_URLin the project’s own.env.
As soon as the SDK detects CU_SHIELD_GRPC_URL, it will automatically switch to the SessionTokenBackend handshake flow.
Open Source Mode (HMAC Keystream)
Used when deploying independent projects without the centralized Enterprise Shield.
- Config:
CU_PROJECT_SECRET(unique per project). - Backend:
HmacBackend(stdlib HMAC-SHA256). - Flow: The project’s ContextUnity SDK hashes its manifest against
CU_PROJECT_SECRETto mint an ephemeral registration token. The Router verifies this using its ownCU_PROJECT_SECRET. No Redis lookup of project secrets is performed.
Enterprise Mode (Shield Session Tokens)
Used in large, multi-tenant deployments managed by contextunity.shield.
- Config:
CU_SHIELD_GRPC_URLis set. - Backend:
SessionTokenBackend(Ed25519). - Flow: Projects establish a zero-trust binding to Shield. A project’s tools and permissions are registered out-of-band by an Infrastructure Operator using the Admin CLI (
uv run python -m contextunity.core.cli.admin sync-policy manifest.yaml). At runtime, Shield issues a short-lived Session Token signed with its private Ed25519 node key. All services verify the token instantly using Shield’s public key, without database lookups. Permissions are strictly controlled by the Shield Policy Engine, not self-declared by the project.
There is no UnsignedBackend or SECURITY_ENFORCEMENT toggle. Security is always enforced.
gRPC TLS
from contextunity.core.grpc_utils import create_channel_sync, create_channel
# TLS is automatically enabled if GRPC_TLS_ENABLED=true or the URL starts with grpcs://channel = create_channel_sync("brain.local:50051")