Kubernetes Integration

This guide covers how to deploy and operate Tenuo in Kubernetes.


Architecture Overview

┌─────────────────────────────────────────────────────────────────────────┐
│                           YOUR CLUSTER                                   │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌──────────────┐      ┌──────────────────────────────────────────┐    │
│   │              │      │              AGENT POD                    │    │
│   │   CONTROL    │      │  ┌─────────────────┐  ┌───────────────┐  │    │
│   │    PLANE     │◄────►│  │ tenuo-authorizer│  │  Your Agent   │  │    │
│   │              │      │  │   (sidecar)     │◄─┤               │  │    │
│   │ • Issues     │      │  │                 │  │ • LangChain   │  │    │
│   │   warrants   │      │  │ • Verifies      │  │ • LangGraph   │  │    │
│   │ • Holds root │      │  │   warrants      │  │ • Your code   │  │    │
│   │   key        │      │  │ • Checks PoP    │  │               │  │    │
│   │              │      │  │ • ~27μs         │  │ • Holds       │  │    │
│   │  (you build  │      │  │                 │  │   keypair     │  │    │
│   │   this)      │      │  │(tenuo/authorizer)│ │               │  │    │
│   └──────────────┘      │  └─────────────────┘  └───────────────┘  │    │
│                         └──────────────────────────────────────────┘    │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Components

Component What It Does Who Provides It
Control Plane Issues warrants, holds root signing key You build this
tenuo-authorizer Verifies warrants, checks PoP, returns allow/deny Tenuo (tenuo/authorizer image)
Agent Executes tasks, holds keypair for PoP signatures You build this

Authorizer Deployment Options

Option Description Best For
Sidecar Per-pod container Fine-grained control
Gateway Cluster-wide via Envoy/Istio Centralized policy
SDK only No separate container Simple deployments

Quickstarts

Get a working setup in 5 minutes:


Helm Chart

For production deployments, use the official Helm chart:

helm install tenuo-authorizer ./charts/tenuo-authorizer \
  --namespace tenuo-system --create-namespace \
  --set config.trustedRoots[0]="YOUR_CONTROL_PLANE_PUBLIC_KEY"

The chart includes:

  • High Availability: Pod anti-affinity, PodDisruptionBudget
  • Autoscaling: HPA support with sensible defaults
  • Security: Non-root, read-only filesystem, minimal capabilities
  • Gateway Config: Full tool/route extraction via ConfigMap

See charts/tenuo-authorizer/README.md for full configuration options.


Choosing a Pattern

Pattern Warrant Scope Complexity Best For
Control Plane Fetch Per-task Medium Task-scoped authority ✅
Request Header Per-request Medium Ingress injects warrants
Environment Variable Per-pod Low Batch jobs, prototyping

Decision Flowchart

Is warrant scope static for the pod lifetime?
├── Yes → Environment Variable (simple, but loses task-scoping)
└── No  → Does your ingress/mesh inject warrants?
          ├── Yes → Request Header
          └── No  → Control Plane Fetch ✅ (recommended)

Fetch a warrant from your control plane when each task starts. This is the canonical pattern that Tenuo was designed for.

When to use: Production systems where you want task-scoped, short-lived authority.

async def handle_task(user_request: str):
    # Fetch warrant scoped to this task
    warrant = await control_plane.get_warrant(
        tools=["read_file"],
        constraints={"path": "/data/reports/*"},
        ttl=60
    )
    
    with warrant_scope(warrant), key_scope(keypair):
        result = await agent.invoke(user_request)
    
    # Warrant expires — no cleanup

📄 Full code: proxy-configs.md#control-plane-fetch


Pattern: Request Header

Warrant passed per-request via X-Tenuo-Warrant header. Your ingress or mesh injects the warrant.

When to use: You have infrastructure that can inject warrants (API gateway, service mesh).

@app.middleware("http")
async def tenuo_middleware(request: Request, call_next):
    warrant = Warrant.from_base64(request.headers["X-Tenuo-Warrant"])
    with warrant_scope(warrant), key_scope(keypair):
        return await call_next(request)

📄 Full code: proxy-configs.md#request-header


Pattern: Environment Variable

Warrant loaded at pod startup from a Secret.

