233 lines
13 KiB
Markdown
233 lines
13 KiB
Markdown
# MinerOps Windows Agent
|
|
|
|
The Windows Agent runs at a mining site and performs local discovery, polling,
|
|
API3 enrichment, pool polling, and approved queued miner-control operations.
|
|
MinerOps does not send API3 credentials through the hub command queue; those
|
|
credentials remain in the Agent's local `agent-config.json`.
|
|
|
|
## Recovered Baseline
|
|
|
|
The seven runtime and support scripts in this directory were recovered from the
|
|
live `C:\MinerOpsAgent` installation. `BASELINE_SHA256SUMS` records their exact
|
|
pre-change hashes. Historical backups, live configuration, state, logs, and
|
|
probe output are intentionally excluded.
|
|
|
|
## Local Files
|
|
|
|
Create `agent-config.json` from `config.example.json` on the Agent host. Never
|
|
commit that file. `site_id` is the durable MinerOps site UUID. `agent_zone_id` is the optional
|
|
durable network-reachability Zone UUID; older configurations may omit it only
|
|
when the Hub can preserve an established assignment or resolve exactly one
|
|
enabled Zone at the Site. `site_name` is retained only for transitional display
|
|
compatibility.
|
|
|
|
The Agent writes runtime state to `agent-state.json` and logs under `logs/`.
|
|
Installation and upgrades preserve all three paths.
|
|
|
|
## Security
|
|
|
|
API3 account and password values are local secrets. Missing credentials make
|
|
miner control unavailable. Passwords, API tokens, salts, and the Agent secret
|
|
must not be written to normal logs or returned to MinerOps command history.
|
|
|
|
New Agent identities use per-Agent credentials created through secure
|
|
one-time enrollment. The permanent Agent secret is returned only to the
|
|
enrolling Agent and is stored locally in `agent-config.json`; MinerOps stores
|
|
only its hash. The legacy deployment shared secret remains only for explicitly
|
|
retained compatibility behavior and must not authenticate a newly enrolled
|
|
per-Agent identity.
|
|
|
|
## Legacy Compatibility
|
|
|
|
The older direct Hub API3, `/agent-control`, password-change, bulk-control, and
|
|
scheduling paths remain available for compatibility and are deprecated for the
|
|
Internal Alpha. The new Miner Detail controls use only the typed control API and
|
|
Agent queue; the modular control backend does not connect directly to miners.
|
|
|
|
## Deployment
|
|
|
|
### New Agent enrollment
|
|
|
|
For a new Agent, use Agent Management in MinerOps:
|
|
|
|
1. Choose the Site and an enabled, unassigned Agent Zone.
|
|
2. Enter a descriptive Agent name.
|
|
3. Create a Windows enrollment.
|
|
4. Download MinerOpsAgent-Windows.zip before the enrollment expires.
|
|
5. Copy the ZIP to the intended Windows machine and extract it.
|
|
6. Open Windows PowerShell as Administrator in the extracted
|
|
MinerOpsAgent-Windows directory.
|
|
7. Run:
|
|
|
|
.\Enroll-MinerOpsAgent.ps1
|
|
|
|
8. Enter the local WhatsMiner API3 account/password when prompted, or leave
|
|
the account blank if API3 functionality is not being configured yet.
|
|
9. The bootstrapper exchanges the short-lived token with POST /api/agent/enroll,
|
|
saves the resulting permanent Agent identity locally, and hands off to the
|
|
safe runtime installer.
|
|
10. Verify the Agent appears in Agent Management and checks in successfully.
|
|
11. Delete the downloaded ZIP and extracted setup directory.
|
|
|
|
Do not place enrollment.json, enrollment tokens, Agent secrets, or API3
|
|
credentials in screenshots, chat, tickets, logs, or source control.
|
|
|
|
### Existing Agent upgrade
|
|
|
|
An existing legacy Agent must receive a per-Agent credential before the global
|
|
shared-secret compatibility path can be retired for its identity. In Agent
|
|
Management, use **Upgrade credential** on that Agent. Download the resulting
|
|
Windows package, transfer it only to that Agent computer, and run:
|
|
|
|
.\Upgrade-MinerOpsAgentCredential.ps1
|
|
|
|
The authorization is bound server-side to the existing Agent ID and its
|
|
current Site and Agent Zone. The script validates the local Agent ID, upgrades
|
|
the canonical runtime, stops the main Agent task, generates the permanent
|
|
secret locally, and recoverably replaces only the credential and durable routing
|
|
fields in `agent-config.json` using protected same-directory pending and prior
|
|
names. Existing API3 credentials, polling settings,
|
|
network ranges, state, logs, and backups are preserved. Before any secret is
|
|
written, the script creates and verifies a protected recovery file containing
|
|
the original Scheduled Task state, exact transition token, and exact locally
|
|
generated credential. The Hub accepts an ambiguous retry only for that same
|
|
token and credential.
|
|
|
|
The Agent directory is a filesystem security boundary. The transition rejects
|
|
junctions/reparse points, verifies trusted ancestors, denies standard users
|
|
create/delete/rename rights, and revalidates the boundary before each rename.
|
|
If an existing Agent directory is discovered insecure, the script first writes
|
|
`C:\MinerOpsAgent.minerops-filesystem-trust.blocked-<random>.state` under the trusted
|
|
parent, then hardens the directory only to contain the incident. The blocker is
|
|
outside the contaminated namespace because changing a DACL does not revoke
|
|
file or directory handles opened before repair. The same process never redeems
|
|
a token, creates or activates a permanent credential, runs the installer, or
|
|
removes that blocker. Ordinary second, third, and later invocations remain
|
|
blocked even when every current ACL looks correct.
|
|
|
|
Recovery, pending, replacement remnants, and late-arriving artifacts are
|
|
non-authoritative while the external blocker exists. Known transition state is
|
|
quarantined without parsing. A correct filename, syntax, or ACL cannot promote
|
|
it on a later run. Invalidate any possibly exposed authorization and retain or
|
|
remove evidence only under the approved incident procedure.
|
|
|
|
### Filesystem trust-epoch recovery
|
|
|
|
Use this procedure only after confirming the blocker was created by the
|
|
containment event and preserving required evidence:
|
|
|
|
1. Do not delete or edit the external blocker. Do not run an ordinary retry.
|
|
2. Use **Restart** to perform a full Windows kernel boot. Shutdown with Fast
|
|
Startup is not sufficient: Microsoft documents Fast Startup as hibernating
|
|
and restoring kernel session 0. The script identifies the kernel epoch by
|
|
the Event Log record anchor of the newest
|
|
`Microsoft-Windows-Kernel-Boot` event 27 whose `BootType` is exactly `0`.
|
|
Provider, event ID, record ID, and supported event version come from typed
|
|
EventRecord properties; namespace-aware XML selection reads only the
|
|
`BootType` payload. The new full-boot record ID must be strictly greater
|
|
than the stored record ID. Equality, an older/restored record, log clearing
|
|
or numbering reset, missing history, duplication, malformed XML, and an
|
|
unsupported provider schema all fail closed and require safe operator
|
|
intervention. There is no timestamp fallback. The anchor is unchanged by
|
|
clock or timezone changes, sleep, hibernation, and Fast Startup. See
|
|
Microsoft's [system power-state documentation](https://learn.microsoft.com/windows/win32/power/system-power-states)
|
|
and [Fast Startup support guidance](https://learn.microsoft.com/troubleshoot/windows-client/setup-upgrade-and-drivers/fast-startup-causes-system-hibernation-shutdown-fail).
|
|
3. For a credential transition, use a fresh transition package if any recovery,
|
|
pending, remnant, quarantine, or internal blocker existed. Remove those
|
|
artifacts only under the approved incident procedure after invalidating the
|
|
old authorization.
|
|
4. From the reviewed package, run:
|
|
|
|
.\Upgrade-MinerOpsAgentCredential.ps1 `
|
|
-ApproveFilesystemTrustResetAfterReboot
|
|
|
|
The script verifies that Windows boot identity changed, rescans the protected
|
|
namespace, positively verifies and stops the expected Scheduled Task, and asks the
|
|
installer to replace managed runtime without backing up or restoring any
|
|
pre-reset runtime. The installer leaves both the Agent task and external
|
|
blocker untouched after publication; it has no blocker-deletion path. Before
|
|
its first fallible stop/install step, the parent durably records the strictly
|
|
validated original task intent as `reset-authorized`; after installer
|
|
success it advances the blocker to `runtime-published`. It then verifies the
|
|
config against the package/server identity, commits the credential, and
|
|
restores the recorded task intent. Only the parent removes the blocker,
|
|
after active config and final task state have both been positively verified
|
|
and non-recovery transition cleanup has succeeded. Protected recovery stays
|
|
until after blocker deletion so an interrupted final cleanup remains safe.
|
|
5. For a genuinely new enrollment, preserve evidence and use the approved
|
|
protected-recreation incident procedure to remove the contaminated namespace
|
|
and its external blocker, then let `Enroll-MinerOpsAgent.ps1` stage a new
|
|
protected directory. Enrollment has no in-script blocker-deletion path; its
|
|
explicit compatibility switch cannot override a retained blocker.
|
|
|
|
The explicit switch without a strictly newer canonical full-kernel-boot anchor
|
|
fails.
|
|
Any suspicious transition artifact, failed runtime publication, failed
|
|
credential convergence, invalid final task, or interrupted cleanup retains the
|
|
blocker. Runtime publication alone never authorizes deletion. Protected
|
|
directory recreation is the alternative when the retained namespace cannot be
|
|
verified.
|
|
|
|
If the script is interrupted after the Hub commits, rerun the same extracted
|
|
package without deleting or editing `agent-credential-transition.recovery.json`
|
|
or `agent-config.json.pending`. A protected, matching pending config is resumed;
|
|
an insecure, malformed, or mismatched artifact fails closed. The original task
|
|
intent is durable: an Agent which was running before the first attempt ends
|
|
running, while an intentionally stopped Agent remains stopped. Success is not
|
|
reported and transition artifacts are not removed until both the active config
|
|
and expected final task state are verified. The verifier requires exactly one
|
|
enabled root `MinerOpsAgent` task, the SYSTEM service-account/highest principal,
|
|
the installed Windows PowerShell action and service-script arguments, and an
|
|
exact final state of `Running` for running intent or `Ready` for stopped intent.
|
|
Missing, query failure, access denied, malformed, multiple, disabled, queued,
|
|
unknown, wrong-action, and wrong-principal results all fail closed and retain
|
|
recovery.
|
|
|
|
After a successful transition, the existing Agent ID, Site, and Zone are
|
|
unchanged. Explicit Agent ID plus the new per-Agent secret is required, and the
|
|
legacy shared secret is permanently disabled for that identity.
|
|
|
|
For later code-only upgrades of an Agent that already has a per-Agent
|
|
credential, copy the new canonical Agent files to a temporary directory and run
|
|
install.ps1 from an elevated Windows PowerShell session.
|
|
|
|
The installer copies only managed runtime code to C:\MinerOpsAgent and
|
|
preserves agent-config.json, agent-state.json, logs\, backups, probe output,
|
|
and other runtime data. Existing Scheduled Task definitions are authoritative
|
|
and are not rewritten. Missing tasks are created for a fresh or incomplete
|
|
installation without hard-coded user names.
|
|
|
|
The per-user `MinerOpsAgentTray` task is optional UI and is not credential or
|
|
core Agent authority. During an explicit filesystem trust reset, runtime
|
|
publication may run noninteractively as `NT AUTHORITY\SYSTEM`, where no safe
|
|
interactive user principal can be inferred. The installer still publishes
|
|
`MinerOpsAgentTray.ps1`, but deliberately defers creation of a missing tray task
|
|
until a later interactive maintenance install. It never creates the tray task
|
|
as SYSTEM or invents a username. An existing tray task remains authoritative
|
|
and is preserved unchanged rather than silently repaired under SYSTEM; inspect
|
|
and remediate a suspected malformed definition separately. The core
|
|
`MinerOpsAgent` task remains mandatory and strictly verified by credential
|
|
recovery. `MinerOpsApi3Enrichment` and `MinerOpsPoolPoller` are non-interactive
|
|
background tasks with explicit SYSTEM principals, so missing instances continue
|
|
to be created during trust-reset publication.
|
|
|
|
If MinerOpsAgent was running before an upgrade, the installer stops only that
|
|
Scheduled Task, waits for it to stop, replaces the managed files, and starts it
|
|
again. A previously stopped Agent remains stopped. Before replacing runtime
|
|
files, the installer copies them to a timestamped backup under
|
|
C:\MinerOpsAgent\backups.
|
|
|
|
Runtime sources, installed destinations, active config, and rollback copies are
|
|
rejected when they are reparse points or have more than one hard link. A normal
|
|
trusted upgrade creates a fresh random backup directory and never adopts an
|
|
existing backup destination. During an explicit post-reboot trust reset, old
|
|
runtime is never copied into backup or restored; fresh package content replaces
|
|
it while the external blocker remains, and the Agent task stays stopped for
|
|
credential verification.
|
|
|
|
A failed deployment restores managed files, removes tasks created by that
|
|
failed attempt, and restores the main Agent's prior running state.
|
|
|
|
uninstall.ps1 unregisters the four MinerOps Scheduled Tasks and removes runtime
|
|
code while preserving local configuration, state, logs, and backups.
|