Security Gateway Setup¶
Deploy the CapiscIO security gateway as a reverse proxy that validates trust badges before forwarding requests to your agent.
Problem¶
You need to:
- Protect your agent's API endpoints from unauthorized access
- Validate trust badges on every incoming request
- Reject requests with invalid, expired, or missing badges
- Keep authentication logic separate from your agent code
Solution¶
Run capiscio gateway start in front of your agent to handle all badge validation automatically.
Architecture¶
┌─────────────┐ ┌─────────────────┐ ┌──────────────┐
│ Client │────▶│ CapiscIO Gateway │────▶│ Your Agent │
│ (with badge)│ │ (port 8080) │ │ (port 3000) │
└─────────────┘ └─────────────────┘ └──────────────┘
│
┌──────┴──────┐
│ Validates │
│ badges │
│ ✓ or 401 │
└─────────────┘
Quick Start¶
Local Mode (Single Key)¶
Verify badges against a single public key:
# Start your agent on port 3000
python my_agent.py # Listens on localhost:3000
# Start gateway on port 8080
capiscio gateway start \
--port 8080 \
--target http://localhost:3000 \
--local-key ./trusted-agent.pub.jwk
Now requests to localhost:8080 require a valid badge signed by the trusted key.
Cloud Mode (Registry)¶
Verify badges against the CapiscIO registry:
capiscio gateway start \
--port 8080 \
--target http://localhost:3000 \
--registry-url https://registry.capisc.io
Configuration Options¶
| Flag | Default | Description |
|---|---|---|
--port | 8080 | Port the gateway listens on |
--target | http://localhost:3000 | Your agent's URL |
--local-key | - | Path to trusted public key (JWK) |
--registry-url | - | CapiscIO registry URL |
Choose One
You must provide either --local-key OR --registry-url, not both.
Production Deployment¶
With Docker¶
FROM ghcr.io/capiscio/capiscio-core:latest
COPY trusted-keys/ /keys/
EXPOSE 8080
CMD ["gateway", "start", \
"--port", "8080", \
"--target", "http://agent:3000", \
"--local-key", "/keys/trusted.pub.jwk"]
With Docker Compose¶
version: '3.8'
services:
gateway:
image: ghcr.io/capiscio/capiscio-core:latest
command: >
gateway start
--port 8080
--target http://agent:3000
--local-key /keys/trusted.pub.jwk
ports:
- "8080:8080"
volumes:
- ./keys:/keys:ro
depends_on:
- agent
agent:
build: ./my-agent
expose:
- "3000"
# No external ports - only accessible through gateway
With Kubernetes¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: capiscio-gateway
spec:
replicas: 2
selector:
matchLabels:
app: capiscio-gateway
template:
metadata:
labels:
app: capiscio-gateway
spec:
containers:
- name: gateway
image: ghcr.io/capiscio/capiscio-core:latest
args:
- gateway
- start
- --port=8080
- --target=http://my-agent-service:3000
- --registry-url=https://registry.capisc.io
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: capiscio-gateway
spec:
selector:
app: capiscio-gateway
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
Testing the Gateway¶
Valid Request¶
# Get a badge (see badges recipe)
BADGE=$(capiscio badge issue \
--sub "did:capiscio:agent:client" \
--domain "client.example.com" \
--key ./client-private.jwk)
# Make authenticated request
curl -X POST http://localhost:8080/api/task \
-H "Authorization: Bearer $BADGE" \
-H "Content-Type: application/json" \
-d '{"task": "translate", "text": "Hello"}'
Missing Badge (401)¶
curl -X POST http://localhost:8080/api/task \
-H "Content-Type: application/json" \
-d '{"task": "translate"}'
# Response: 401 Unauthorized
# {"error": "missing authorization header"}
Invalid Badge (403)¶
curl -X POST http://localhost:8080/api/task \
-H "Authorization: Bearer invalid.token.here" \
-H "Content-Type: application/json" \
-d '{"task": "translate"}'
# Response: 403 Forbidden
# {"error": "invalid badge signature"}
Multiple Trusted Keys¶
To trust badges from multiple issuers, create a JWKS (JSON Web Key Set):
{
"keys": [
{
"kty": "OKP",
"crv": "Ed25519",
"x": "key1-public-x-value",
"kid": "partner-1",
"alg": "EdDSA"
},
{
"kty": "OKP",
"crv": "Ed25519",
"x": "key2-public-x-value",
"kid": "partner-2",
"alg": "EdDSA"
}
]
}
Then use the registry mode which supports JWKS endpoints.
Gateway Behind Load Balancer¶
When running behind a load balancer (nginx, AWS ALB, etc.):
# docker-compose.yml
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/ssl/certs:ro
depends_on:
- gateway
gateway:
image: ghcr.io/capiscio/capiscio-core:latest
command: gateway start --port 8080 --target http://agent:3000 --local-key /keys/trusted.pub.jwk
expose:
- "8080"
# nginx.conf
upstream gateway {
server gateway:8080;
}
server {
listen 443 ssl;
server_name agent.example.com;
ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/certs/key.pem;
location / {
proxy_pass http://gateway;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Monitoring¶
Logs¶
# View gateway logs
docker logs -f capiscio-gateway
# Example output:
# 2025/12/01 19:48:00 Starting Gateway in LOCAL MODE (Key: /keys/trusted.pub.jwk)
# 2025/12/01 19:48:00 Gateway listening on :8080 -> http://agent:3000
# 2025/12/01 19:48:15 [200] POST /api/task - valid badge from did:capiscio:agent:client
# 2025/12/01 19:48:20 [401] POST /api/task - missing authorization header
Metrics (Prometheus)¶
The gateway exposes metrics at /metrics:
Troubleshooting¶
"must provide either --local-key or --registry-url"¶
You need to specify how to verify badges:
# Use a local key
capiscio gateway start --local-key ./trusted.pub.jwk --target http://localhost:3000
# OR use the registry
capiscio gateway start --registry-url https://registry.capisc.io --target http://localhost:3000
"invalid target URL"¶
The target must be a valid URL:
Gateway returns 502¶
Your agent isn't reachable:
- Check agent is running:
curl http://localhost:3000/health - Check network connectivity between gateway and agent
- Verify the target URL is correct
See Also¶
- Issue and Verify Badges - Create badges for testing
- Badge Keeper - Auto-renew client badges
- CLI Reference: gateway - Full command reference