Advisory network-egress verdicts and binary-hash attestation for AI agent ecosystems.
⚠️ Read this first. Aegis is an advisory verdict service, not a network control point. It answers "should this connection be allowed?" — it does not intercept, proxy, or block traffic itself. The surrounding agent harness must honor the verdicts. See Not yet implemented before evaluating Aegis as a security control, and docs/THREAT-MODEL.md for the trust boundaries.
Aegis is a small HTTP API (axum + SQLite) that exposes:
An agent (or its harness) asks Aegis whether a destination is permitted before connecting:
curl -s -X POST http://127.0.0.1:8686/api/egress/check \
-H 'Content-Type: application/json' \
-d '{"agent_id": "research-agent", "destination": "https://api.github.com"}'- Allowed:
200with{"allowed": true, ...}. - Denied:
403and the attempt is recorded in the audit log with a reason (explicit deny rule, no matching allow under default-deny, or missing attestation).
Policy semantics: per-agent destination rules where *.github.com matches
subdomains only, deny always wins over allow, unknown destinations fall
through to the configured default_policy (default: deny). Host parsing is
hardened against userinfo/trailing-dot/case/IPv6-bracket tricks and fails closed
on ambiguous input.
The caller does. Aegis returns a verdict and writes an audit row; it cannot
see or stop the actual network connection. Enforcement happens when your agent
harness, wrapper script, or platform treats a non-200 response as "refuse to
dial":
verdict = requests.post(f"{AEGIS}/api/egress/check",
json={"agent_id": aid, "destination": url})
if verdict.status_code != 200:
raise Blocked(f"aegis denied {url}: {verdict.text}")
# only now connectIf a compromised agent skips the check call, Aegis will never know. There is no interception layer (yet) that makes checking unavoidable.
require_attestation = true denies egress to any agent_id not registered via
the admin-only POST /api/attestation/attestate. Registration computes a
SHA-256 of the caller-supplied binary_path and stores (agent_id, hash).
What this honestly means:
- The hashed file is self-reported: whoever registers chooses which file is hashed. This proves nothing about what the agent process is actually running.
/api/attestation/verifyis an equality check ("does this path's hash / supplied hash match what was registered?"). Nothing more.- A stored hash verifies binary integrity across restarts only when the reference hash was distributed out-of-band (e.g., provisioned by your deploy tooling). If the registrant is the agent itself, the hash is just a claim.
- Because registration is admin-gated and the data plane has no per-agent
authentication, anyone who can reach the API can reuse an already-registered
agent_id. Per-agent credentials are on the roadmap.
See docs/THREAT-MODEL.md for the full analysis.
An optional, deliberately crude check: maps a destination's top-level domain to
a coarse region (e.g. .cn, .ru, EU-country TLDs) and rejects blocked
regions. This is not real GeoIP — a .com domain hosted anywhere maps to
US, and the lookup is trivially influenced by choosing a domain name. Treat it
as a demo-grade heuristic.
- Admin endpoints (policy CRUD, attestation registration/listing, audit reads)
require
Authorization: Bearer $AEGIS_ADMIN_TOKEN, compared in constant time via SHA-256 digests. Release builds refuse to start without a token unlessAEGIS_INSECURE_DEV=1is set explicitly. - Binds to
127.0.0.1by default; CORS is deny-by-default with an explicit origin allowlist. - Every check (allowed or blocked) is appended to a SQLite
egress_logwith timestamp, reason, and status; readable via admin-only endpoints. Rows older thanlog_retention_days(default 30) are deleted by an hourly background prune and on demand viaPOST /api/egress/prune; prune counters appear in/api/egress/stats. - Fail-fast strict config validation; graceful shutdown on SIGINT/SIGTERM; blocking DB work stays off the async runtime.
The following are not in the codebase, despite earlier versions of this README claiming them. Do not rely on them:
- Proxy interception. Aegis is not an HTTP(S) proxy. There is no
CONNECThandling, no TLS termination/inspection, no transparent traffic capture, and no way to force traffic through Aegis. SettingHTTP_PROXY/HTTPS_PROXYto Aegis does nothing useful today. - Rate limiting, bandwidth, connection and request-size controls. The
config keys
max_request_size_bytes,max_connections_per_agent, andbandwidth_limit_kbpsexist but are not enforced anywhere. - Real Geo-IP data residency. Only the TLD heuristic described above.
- Per-agent authentication on the data plane (agent identity is a client-supplied string).
- Measured runtime attestation (hashing the actual executable of the calling process) and cryptographic attestation tokens.
Tracking issues describe the plan for each of these.
cargo build --release
aegis init # writes config.toml (defaults below)
export AEGIS_ADMIN_TOKEN="$(openssl rand -hex 32)"
./target/release/aegis serve --config config.toml
# Listening on 127.0.0.1:8686| Endpoint | Auth | Purpose |
|---|---|---|
GET /health |
none | liveness (process up; no dependencies checked) |
GET /health/live |
none | liveness probe alias (#6) |
GET /health/ready |
none | readiness — 200 only after a live DB round-trip, 503 otherwise (#6) |
GET /metrics |
none | Prometheus scrape: decision counter by outcome, decision latency histogram, active-policies gauge (#6) |
POST /api/egress/check |
none* | egress verdict (data plane) |
POST /api/geo/check |
none* | coarse residency verdict |
POST /api/attestation/verify |
none* | hash equality check |
GET/POST /api/egress/policies/{agent_id} |
bearer | inspect / add policies |
DELETE /api/egress/policies/{agent_id}/{id} |
bearer | remove a policy |
GET /api/egress/log?limit=N |
bearer | recent audit rows |
GET /api/egress/stats |
bearer | aggregate counts + prune counters |
POST /api/egress/prune |
bearer | delete audit rows older than log_retention_days |
POST /api/attestation/attestate |
bearer | register (agent_id, sha256(path)) |
GET /api/attestation/agents |
bearer | registered agents |
* Data-plane endpoints have no authentication; protect them at the network layer (loopback/firewall) and treat reachability as authorization. See the threat model.
Audit fidelity (#7): every egress_log row records the request's true
metadata — the client IP (direct socket peer; X-Forwarded-For is honored
only from [server] trusted_proxies), the actual HTTP method, and the buffered
request-body size. Rows also carry the raw XFF chain and user agent for
provenance. Databases created by older builds migrate in place on startup
(versioned via PRAGMA user_version; historical rows keep their original
values).
Metrics (#6): GET /metrics serves three bounded-cardinality families in
Prometheus text format — aegis_egress_decisions_total{outcome} (verdicts of
/api/egress/check and /api/geo/check, with outcome one of allowed,
blocked for policy denials, or error for infrastructure faults),
aegis_egress_check_latency_seconds{route} (wall-clock decision latency,
including requests that fail validation), and aegis_active_policies (policy
rows, counted in SQLite at scrape time). No per-agent or per-destination
labels are ever exported.
Minimal config (config.toml):
[server]
host = "127.0.0.1"
port = 8686
# Proxies trusted to set X-Forwarded-For (#7). Empty = XFF never honored.
trusted_proxies = []
[database]
path = "/var/lib/aegis/aegis.db"
[egress]
default_policy = "deny"
# Audit rows older than this are pruned hourly (and via POST /api/egress/prune).
log_retention_days = 30
[attestation]
enabled = true
require_attestation = false # flip to true to gate egress on registration
[geo]
enabled = false
blocked_regions = []Governance Hub is the unified admin console and sole browser-facing product. The backend control plane is:
Hive Argus Patroclus Relay Miser Sentiel Aegis Forge
───── ───── ───────── ───── ───── ─────── ───── ─────
Agent OIDC Authz MCP Cost Observability Egress Supply Chain
Runtime Identity Infrastructure Gateway Optimization & DLP Verdicts Trust
& Orchestration & Policy & Search ```
Aegis complements Patroclus (which tools may an agent use) and Relay (which MCP
gateways mediate tool calls) by answering which raw network destinations an
agent intends to reach — *provided callers ask and obey*. Integrate by calling
`/api/egress/check` from the agent harness before each outbound connection.
## Status
**Early development.** The documentation above reflects the code as it exists;
features listed under [Not yet implemented](#not-yet-implemented) should be
assumed absent until they appear in this repository with tests.
## License
MIT