A station verification service for enforcing station compliance and proving runtime integrity in confidential runtimes (Azure ACI Confidential Containers).
OA-Verifier provides verifier-side evidence and enforcement for station governance:
- The exact runtime policy measured - via attested CCE policy hash
- No runtime tampering of measured policy path - via AMD SEV-SNP attestation
- Station compliance enforcement - via toggle checks and ownership/signature verification
- Verifier role: station compliance enforcer, not prompt/response transport.
- Prompt/response path: end user client -> provider.
- Governance path: station registration, signature checks, toggle checks.
- Required anti-forgery verification inputs: registry station authorization, org signature/public-key path, provider account-state APIs.
See:
| Station Type | Verification |
|---|---|
| OpenRouter Stations | Privacy toggles, API key ownership, account binding |
| Future Station Types | Planned extension for other provider/enclave-based services |
Anyone can verify the service is running expected code:
# Fetch attestation from live service
curl -sS "https://verifier.openanonymity.ai/attestation?nonce=$(date +%s)" | jq .summary
# Returns hardware-signed proof including:
# - cce_policy_hash: SHA256 of the container policy (what code can run)
# - attestation_type: sevsnpvm (AMD SEV-SNP)
# - debug_disabled: true (no debugging possible)# Clone and run local verification script
git clone https://github.com/openanonymity/oa-verifier
cd oa-verifier
./scripts/verify-local.sh https://verifier.openanonymity.aiThis rebuilds the container locally with Nix and compares the policy hash against what Azure hardware attests.
For strict zero-trust conclusions, also verify the JWT signature using the verify_at key endpoint returned by /attestation.
Source Code (this repo)
↓ [Nix reproducible build]
Container Image (deterministic hash)
↓ [CCE policy generated from image]
Policy Hash (SHA256 of allowed container config)
↓ [Measured by AMD SEV-SNP hardware]
Attestation JWT (signed by Azure MAA)
↓ [Verifiable by anyone]
Proof: "This exact code is running in an isolated enclave"
| Endpoint | Method | Description |
|---|---|---|
/attestation |
GET | Hardware attestation JWT with policy hash |
/attestation/raw |
GET | JSON response containing token |
/broadcast |
GET | List of verified and banned stations |
| Endpoint | Method | Description |
|---|---|---|
/register |
POST | Register station with Ed25519 public key |
/submit_key |
POST | Submit double-signed API key for verification |
/station/{public_key} |
GET | Get station info by public key |
/banned-stations |
GET | List banned stations |
| Layer | Protection | Verification |
|---|---|---|
| Source | Public, auditable | You read it |
| Build | Nix reproducible | Rebuild locally |
| Image | Sigstore signed | cosign verify |
| Runtime | AMD SEV-SNP enclave | MAA attestation |
| Network | TLS terminates in enclave | Channel binding hash |
- Memory isolation: Hypervisor cannot read enclave memory
- No stdio: Container cannot write to stdout/stderr (policy enforced)
- No debugging: Debug mode disabled in hardware
- Measured boot: Only the attested container can run
- TLS channel binding: The TLS certificate is generated inside the enclave and its public key hash is included in the hardware attestation. This means MITM is impossible -- you can verify the TLS public key hash from
/attestationmatches the certificate presented by the server, proving your connection terminates inside the attested enclave
# Build server
go build -o oa-verifier ./cmd/verifier
# Run locally (without attestation)
./oa-verifier -local
# Run with attestation (requires Azure environment)
./oa-verifier -attestation# Build container with deterministic hash
nix build .#container
# Load and inspect
docker load < result
docker inspect oa-verifier:latestSee deploy/README.md for details.
| Variable | Description |
|---|---|
MAA_ENDPOINT |
Azure MAA sidecar endpoint |
STATION_REGISTRY_URL |
Station registry service |
STATION_REGISTRY_SECRET |
Registry auth secret |
TLS_DOMAIN |
Custom domain for Let's Encrypt |
CHALLENGE_MIN_INTERVAL |
Min seconds between privacy checks |
CHALLENGE_MAX_INTERVAL |
Max seconds between privacy checks |
SUBMIT_KEY_OWNERSHIP_GRACE_SECONDS |
Grace window for ownership checks |
STATION_FAILURE_GRACE_SECONDS |
Grace window before unregistering on transient failures |
- Trust Model - Role boundaries, data flow, guarantees/non-goals, unlinkability model
- Attestation Deep Dive - How zero-trust verification works
- Deployment Guide - CI/CD and Azure setup
GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).