Files
EvoFirewall/docs/agent-credentials.md
T
Denozordec 9fa6269174
quality / changes (push) Successful in 7s
quality / commitlint (push) Skipped
quality / openapi (push) Successful in 30s
quality / web (push) Successful in 1m3s
quality / api (push) Successful in 1m15s
quality / linux-agent-smoke (push) Failing after 27s
quality / docker-check (push) Failing after 2m28s
CD / quality (push) Failing after 5m52s
CD / publish (push) Skipped
feat: harden firewall policies telemetry and operations
Implement reliable agent apply, telemetry v2, analytics retention, guarded rollouts, enrollment, labels and webhooks. Improve ReUI frontend data safety and bounded list loading, and add Docker smoke, recovery and resource checks. Document local verification and pending native acceptance.
2026-10-26 13:10:58 +07:00

34 lines
6.1 KiB
Markdown

# Agent enrollment and token lifecycle
Install links are bearer invitations lasting 24 hours. The controller renders a credential scoped to that link with HMAC-SHA256; the global enrollment seed stays on the controller as the HMAC key. Changing that key invalidates outstanding invitations. Install IDs and slugs use 32 random characters. Both download paths use `Cache-Control: no-store`.
## Enrollment
`POST /v1/agent/enroll` requires `X-Evofw-Enrollment-Credential` and `install_link_id`, together with the agent-generated token and identity fields. Global `X-Evofw-Seed` enrollment is disabled. Already enrolled agents continue authenticating with their existing tokens.
Downloading does not consume an invitation. Successful enrollment consumes it in the same SQLite transaction that installs the agent token and changes the invited agent to pending. Approval remains a separate operator action. Concurrent submissions cannot replace the winner. An identical token retry returns the original agent, including after approval; a different token is rejected. A revoked/expired invitation or revoked agent is rejected before retry handling, so a previously downloaded script cannot bypass revocation or expiry. Existing pre-upgrade invitations receive a 24-hour expiry during migration; their old downloaded seed-based scripts must be downloaded again.
The Linux installer saves the generated enrollment token in a private `enrollment-pending.json` before its first request. A failed request keeps it for retry. The active config is committed with fsync, rename and directory fsync before pending cleanup. The RouterOS installer similarly saves its token before enrollment and uses the same token after restart. Reusing the invitation on a different machine after consumption is refused.
## Rotation API
An operator requests rotation with `POST /api/v1/agents/:id/token-rotation` (`fw:agents:write`). The server requires an approved agent running a known supporting client version (`linux/10`, `rsc/10`, or the matching `install.sh/2`). Older clients receive an unsupported-capability response and retain their current token. Repeating an outstanding request returns the same request ID. Requests expire after 24 hours.
Operators inspect safe status with `GET /api/v1/agents/:id/token-rotation`, which returns support, client version, agent status, pending request and last completed request receipt. The agent polls `GET /v1/agent/credentials`. The response contains `client_id`, an optional pending `rotation` with request ID and expiry, and an optional `completed_rotation` receipt containing only its request ID. It never contains tokens or token hashes.
The client generates its next token and saves `{request_id, old_token, next_token}` privately before `POST /v1/agent/token-rotation` with `{request_id, next_token}`, authenticated by the old token. SQLite atomically changes the active hash and records the exact exchange. The old token immediately stops working on all normal agent endpoints. Only the exchange endpoint recognizes the old hash for a 24-hour exact replay, and only while the recorded next hash remains the current credential and the agent remains approved. Wrong request/token pairs, revoked agents, and expired replays are refused.
After a matching ACK, Linux commits the active configuration before removing pending state; RouterOS commits its credential file before changing the active global. A restart resumes pending recovery before policy, telemetry or self-update. An ACK loss retries the same exchange and token. After the old-token replay window expires, the saved next token can authenticate a normal credential-status read: matching client ID and completed request receipt prove it is already active. A separate last-completed receipt survives a newer operator request and contains no old hash. Failed or mismatched responses preserve pending state and do not overwrite the active credential. When an uncommitted request expires or is superseded, a successful old-token status read proves that the old credential is still active. Only if the old request is no longer active does the client remove the abandoned pending attempt and continue policy/telemetry using the old token; the next sync handles a newer request. A request still active on the controller or an unavailable status read preserves pending state.
Rotation does not alter enforcement, policy hashes, telemetry queues or counter epochs. Credentials are never placed in logs or operator list responses. Revoking an agent blocks ordinary authentication and all exchange/recovery paths. Link revocation prevents new enrollment; agent revocation independently disables an enrolled credential.
## Client storage and limits
Linux uses mode-0600 pending files under its private config/state directories, an existing sync lock, and fsync/rename commits. Pending credentials must be treated as secrets and retained until recovery completes. RouterOS uses `flash/evofw-credentials.json` when flash storage exists, otherwise `evofw-credentials.json`. This authoritative file overrides the legacy token baked into the sync script on every run, including after reboot. Existing baked credentials migrate without resetting enforcement.
RouterOS file writes do not provide Linux crash-atomic durability. Power loss can leave corrupt or empty files; invalid state stops synchronization and requires recovery while existing firewall rules remain. RouterOS scripting syntax, persistence, and credential exchange have not been executed on a device or CHR. Linux kernel commands were not executed in this Windows environment.
## Validation
The credential suite executes the actual embedded Linux Python worker with a mocked HTTP transport and temporary files, covering lost ACK, process restart, expired old-token replay, and mismatched ACK. Directory fsync calls are adapted only in the Windows test harness. API tests cover scoped invitations, failed attempts without consumption, competing enrollment, exact retry, expiry/revocation after download, disabled global seed, client version gating, immediate normal-path old-token rejection, bounded exchange replay, and retained recovery receipts. RouterOS assertions inspect generated script contracts and ordering; they are not native execution.