Skip to content

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

ComponentRoleRotation Interval
SPIRE AgentRuns 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-writerSidecar that fetches SVIDs from the local SPIRE agent and writes them to a shared Docker volume.Every 300 seconds (5 minutes)
nginx-federationReverse 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.

PropertyDetails
MethodmTLS via SPIRE SVID (the only accepted external auth method, EVENTSTORE_MTLS_REQUIRED=true)
IssuedDuring operator onboarding (agent.conf, x509pop attestation certs, trust bundle)
SVID RotationAutomatic every 300 seconds (no manual intervention)
Legacy: X-Federation-LicenseDEACTIVATED -- rejected with 403 (EVENTSTORE_MTLS_REQUIRED=true)
Legacy: FEDERATION_LICENSE_KEYEnv 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:

PriorityMethodMechanismStatus
1 (only)mTLSClient certificate verified via SPIRE trust bundleACTIVE
--X-Federation-LicenseLicense key headerDEACTIVATED (403)
--X-Internal-KeyInternal 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:

EffectTiming
EventStore rejects new eventsImmediate (mTLS handshake fails)
Federation sync stopsWithin 60 seconds (cache TTL)
Cross-registry transfers blockedImmediate
Your agents removed from federation discoveryWithin 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 TypeEmitted ByNotes
TokensTransferredRegistryAll token transfers between agents
TransactionFeeCollectedRegistryFee deductions on transfers
TokensStakedRegistryStaking and unstaking operations
TokensIssuedTEG onlyMinting -- disabled in federated mode
CrossRegistryTransferCompletedRegistryAudit trail only (not counted in supply projection)
RewardsDistributedRegistryAudit 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:

  1. Configuration: MINTING_AUTHORITY=disabled in your operator compose file
  2. Policy gate: TokensIssued events from federated registries are rejected by the EventStore
  3. 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.

nginx
# 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):

EndpointPurpose
POST /api/v1/events/Write events to the EventStore
GET /api/v1/federation/agent-cardsSync agent cards across registries
POST /api/v1/federation/sync-requestPush-based federation sync
POST /internal/federation/queryCross-registry agent lookup
POST /api/v1/cross-teg/transferCross-registry transfer initiation

Security Incident Response

Step 1: Identify

Check cert-writer and nginx logs for certificate errors:

bash
# 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 -20

Step 2: Verify SPIRE Agent Health

bash
docker exec ${REGISTRY_NAME}-spire-agent /opt/spire/bin/spire-agent healthcheck

A healthy agent returns:

Agent is healthy.

If unhealthy, restart the SPIRE agent:

bash
docker compose -f docker-compose.operator.yml restart spire-agent

Then wait 60 seconds and restart cert-writer:

bash
docker compose -f docker-compose.operator.yml restart cert-writer

Step 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):

  1. Run the generate-operator-env.sh script to generate new credentials
  2. Update your .env.operator file with the new values
  3. Restart your stack:
bash
docker compose -f docker-compose.operator.yml down
docker compose -f docker-compose.operator.yml up -d

Note: 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

ItemHow to Verify
SPIRE agent healthydocker exec ${REGISTRY_NAME}-spire-agent /opt/spire/bin/spire-agent healthcheck
cert-writer runningdocker logs ${REGISTRY_NAME}-cert-writer --tail 5 (should show recent SVID fetch)
nginx-federation accepting connectionscurl -k https://localhost:<federation-port>/health from the host (the federation sidecar's published port)
SPIRE x509pop certs valid / auto-rotatingSuccessful EventStore writes (check registry logs for 401/403 errors)
Minting disabledMINTING_AUTHORITY=disabled in .env.operator
Database passwords not defaultVerify .env.operator contains generated passwords
Docker images up to datedocker compose -f docker-compose.operator.yml pull (check for updates regularly)

Server components AGPL-v3 · client SDK Apache-2.0. If a doc and the running stack disagree, trust the stack.