diff --git a/CHANGELOG.md b/CHANGELOG.md index bd0972b..4f8665c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added — Diagram documentation pages + README fix (2026-04-13) + +- Token lifecycle and security topology diagrams now have dedicated markdown pages (`docs/token-lifecycle.md`, `docs/security-topology.md`) with context tables and navigation. Architecture doc links updated. +- README: fixed "Key works for everything, forever" — IAM keys don't work like that. Changed to "Key is over-permissioned and long-lived." + ### Added — AgentWrit logo (2026-04-13) - README hero image added — centered logo at `docs/diagrams/agentwrit-logo.png`. diff --git a/README.md b/README.md index b0e053f..77dff07 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,16 @@ Think of it as an issuer of legal **writs** for software: narrow authority, time ### Why this matters -| Without AgentWrit | With AgentWrit | +Traditional IAM was built for humans and long-running services — not for AI agents that spin up, do one task, and disappear. Agents are ephemeral, task-scoped, and delegate to other agents. They need credentials that match that lifecycle. AgentWrit was purpose-built for it. + +| Traditional IAM for agents | AgentWrit | |---|---| -| Agent gets a long-lived API key | Agent requests a token per task | -| Key works for everything, forever | Token works for one task, expires in minutes | -| Leaked key = full blast radius | Leaked token = one task, already expiring | -| Revocation is slow and manual | Revocation is instant at 4 levels | -| No record of what was issued | Every credential event is audited in a tamper-evident hash chain | +| Agents get static API keys or service account credentials designed for long-running services | Each agent requests a token scoped to one task | +| Credentials are over-permissioned because scoping per-task is manual and fragile | Scope attenuation is automatic — permissions only narrow, never expand | +| Leaked credential exposes everything the service account can access | Leaked token exposes one task, already expiring in minutes | +| Revoking a static key means rotating it everywhere it's used | Revocation is instant at 4 levels — token, agent, task, or delegation chain | +| No visibility into which agent used which credential for which task | Every credential event is audited per-agent, per-task in a tamper-evident hash chain | +| No native concept of agent-to-agent delegation | Delegation is built in — Agent A can delegate narrower-scoped tokens to Agent B with full chain tracking | > **What the audit trail covers:** The broker logs credential lifecycle events — issue, renew, revoke, delegate, release, auth failures, and scope violations. It does not see what the agent does with the token at the resource server. diff --git a/docs/architecture.md b/docs/architecture.md index 2ca72cc..e4c76da 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -14,7 +14,7 @@ AgentWrit sits between AI agents and the resources they need to access, providin AgentWrit Architecture Overview

-> **More diagrams:** [Token Lifecycle](diagrams/token-lifecycle.svg) · [Security Topology](diagrams/security-topology.svg) +> **More diagrams:** [Token Lifecycle](token-lifecycle.md) · [Security Topology](security-topology.md) **Broker** (`cmd/broker`) -- The central authority. Loads or generates a persistent Ed25519 signing key (`internal/keystore`), issues EdDSA-signed JWTs, validates challenge-response registrations, manages scope attenuation, delegation, revocation, and maintains a hash-chained audit trail. All endpoints use `application/json` with RFC 7807 error responses. diff --git a/docs/security-topology.md b/docs/security-topology.md new file mode 100644 index 0000000..464da68 --- /dev/null +++ b/docs/security-topology.md @@ -0,0 +1,35 @@ +# Security Topology & Trust Boundaries + +How AgentWrit's three trust zones — Operator, App, and Agent — enforce the principle of least privilege through nested scope boundaries. + +

+ Security Topology +

+ +## The three zones + +| Zone | Actor | Trust level | What they control | +|------|-------|------------|-------------------| +| **Zone 1 — Operator** | Human operator using `awrit` CLI | Highest | Admin secret, app registration with scope ceilings, 4-level revocation, audit trail inspection, token TTL configuration | +| **Zone 2 — App** | Automated software (SDK or HTTP client) | Medium | Client credential auth, launch token creation bounded by scope ceiling, agent provisioning | +| **Zone 3 — Agent** | AI agent doing work | Lowest | Ed25519 keypair (no shared secret), scoped JWT bounded by launch token, renewal, delegation (narrower only), release | + +## How scope narrows through the zones + +1. **Operator** registers an app with a scope ceiling — the maximum permissions any agent under this app can ever hold. +2. **App** authenticates and creates a launch token. The launch token's `allowed_scope` must be a subset of the app's ceiling. +3. **Agent** registers with the launch token and requests a scope. The requested scope must be a subset of the launch token's `allowed_scope`. +4. **Delegation** narrows further — Agent A can delegate to Agent B, but only with the same or narrower scope. Never wider. + +Scopes only move in one direction: down. Every boundary is enforced at issuance time, not at validation time. + +## Security properties + +- **Challenge-response** — Ed25519 keypair per agent instance. No shared secrets at the agent level. +- **Hash-chain audit** — tamper-evident trail with 24 event types. Each record hashes the previous. +- **Scope attenuation** — scopes can only narrow, never escalate. Delegation preserves the original principal. +- **Token TTL** — default 5 minutes, max 24 hours (configurable). Per-app override available. Revocable at 4 levels. + +--- + +*Back to [Architecture](architecture.md) · [Concepts](concepts.md)* diff --git a/docs/token-lifecycle.md b/docs/token-lifecycle.md new file mode 100644 index 0000000..2d2148a --- /dev/null +++ b/docs/token-lifecycle.md @@ -0,0 +1,29 @@ +# Token Lifecycle + +How an AgentWrit token moves from issuance through renewal, delegation, revocation, release, and expiration. + +

+ Token Lifecycle +

+ +## The five phases + +| Phase | What happens | API | +|-------|-------------|-----| +| **Setup** | Operator registers an app with a scope ceiling. App authenticates with client credentials. | `awrit app register`, `POST /v1/app/auth` | +| **Launch Token** | App (or admin) creates a launch token bounded by the scope ceiling. | `POST /v1/app/launch-tokens`, `POST /v1/admin/launch-tokens` | +| **Agent Registration** | Agent gets a challenge nonce, signs it with Ed25519, registers with the launch token. Receives a scoped JWT and SPIFFE identity. | `GET /v1/challenge`, `POST /v1/register` | +| **Lifecycle** | Active token can be renewed (old revoked, new issued), delegated (narrower scope only), released (voluntary teardown), or left to expire on TTL. | `POST /v1/token/renew`, `POST /v1/delegate`, `POST /v1/token/release` | +| **Revocation** | Operator or admin revokes at four levels: single token (JTI), all tokens for an agent, all tokens for a task, or an entire delegation chain. | `POST /v1/revoke` | + +## Token states + +- **Active** — issued, within TTL, not revoked +- **Renewed** — new token issued, old token immediately revoked +- **Revoked** — explicitly killed via `/v1/revoke` (4 levels) +- **Released** — agent voluntarily surrendered the token via `/v1/token/release` +- **Expired** — TTL elapsed, no longer valid + +--- + +*Back to [Architecture](architecture.md) · [API Reference](api.md)*