Operator Guide: Security Architecture
Audience: Federated registry operators Last Updated: 2026-06-04
Overview
All cross-registry communication in TheProtocol is secured by mutual TLS (mTLS) via SPIRE SVIDs. Your operator stack includes a SPIRE agent that attests via x509pop (x509 Proof of Possession) attestation certificates and automatically fetches and rotates cryptographic identities, a cert-writer sidecar that writes certificates to a shared volume, and an nginx-federation proxy that enforces client certificate validation on all inbound federation traffic.
mTLS Architecture
How It Works
Components
| Component | Role | Rotation Interval |
|---|---|---|
| SPIRE Agent | Runs in your stack. Attests workload identity via x509pop attestation certificate to the TheProtocol SPIRE Server. Fetches X.509 SVIDs. Unlike join tokens, x509pop survives restarts. | Continuous (auto-renewed before expiry) |
| cert-writer | Sidecar that fetches SVIDs from the local SPIRE agent and writes them to a shared Docker volume. | Every 300 seconds (5 minutes) |
| nginx-federation | Reverse proxy for federation endpoints. Presents your SVID as the server certificate. Validates incoming peer client certificates against the SPIRE trust bundle. | N/A (reads certs from shared volume) |
Trust Domain
All SVIDs belong to the trust domain example.com. Your registry's SPIFFE ID follows the pattern:
spiffe://example.com/service/registry-<your-operator-name>Federation Authentication
Your registry authenticates to the TheProtocol EventStore and federation network exclusively via mTLS using SPIRE SVIDs.
| Property | Details |
|---|---|
| Method | mTLS via SPIRE SVID (the only accepted external auth method, EVENTSTORE_MTLS_REQUIRED=true) |
| Issued | During operator onboarding (agent.conf, x509pop attestation certs, trust bundle) |
| SVID Rotation | Automatic every 300 seconds (no manual intervention) |
Legacy: X-Federation-License | DEACTIVATED -- rejected with 403 (EVENTSTORE_MTLS_REQUIRED=true) |
Legacy: FEDERATION_LICENSE_KEY | Env var exists in code but is NOT used for authentication |
Authentication Priority
When your registry communicates with the mainframe, authentication is checked in this order:
| Priority | Method | Mechanism | Status |
|---|---|---|---|
| 1 (only) | mTLS | Client certificate verified via SPIRE trust bundle | ACTIVE |
| -- | X-Federation-License | License key header | DEACTIVATED (403) |
| -- | X-Internal-Key | Internal API key (intra-stack only) | Active (internal) |
Federation license auth is deactivated (EVENTSTORE_MTLS_REQUIRED=true). All external writes require mTLS.
SPIRE Attestation Revocation
If your SPIRE x509pop attestation is revoked by the mainframe:
| Effect | Timing |
|---|---|
| EventStore rejects new events | Immediate (mTLS handshake fails) |
| Federation sync stops | Within 60 seconds (cache TTL) |
| Cross-registry transfers blocked | Immediate |
| Your agents removed from federation discovery | Within minutes |
Total network isolation: under 2 minutes (economic quarantine).
If you believe your attestation was revoked in error, contact the operator of your parent frame immediately.
Event Emission Policies
Your registry emits events to the EventStore according to a policy table (a live DB count, currently 100+ rows). Each row has explicit flags controlling which layer is authorized to emit it.
Key Policies
| Event Type | Emitted By | Notes |
|---|---|---|
TokensTransferred | Registry | All token transfers between agents |
TransactionFeeCollected | Registry | Fee deductions on transfers |
TokensStaked | Registry | Staking and unstaking operations |
TokensIssued | TEG only | Minting -- disabled in federated mode |
CrossRegistryTransferCompleted | Registry | Audit trail only (not counted in supply projection) |
RewardsDistributed | Registry | Audit trail only (underlying transfer already counted) |
Why Minting is Disabled
In federated mode, your registry cannot mint new AVT tokens. This is enforced at three levels:
- Configuration:
MINTING_AUTHORITY=disabledin your operator compose file - Policy gate:
TokensIssuedevents from federated registries are rejected by the EventStore - Supply audit: Any supply discrepancy triggers a BREACH alert (checked every 60 seconds)
This prevents rogue supply inflation across the federation.
mTLS Through Public Nginx
If you expose your registry behind a public nginx reverse proxy (e.g., with a custom domain and Let's Encrypt wildcard certificate), you need to handle mTLS passthrough for federation traffic.
How It Works
Your public nginx uses ssl_verify_client optional_no_ca on federation endpoints. This accepts mTLS client certificates from federation peers without requiring a specific CA on the nginx side. The certificate is passed through to the registry backend, which validates it against the SPIRE trust bundle.
# Public nginx config for federation endpoints
server {
listen 443 ssl;
server_name your-registry.example.com;
ssl_certificate /etc/letsencrypt/live/your-registry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-registry.example.com/privkey.pem;
# Accept mTLS client certs without CA validation at nginx level
ssl_verify_client optional_no_ca;
location /api/v1/federation/ {
proxy_set_header X-SSL-Client-Cert $ssl_client_escaped_cert;
proxy_pass http://localhost:<registry-port>;
}
location / {
proxy_pass http://localhost:<registry-port>;
}
}Wildcard Certificate Management
For operators with custom domains, use a wildcard certificate (e.g., *.your-registry.example.com) managed via Let's Encrypt DNS-01 challenge or your preferred CA. The nginx-federation sidecar in your operator stack uses SPIRE SVIDs for inter-registry mTLS -- the public wildcard cert is only for user-facing HTTPS.
Endpoints Protected by Federation Auth
The following endpoints require federation authentication (mTLS only):
| Endpoint | Purpose |
|---|---|
POST /api/v1/events/ | Write events to the EventStore |
GET /api/v1/federation/agent-cards | Sync agent cards across registries |
POST /api/v1/federation/sync-request | Push-based federation sync |
POST /internal/federation/query | Cross-registry agent lookup |
POST /api/v1/cross-teg/transfer | Cross-registry transfer initiation |
Security Incident Response
Step 1: Identify
Check cert-writer and nginx logs for certificate errors:
# Check cert-writer health
docker logs ${REGISTRY_NAME}-cert-writer --tail 50
# Check nginx-federation for TLS errors
docker logs ${REGISTRY_NAME}-nginx-federation --tail 50
# Check registry logs for auth failures
docker logs ${REGISTRY_NAME}-registry 2>&1 | grep -i "401\|403\|unauthorized" | tail -20Step 2: Verify SPIRE Agent Health
docker exec ${REGISTRY_NAME}-spire-agent /opt/spire/bin/spire-agent healthcheckA healthy agent returns:
Agent is healthy.If unhealthy, restart the SPIRE agent:
docker compose -f docker-compose.operator.yml restart spire-agentThen wait 60 seconds and restart cert-writer:
docker compose -f docker-compose.operator.yml restart cert-writerStep 3: Escalate
If the issue persists after restarting SPIRE agent and cert-writer, escalate to the operator of your parent frame:
- Email: security@example.com
- Include: Container logs, your operator name, your registry DID, and the timestamp of the issue
Secret Rotation
To rotate your stack secrets (database passwords, Redis password, internal keys):
- Run the
generate-operator-env.shscript to generate new credentials - Update your
.env.operatorfile with the new values - Restart your stack:
docker compose -f docker-compose.operator.yml down
docker compose -f docker-compose.operator.yml up -dNote: SPIRE SVIDs auto-rotate every 300 seconds. No manual credential rotation is required. Your SPIRE agent uses x509pop attestation certificates that survive restarts -- if your agent loses connectivity, a simple restart is sufficient to re-attest.
Security Checklist
| Item | How to Verify |
|---|---|
| SPIRE agent healthy | docker exec ${REGISTRY_NAME}-spire-agent /opt/spire/bin/spire-agent healthcheck |
| cert-writer running | docker logs ${REGISTRY_NAME}-cert-writer --tail 5 (should show recent SVID fetch) |
| nginx-federation accepting connections | curl -k https://localhost:<federation-port>/health from the host (the federation sidecar's published port) |
| SPIRE x509pop certs valid / auto-rotating | Successful EventStore writes (check registry logs for 401/403 errors) |
| Minting disabled | MINTING_AUTHORITY=disabled in .env.operator |
| Database passwords not default | Verify .env.operator contains generated passwords |
| Docker images up to date | docker compose -f docker-compose.operator.yml pull (check for updates regularly) |