source: advance the checked projection
Source-Sha: 194a59adfd6c901635da7a9c18253bb2210e2426 Policy-Sha: b9b0be0ee74e55f561a803b8aef6be3c2134f5a83b46816a069a372f2eb04f4d Tree-Digest: 4697f2e281c1c6ecafff17cf6eeb391a0a1ac0fa6e5fc429f5b473f4579c252c
This commit is contained in:
parent
0401c76c79
commit
ffdccba10f
42 changed files with 2516 additions and 554 deletions
|
|
@ -43,7 +43,7 @@ web/src/
|
|||
│ ├── polling.ts # POLL.* constants — all intervals centralized
|
||||
│ ├── store.ts, queryParser.ts, vulnerabilities.ts
|
||||
│ └── client-logger.ts # Client errors ship to the server log (ETHOS #1)
|
||||
├── desktop/ # Tauri tray-app variant (vite.desktop.config.ts)
|
||||
├── desktop/ # Retained legacy Tauri web shell; not RedFlag Desktop
|
||||
└── types/ # Shared TS types mirroring server models
|
||||
```
|
||||
|
||||
|
|
@ -65,6 +65,10 @@ web/src/
|
|||
- Mobile layout usable, not optimized
|
||||
- Several UI coverage gaps tracked as `UI-*` tasks (not architecture — task tier)
|
||||
|
||||
The native RedFlag Desktop is the Qt/QML component described in
|
||||
[components/05-desktop](05-desktop.md). `web/src/desktop` is retained legacy source, not a
|
||||
second supported Desktop implementation or an architectural authority.
|
||||
|
||||
---
|
||||
|
||||
*Last reviewed: 2026-06-14*
|
||||
*Last reviewed: 2026-09-14*
|
||||
|
|
|
|||
|
|
@ -20,6 +20,28 @@ On Linux the agent invokes it through `sudo systemd-run --wait --property=Protec
|
|||
|
||||
### Windows Invocation (SEC-030, decided 2026-07-01)
|
||||
|
||||
**Current source boundary:** the native Windows payload now builds the Rust Helper. It
|
||||
answers its version and supports verification-only binary and `MutationEnvelope` checks.
|
||||
Windows-only source now opens each trust-path component without following reparse points,
|
||||
checks SYSTEM/Administrators ownership and denies write grants to other principals, rejects
|
||||
hard-linked trust files, and creates write-through, one-shot authorization claims. The fixed
|
||||
task dispatcher reads an envelope from its protected exchange, pins the installed authority
|
||||
placement, and uses the shared verifier. The wrapper carrying that envelope is decoded
|
||||
before the envelope itself, so a request the Helper could read but whose envelope it could
|
||||
not is refused under its own validated request id instead of leaving the caller an unknown
|
||||
outcome; a wrapper too malformed to establish an identity still writes no result, because
|
||||
the Helper does not invent one. A shared Go/Rust fixture pins that wrapper on both sides.
|
||||
The Agent reaches this path read-only through `redflag-agent -verify-envelope`, which mints
|
||||
nothing, admits no backend, and passes no command or path to the privileged process.
|
||||
Windows mint and backend execution still return typed refusals.
|
||||
|
||||
Native acceptance of the *installed* rail — ACL enforcement, service identity, task
|
||||
definition, and exchange roots — remains open: the transport is covered by tests, not by a
|
||||
witness on a provisioned host. Replay refusal is likewise open and deliberately unexercised,
|
||||
because verification must not consume an authorization; the claim belongs at an execution
|
||||
boundary that no admitted backend has yet. Low-privilege service migration and WUA / Winget
|
||||
executors remain required before mutation authority is enabled.
|
||||
|
||||
Windows has no `systemd-run` equivalent for spinning up an ad-hoc transient privileged unit, so the helper is invoked through a **Scheduled Task, configured to run once as SYSTEM**. The agent's own service account has no standing right to mutate anything — it only holds a delegated "AllowedToRun" ACE on this one task definition (`schtasks /run /tn RedFlagHelper`), the direct Windows analogue of the Linux sudoers line that grants exactly one `systemd-run` invocation and nothing else.
|
||||
|
||||
Two elevation-model alternatives were considered and rejected:
|
||||
|
|
@ -28,6 +50,54 @@ Two elevation-model alternatives were considered and rejected:
|
|||
|
||||
The task definition itself is provisioned **at agent-install time** by the (already-elevated) install script, the same moment Linux drops its sudoers entry — not self-provisioned by the agent on first gated operation, which would just relocate the "who grants the first elevation" problem rather than solve it.
|
||||
|
||||
`installer/windows/provision-helper.ps1` now prepares that installer-owned boundary. It
|
||||
creates one triggerless `\RedFlag\Helper` task with a fixed Helper path and `run-request`
|
||||
argument, grants the Agent service SID read/run rather than task mutation, and places the
|
||||
Agent-writable request child beneath a non-Agent-writable Helper root beside SYSTEM-owned
|
||||
trust, replay, and result directories. The staged
|
||||
payload validates this description but does not run the provisioning script.
|
||||
|
||||
`run-request` accepts no command-line arguments. Its machine exchange is fixed at
|
||||
`C:\ProgramData\RedFlag\helper`; the installer refuses alternate data roots for this
|
||||
transport. It opens each component relative to a retained directory handle, rejects
|
||||
reparse points and hard-linked files, bounds input size, and denies concurrent write/delete
|
||||
sharing while reading. The RedFlag and Helper roots, authority file, and result directory
|
||||
must pass owner/DACL checks. A handle lock serializes dispatcher instances.
|
||||
|
||||
The Agent writes `requests\pending.json`: `version`, a fresh UUID `request_id`, an action
|
||||
(`verify-envelope` or `execute-envelope`), and the unchanged `envelope`. Unknown envelope
|
||||
fields and duplicate struct fields are refused. Installer-owned `authority.json` contains
|
||||
`version`, `target_id`, `authority_kind` (`standalone` or `fleet-server`), `authority_id`, and
|
||||
`public_keys` (Ed25519 hex). This is local trust configuration. Provisioning accepts it
|
||||
through `-AuthorityFile`, but refuses to replace an existing different authority; enrollment
|
||||
and rotation need their own explicit transaction.
|
||||
|
||||
The result is a create-new `results\<request_id>.json` containing `version`, `request_id`,
|
||||
`envelope_verified`, and the common joined `receipt`. Read-only verification reports
|
||||
`decision=verified`, `executed=false`, and zero verified backend actions. Backend execution
|
||||
currently reports `backend_not_migrated`; neither path consumes replay authorization.
|
||||
Protected results are flushed and closed before the Agent can read them. Results stay as
|
||||
local evidence; retention and timed-out request reconciliation remain follow-up work.
|
||||
|
||||
The Agent's Windows envelope executor triggers only `\RedFlag\Helper`, serializes its one
|
||||
pending slot across processes, validates the full receipt join, and leaves an unresolved
|
||||
slot intact after task-start failure, timeout, cancellation, or an invalid response. Task
|
||||
start never counts as execution success. A later call first reads any pending request and
|
||||
its protected result. A valid joined result retires the slot and is returned when the caller
|
||||
retried the same action, authorization, and manifest; a different call may proceed while the
|
||||
old result stays as evidence. Missing, malformed, or mismatched results keep the slot blocked
|
||||
with its request ID for reconciliation. Windows standalone mint explicitly refuses until
|
||||
fresh StepUp exists. New Agent service installs select the virtual
|
||||
`NT SERVICE\RedFlagAgent` account and enable its service SID. Helper provisioning grants
|
||||
that SID modify access to Agent state/logs, modify access to the untrusted request directory,
|
||||
read access to results, and no access to authority/replay state. Existing SYSTEM services
|
||||
use the explicit `-MigrateAgentService` transaction: enable the service SID, prepare ACL/task
|
||||
ownership while LocalSystem is still available, stop the service, change its account, verify
|
||||
SCM state, and restore its prior running state. Only an observed LocalSystem service is
|
||||
migrated; another operator-owned identity is refused. If the new identity cannot start, the
|
||||
script restores LocalSystem and its prior running state while retaining the prepared narrow
|
||||
ACLs for a later retry. Native transport acceptance remains open.
|
||||
|
||||
The ACL lockdown described here is the v1 cut, not the final word — Casey's call ("that'll do for now"). Revisit if a real gap in the ACE-delegation model surfaces (see `docs/tasks/SEC-030-windows-privileged-mutation-helper.md` Open Questions for what's still unresolved: WUA's COM-driven install path, rollback ownership parity with Linux's `.bak` handling).
|
||||
|
||||
---
|
||||
|
|
|
|||
Loading…
Reference in a new issue