Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue related to verification of Windows disk encryption #25875

Merged
merged 3 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changes/25273-hde-windows-verifying
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Fixed issue where Windows disk encryption where status updates from "Verifying" to "Verified" were
sometimes stuck in the "Verifying" state.
2 changes: 1 addition & 1 deletion server/datastore/mysql/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -3829,7 +3829,7 @@ func (ds *Datastore) SetOrUpdateHostDisksSpace(ctx context.Context, hostID uint,
func (ds *Datastore) SetOrUpdateHostDisksEncryption(ctx context.Context, hostID uint, encrypted bool) error {
return ds.updateOrInsert(
ctx,
`UPDATE host_disks SET encrypted = ? WHERE host_id = ?`,
`UPDATE host_disks SET encrypted = ?, updated_at = CURRENT_TIMESTAMP(6) WHERE host_id = ?`,
`INSERT INTO host_disks (encrypted, host_id) VALUES (?, ?)`,
encrypted, hostID,
)
Expand Down
77 changes: 75 additions & 2 deletions server/datastore/mysql/microsoft_mdm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,49 @@ func testMDMWindowsDiskEncryption(t *testing.T, ds *Datastore) {
// Check that filtered lists do include macOS hosts
checkListHostsFilterDiskEncryption(t, nil, fleet.DiskEncryptionFailed, []uint{hosts[1].ID, hosts[5].ID})
checkListHostsFilterOSSettings(t, nil, fleet.OSSettingsFailed, []uint{hosts[1].ID, hosts[5].ID})

// delete the macOS host profile
ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error {
_, err := q.ExecContext(ctx, `DELETE FROM host_mdm_apple_profiles WHERE host_uuid = ? AND profile_identifier = ?`, hosts[5].UUID, mobileconfig.FleetFileVaultPayloadIdentifier)
return err
})
})

t.Run("BitLocker host disks updated", func(t *testing.T) {
gillespi314 marked this conversation as resolved.
Show resolved Hide resolved
// confirm our initial state is as expected
// hosts[2] is was transferred to a team and is not counted
// hosts[3] is a Windows server and is not counted
checkExpected(t, nil, hostIDsByDEStatus{
fleet.DiskEncryptionVerified: []uint{hosts[0].ID},
fleet.DiskEncryptionFailed: []uint{hosts[1].ID},
fleet.DiskEncryptionEnforcing: []uint{hosts[4].ID},
gillespi314 marked this conversation as resolved.
Show resolved Hide resolved
})

// simulate host[4] previously reported encrypted for disk encryption detail query
// results
require.NoError(t, ds.SetOrUpdateHostDisksEncryption(ctx, hosts[4].ID, true))
// manualy update host_disks for hosts[3] to encrypted and ensure updated_at
gillespi314 marked this conversation as resolved.
Show resolved Hide resolved
// timestamp is in the past
updateHostDisks(t, hosts[4].ID, true, time.Now().Add(-3*time.Hour))

// simulate host[4] reporting disk encryption key
require.NoError(t, ds.SetOrUpdateHostDiskEncryptionKey(ctx, hosts[4], "test-key", "", ptr.Bool(true)))

// check that host[4] is now counted as verifying (not verified because host_disks still needs to be updated)
checkExpected(t, nil, hostIDsByDEStatus{
fleet.DiskEncryptionVerified: []uint{hosts[0].ID},
fleet.DiskEncryptionFailed: []uint{hosts[1].ID},
fleet.DiskEncryptionVerifying: []uint{hosts[4].ID},
})

// simulate host[4] reporting detail query results for disk encryption
require.NoError(t, ds.SetOrUpdateHostDisksEncryption(ctx, hosts[4].ID, true))
// status for hosts[4] now verified because SetOrUpdateHostDisksEncryption always sets host_disks.updated_at
// to the current timestamp even if the `encrypted` value hasn't changed
checkExpected(t, nil, hostIDsByDEStatus{
fleet.DiskEncryptionVerified: []uint{hosts[0].ID, hosts[4].ID},
fleet.DiskEncryptionFailed: []uint{hosts[1].ID},
})
})
})
}
Expand Down Expand Up @@ -863,6 +906,36 @@ func testMDMWindowsProfilesSummary(t *testing.T, ds *Datastore) {
cleanupTables(t)
})

t.Run("bitlocker host disk updated", func(t *testing.T) {
gillespi314 marked this conversation as resolved.
Show resolved Hide resolved
// all hosts are pending because no profiles and disk encryption is enabled
checkExpected(t, nil, hostIDsByProfileStatus{
fleet.MDMDeliveryPending: []uint{hosts[0].ID, hosts[1].ID, hosts[2].ID, hosts[3].ID, hosts[4].ID},
})

// simulate host already has encrypted disks
require.NoError(t, ds.SetOrUpdateHostDisksEncryption(ctx, hosts[0].ID, true))
// manualy update host_disks for hosts[0] to encrypted and ensure updated_at
// timestamp is in the past
updateHostDisks(t, hosts[0].ID, true, time.Now().Add(-2*time.Hour))

require.NoError(t, ds.SetOrUpdateHostDiskEncryptionKey(ctx, hosts[0], "test-key", "", ptr.Bool(true)))
// status is verifying because hosts_disks hasn't been updated again
checkExpected(t, nil, hostIDsByProfileStatus{
fleet.MDMDeliveryVerifying: []uint{hosts[0].ID},
fleet.MDMDeliveryPending: []uint{hosts[1].ID, hosts[2].ID, hosts[3].ID, hosts[4].ID},
})

require.NoError(t, ds.SetOrUpdateHostDisksEncryption(ctx, hosts[0].ID, true))
// status for hosts[0] now verified because SetOrUpdateHostDisksEncryption always sets host_disks.updated_at
// to the current timestamp even if the `encrypted` value hasn't changed
checkExpected(t, nil, hostIDsByProfileStatus{
fleet.MDMDeliveryVerified: []uint{hosts[0].ID},
fleet.MDMDeliveryPending: []uint{hosts[1].ID, hosts[2].ID, hosts[3].ID, hosts[4].ID},
})

cleanupTables(t)
})

t.Run("bitlocker failed", func(t *testing.T) {
expected := hostIDsByProfileStatus{
fleet.MDMDeliveryPending: []uint{hosts[0].ID, hosts[1].ID, hosts[2].ID, hosts[3].ID, hosts[4].ID},
Expand Down Expand Up @@ -2460,11 +2533,11 @@ VALUES (?, 'pending', 'install', ?, 'disable-onedrive', ?)`, enrolledDevice2.Hos
atomicCommandUUID)
})
assert.Empty(t, count, "All devices have responded, so the command should be completely removed from the queue")

}

func createResponseAsEnrichedSyncML(t *testing.T, enrolledDevice *fleet.MDMWindowsEnrolledDevice, atomicCommandUUID string,
replaceCommandUUID string) fleet.EnrichedSyncML {
replaceCommandUUID string,
) fleet.EnrichedSyncML {
rawResponse := fmt.Sprintf(`
<SyncML
xmlns="SYNCML:SYNCML1.2">
Expand Down
Loading