diff --git a/.planning/phases/04-security/04-CONTEXT.md b/.planning/phases/04-security/04-CONTEXT.md new file mode 100644 index 00000000..913aa269 --- /dev/null +++ b/.planning/phases/04-security/04-CONTEXT.md @@ -0,0 +1,98 @@ +# Phase 4: Security - Context + +**Gathered:** 2026-03-11 +**Status:** Ready for planning + + +## Phase Boundary + +All agent-server communication is authenticated and integrity-protected. JWT for API access control, Ed25519 signatures for pushed configuration/commands, bootstrap token for initial agent registration. This phase secures the communication channel between agents and server — not user/UI auth (deferred to v2 with web UI). + + + + +## Implementation Decisions + +### Bootstrap token flow +- Single shared token from `CAMELEER_AUTH_TOKEN` env var — no config file fallback +- Agent passes bootstrap token via `Authorization: Bearer ` header on `POST /register` +- Server returns `401 Unauthorized` when token is missing or invalid — no detail about what's wrong +- Server fails fast on startup if `CAMELEER_AUTH_TOKEN` is not set — prevents running insecure +- Hot rotation via dual-token overlap: support `CAMELEER_AUTH_TOKEN_PREVIOUS` env var, server accepts both during rotation window. Remove old var when all agents updated + +### JWT lifecycle +- Access JWT expires after 1 hour +- Separate refresh token with 7-day expiry, issued alongside access JWT at registration +- Agent calls `POST /api/v1/agents/{id}/refresh` with refresh token to get new access JWT +- JWT claims: `sub` = agentId, custom claim for group +- Registration response includes both access JWT and refresh token (replaces current `serverPublicKey: null` placeholder with actual public key) + +### Ed25519 signing +- Ephemeral keypair generated fresh each server startup — no persistence needed +- Agents receive public key during registration; must re-register after server restart to get new key +- Signature included as a `signature` field in the SSE event data JSON — agent verifies payload minus signature field +- All command types signed (config-update, deep-trace, replay) — uniform security model + +### Endpoint protection +- Public (no JWT): `GET /health`, `POST /register` (uses bootstrap token), OpenAPI/Swagger UI docs +- Protected (JWT required): all other endpoints including ingestion (`/data/**`), search, agent management, commands +- SSE connections authenticated via JWT as query parameter: `/agents/{id}/events?token=` (EventSource API doesn't support custom headers) +- Spring Security filter chain (`spring-boot-starter-security`) with custom `JwtAuthenticationFilter` + +### Claude's Discretion +- JWT signing algorithm (HMAC with server secret vs Ed25519 for JWT too) +- Nimbus JOSE+JWT vs jjwt vs other JWT library +- Ed25519 implementation library (Bouncy Castle vs JDK built-in) +- Spring Security configuration details (SecurityFilterChain bean, permit patterns) +- Refresh token storage mechanism (in-memory map, agent registry, or stateless) + + + + +## Specific Ideas + +- "This phase and version really is about securing the communication channel between agent and server" — scope is agent-server auth, not user-facing auth +- Bootstrap token rotation without downtime was explicitly called out as important +- Agents already re-register on restart (Phase 3 design), so ephemeral Ed25519 keys align naturally + + + + +## Existing Code Insights + +### Reusable Assets +- `ProtocolVersionInterceptor` + `WebConfig`: Path-based request filtering pattern — Spring Security filter chain replaces this for auth +- `AgentRegistrationController.register()`: Already returns `serverPublicKey: null` — fill with real Ed25519 public key +- `SseConnectionManager.sendEvent()`: SSE delivery point — signing hooks into data before this call +- `AgentRegistryConfig`: Configuration properties pattern — extend for security settings (token expiry, etc.) +- `AgentRegistryService`: Agent lookup by ID — used for JWT validation (verify agent exists) + +### Established Patterns +- Core module: interfaces + domain logic; App module: Spring Boot + implementations +- `application.yml` for all configurable values with sensible defaults +- `AgentEventListener` interface decouples core from app module — signing logic can live in app module + +### Integration Points +- `POST /register` needs bootstrap token validation before reaching current registration logic +- `SseConnectionManager.connect()` needs JWT validation from query parameter +- `SseConnectionManager.onCommandReady()` needs to sign payload before delivery +- All existing controllers need JWT auth enforced — Spring Security filter handles this transparently +- `WebConfig` excluded paths need to align with Spring Security permit patterns + + + + +## Deferred Ideas + +- User/UI authentication — belongs with web UI in v2 +- Role-based access control (admin vs agent vs viewer) — future phase +- Token revocation list — evaluate after v1 usage patterns +- Mutual TLS as additional transport security — infrastructure concern, not application layer +- Key rotation API endpoint — adds attack surface, stick with restart-based rotation for v1 + + + +--- + +*Phase: 04-security* +*Context gathered: 2026-03-11*