docs(04): capture phase context
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
98
.planning/phases/04-security/04-CONTEXT.md
Normal file
98
.planning/phases/04-security/04-CONTEXT.md
Normal 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*
|
||||||
Reference in New Issue
Block a user