Make rollback, first upgrades and pin changes work as tested on Windows
Found in an end-to-end test on a Windows 11 VM against a self-signed server.
- Rollback: a 1.20 agent re-enrolls within a second of an un-enroll, so an
older agent pushed afterwards arrived on an enrolled PC and was refused.
Revoke now takes {"blockreenroll": true, "reason": ...}; a blocked PC is
never issued a credential and keeps working on the shared key until
POST .../assets/<assetid>/allow-reenroll. The Enrollment page offers the
block when un-enrolling and shows blocked PCs with an allow button.
- First upgrade of old agents: agents before 1.20 check the server
certificate when downloading the upgrade, so a store wave failed on PCs that
do not trust a self-signed server while the Migration tab said ready. A
failed download now marks the PC blocked with "server certificate not
trusted by this PC". New Install-ShopDBServerCertificate.ps1 (GE-Enforce,
SYSTEM) adds a non-CA server certificate to the trusted roots after checking
its thumbprint; the server certificate page offers a .cer download and the
SHA-1 thumbprint.
- The generated installer writes ServerPins (with an optional next pin for a
planned rotation), can leave the shared key out so the PC waits for
approval, never touches an existing credential, and skips the trusted-root
import for a CA certificate.
- The agent re-reads server pins about every 60 seconds and recycles pooled
connections within 2 minutes, so a pin change needs no restart.
- An alert can only be acknowledged by a PC it targets.
- A wave no longer counts a PC as failed after a later wave upgraded it.
- The scripts report a pin mismatch only when the pin really is missing, and
otherwise log the real error.
- Runbook: trust step before the first wave, rollback order, pin re-read,
verifying the pin against the live URL; agent contract updated.
This commit is contained in:
@@ -12,8 +12,8 @@ builds of 0021/0022, and on a re-run:
|
||||
table where an earlier build of 0021/0022 created them.
|
||||
2. Rename endpointapplications.app_fingerprint to appfingerprint where an
|
||||
earlier build of 0020 used the underscore spelling.
|
||||
3. Create endpointcredentials, endpointenrollrequests and
|
||||
endpointmigrationwaves.
|
||||
3. Create endpointcredentials (with the reenrollblocked flag and its reason),
|
||||
endpointenrollrequests and endpointmigrationwaves.
|
||||
|
||||
MySQL 5.6 safe: no JSON columns, and the enroll request lookup index uses
|
||||
prefix lengths so the key stays under 767 bytes on utf8mb4.
|
||||
@@ -109,12 +109,26 @@ def upgrade():
|
||||
sa.Column('lastusedat', sa.DateTime(), nullable=True),
|
||||
sa.Column('revokedat', sa.DateTime(), nullable=True),
|
||||
sa.Column('revokedby', sa.String(length=64), nullable=True),
|
||||
sa.Column('reenrollblocked', sa.Boolean(), nullable=False,
|
||||
server_default=sa.false()),
|
||||
sa.Column('reenrollblockedreason', sa.String(length=64),
|
||||
nullable=True),
|
||||
sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('credentialid'),
|
||||
sa.UniqueConstraint('assetid'),
|
||||
sa.UniqueConstraint('credentialhash'),
|
||||
)
|
||||
else:
|
||||
# A test database that ran an earlier build of this revision.
|
||||
columns = _columns(CREDENTIALS)
|
||||
if 'reenrollblocked' not in columns:
|
||||
op.add_column(CREDENTIALS, sa.Column(
|
||||
'reenrollblocked', sa.Boolean(), nullable=False,
|
||||
server_default=sa.false()))
|
||||
if 'reenrollblockedreason' not in columns:
|
||||
op.add_column(CREDENTIALS, sa.Column(
|
||||
'reenrollblockedreason', sa.String(length=64), nullable=True))
|
||||
|
||||
if not _has_table(REQUESTS):
|
||||
op.create_table(
|
||||
|
||||
Reference in New Issue
Block a user