docs(04): capture phase context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-11 19:37:51 +01:00
parent 2da2b76771
commit b594ac6f4a

View File

@@ -0,0 +1,98 @@
# Phase 4: Security - Context
**Gathered:** 2026-03-11
**Status:** Ready for planning
<domain>
## 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).
</domain>
<decisions>
## 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 <token>` 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=<jwt>` (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)
</decisions>
<specifics>
## 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
</specifics>
<code_context>
## 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
</code_context>
<deferred>
## 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
</deferred>
---
*Phase: 04-security*
*Context gathered: 2026-03-11*