Make an admin's refusal stick, and let a revoke actually deny
Three holes in the enrollment path, all of the same shape: a decision the admin made did not survive contact with a PC that simply asked again. REJECTION WAS UNDONE BY A NEW NONCE. A rejected request re-armed itself as a fresh cycle when the PC came back with a different nonce, and with the shared key and auto-enroll on it was then issued the credential the admin had just refused. Rejection now binds to the endpoint identity - hostname plus BIOS serial - not to the nonce, so the PC stays refused however often it reinstalls. An admin clears it deliberately, through the approve path that already exists; a genuinely different PC is untouched. THE PENDING QUEUE COULD BE FILLED UNTIL IT REFUSED EVERY NEW PC. /enroll takes no auth by design - a bay that has never spoken to the server has nothing to authenticate with - so anything that can reach the server could sit at the cap and lock out real enrollments fleet-wide. Rows nobody has touched for seven days now age out before the cap refuses anyone, and the count of what went is audited. Per-identity dedup and the cap itself were already there and are left alone. REVOKE DID NOT STOP A LIVE AGENT. It fell back to the shared key and the server admitted it again, so revoking a compromised PC changed nothing while that key still worked. plugin.endpoints.revokeddeniessharedkey makes a revoked host refused on the shared key too. That switch DEFAULTS OFF, and that is the important part. Turning it on would silence any bay revoked for a key rotation, and would break the documented revoke-then-rollback path to an older agent - on an air-gapped site, mid migration, that is a fleet outage. A never-enrolled bay is never affected either way: with no credential row at all the shared key still works, which is the whole un-migrated fleet. The checkbox sits next to the other two enrollment switches and says what turning it on costs, because a setting that can stop the floor should not be reachable only through the API.
This commit is contained in:
@@ -4,16 +4,25 @@
|
||||
One row per asset. Holds only the sha256 of the secret the
|
||||
agent was issued, plus a short display prefix. Revoking sets
|
||||
revokedat; re-issuing after a revoke UPDATES the same row, so
|
||||
an asset never carries two credentials. reenrollblocked keeps
|
||||
an asset never carries two credentials. The row therefore also
|
||||
says that this PC has enrolled at least once, which is how
|
||||
agentauth tells a revoked PC from one that never enrolled:
|
||||
plugin.endpoints.revokeddeniessharedkey refuses the shared key
|
||||
to the first and never to the second. reenrollblocked keeps
|
||||
a revoked PC from enrolling again (rolling it back to an agent
|
||||
that only knows the shared key, or a compromised PC) until an
|
||||
admin allows it.
|
||||
|
||||
EndpointEnrollRequest
|
||||
One row per (hostname, serial number) that asked to enroll. The
|
||||
agent's enrollment nonce is recorded on first sight and is what
|
||||
an admin approval is bound to, so a second machine claiming the
|
||||
same hostname and serial cannot collect the approved credential.
|
||||
One row per (hostname, serial number) that asked to enroll -
|
||||
the endpoint's identity, and the reason every contact from one
|
||||
PC lands on one row. The agent's enrollment nonce is recorded
|
||||
on first sight and is what an admin approval is bound to, so a
|
||||
second machine claiming the same hostname and serial cannot
|
||||
collect the approved credential. A REJECTED row binds to the
|
||||
identity instead: any nonce from that hostname and serial stays
|
||||
rejected, so a reinstall cannot argue its way back into the
|
||||
queue. Only an admin approving the request clears it.
|
||||
|
||||
EndpointMigrationWave
|
||||
An admin action that pushed the agent upgrade to a set of PCs.
|
||||
|
||||
Reference in New Issue
Block a user