When to use: Batch jobs, static workloads, or initial prototyping.

env:
- name: TENUO_WARRANT_BASE64
  valueFrom:
    secretKeyRef:
      name: tenuo-credentials
      key: WARRANT_BASE64

📄 Full code: proxy-configs.md#environment-variable

⚠️ Anti-Pattern Warning

Long-lived warrants in environment variables defeat Tenuo’s purpose:

# ❌ 24-hour warrant in env var = IAM with extra steps
env:
  - name: TENUO_WARRANT_BASE64
    value: "eyJ..."  # TTL: 86400s

# ✅ Short-lived, per-task warrants from control plane

Deploying the Authorizer

As Sidecar

containers:
- name: tenuo-authorizer
  image: tenuo/authorizer:0.1
  ports:
  - name: metrics
    containerPort: 9090
  env:
  - name: TRUSTED_ISSUERS
    value: "<control-plane-public-key-hex>"
  resources:
    requests: { memory: "32Mi", cpu: "10m" }
    limits: { memory: "64Mi", cpu: "100m" }
- name: agent
  # Your agent container

As Gateway

See Envoy config or Istio config.


Key Rotation

Rotate signing keys without downtime.

Steps

  1. Add new key to trusted issuers ```yaml env:
    • name: TRUSTED_ISSUERS value: “OLD_KEY_HEX,NEW_KEY_HEX” ```
  2. Roll out authorizer
    kubectl rollout restart deployment/tenuo-authorizer
    
  3. Update control plane to sign with new key

  4. Wait for old warrants to expire (max TTL window)

  5. Remove old key ```yaml env:
    • name: TRUSTED_ISSUERS value: “NEW_KEY_HEX” ```

Rollback: Re-add old key to TRUSTED_ISSUERS.


Security Checklist

Practice Why
K8s Secrets, not ConfigMaps Secrets can be encrypted at rest
SigningKey per workload Limits blast radius
Short TTLs (60-300s) Stolen warrants expire quickly
Network policies Restrict control plane access
Verify SA tokens in control plane Prevent warrant spoofing

SigningKey Strategy

Strategy Security Complexity
Per-pod Best High
Per-deployment Good Medium ✅
Shared Weak Low

Debugging Denials

Structured Logs

{
  "level": "warn",
  "event": "authorization_denied",
  "reason": "constraint_violation",
  "tool": "read_file",
  "constraint": "path",
  "expected": "Pattern(/data/*)",
  "actual": "/etc/passwd"
}

Tail Denials

# All denials
kubectl logs -l app=tenuo-authorizer -f | \
  jq 'select(.event == "authorization_denied")'

# By tool
kubectl logs -l app=tenuo-authorizer -f | \
  jq 'select(.tool == "read_file")'

# Count by reason (last hour)
kubectl logs -l app=tenuo-authorizer --since=1h | \
  jq -r 'select(.event == "authorization_denied") | .reason' | \
  sort | uniq -c | sort -rn

Debug Headers (Non-Production)

env:
- name: DEBUG_MODE
  value: "true"  # ⚠️ Non-production only

Denied responses include X-Tenuo-Deny-Reason:

HTTP/1.1 403 Forbidden
X-Tenuo-Deny-Reason: constraint_violation: path=/etc/passwd not in Pattern(/data/*)

Common Denial Reasons

Reason Cause Fix
tool_not_in_warrant Tool not authorized Issue warrant with correct tools
constraint_violation Argument out of bounds Check constraints or widen warrant
warrant_expired TTL passed Issue new warrant or increase TTL
missing_pop No PoP signature Ensure keypair is set in context
invalid_pop Wrong keypair Check keypair matches warrant holder
chain_invalid Broken delegation chain Verify issuer chain

CLI Debugging

# Decode and inspect warrant contents
tenuo decode $WARRANT

# Output shows: ID, issuer, holder, tools, TTL, constraints

Metrics

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: tenuo-authorizer
spec:
  selector:
    matchLabels:
      app: tenuo-authorizer
  podMetricsEndpoints:
  - port: metrics
Metric Description
tenuo_authz_total{result,tool} Decision counts
tenuo_authz_duration_seconds Latency histogram
tenuo_warrant_ttl_remaining_seconds Time until expiry

See Also