Bugfix: Ignore non-Fleet-MDM-enrolled Windows hosts in disk encryption stats and filters (#27066)

This commit is contained in:
Martin Angers
2025-03-12 15:31:23 -04:00
committed by GitHub
parent aa2266f151
commit 29b06a61f1
5 changed files with 149 additions and 13 deletions
@@ -0,0 +1 @@
* Fixed a bug to ignore Windows hosts that are not enrolled in Fleet MDM for disk encryption statistics and filters.
+5 -1
View File
@@ -1560,7 +1560,11 @@ func (ds *Datastore) filterHostsByOSSettingsDiskEncryptionStatus(sql string, opt
// team" filter here (note that filterHostsByTeam applies the "no team" filter if TeamFilter == 0)
sqlFmt += ` AND h.team_id IS NULL`
}
sqlFmt += ` AND ((h.platform = 'windows' AND %s) OR (h.platform = 'darwin' AND %s) OR ((h.platform = 'ubuntu' OR h.os_version LIKE 'Fedora%%') AND %s))`
sqlFmt += ` AND (
(h.platform = 'windows' AND mwe.host_uuid IS NOT NULL AND hmdm.enrolled = 1 AND hmdm.is_server = 0 AND %s) -- windows
OR (h.platform = 'darwin' AND ne.id IS NOT NULL AND hmdm.enrolled = 1 AND %s) -- apple
OR ((h.platform = 'ubuntu' OR h.os_version LIKE 'Fedora%%') AND %s) -- linux
)`
var subqueryMacOS string
var subqueryParams []interface{}
+2 -1
View File
@@ -710,7 +710,8 @@ func (ds *Datastore) applyHostLabelFilters(ctx context.Context, filter fleet.Tea
if opt.ConnectedToFleetFilter != nil && *opt.ConnectedToFleetFilter ||
opt.OSSettingsFilter.IsValid() ||
opt.MacOSSettingsFilter.IsValid() ||
opt.MacOSSettingsDiskEncryptionFilter.IsValid() {
opt.MacOSSettingsDiskEncryptionFilter.IsValid() ||
opt.OSSettingsDiskEncryptionFilter.IsValid() {
query += `
LEFT JOIN nano_enrollments ne ON ne.id = h.uuid AND ne.enabled = 1 AND ne.type = 'Device'
LEFT JOIN mdm_windows_enrollments mwe ON mwe.host_uuid = h.uuid AND mwe.device_state = ?`
+11 -3
View File
@@ -585,11 +585,16 @@ SELECT
0 AS removing_enforcement
FROM
hosts h
JOIN host_mdm hmdm ON h.id = hmdm.host_id
JOIN mdm_windows_enrollments mwe ON h.uuid = mwe.host_uuid
LEFT JOIN host_disk_encryption_keys hdek ON h.id = hdek.host_id
LEFT JOIN host_mdm hmdm ON h.id = hmdm.host_id
LEFT JOIN host_disks hd ON h.id = hd.host_id
LEFT JOIN host_disks hd ON h.id = hd.host_id
WHERE
h.platform = 'windows' AND hmdm.is_server = 0 AND %s`
mwe.device_state = '%s' AND
h.platform = 'windows' AND
hmdm.is_server = 0 AND
hmdm.enrolled = 1 AND
%s`
var args []interface{}
teamFilter := "h.team_id IS NULL"
@@ -605,6 +610,7 @@ WHERE
ds.whereBitLockerStatus(fleet.DiskEncryptionVerifying),
ds.whereBitLockerStatus(fleet.DiskEncryptionEnforcing),
ds.whereBitLockerStatus(fleet.DiskEncryptionFailed),
microsoft_mdm.MDMDeviceStateEnrolled,
teamFilter,
)
if err := sqlx.GetContext(ctx, ds.reader(ctx), &res, stmt, args...); err != nil {
@@ -961,6 +967,7 @@ WHERE
mwe.device_state = '%s' AND
h.platform = 'windows' AND
hmdm.is_server = 0 AND
hmdm.enrolled = 1 AND
%s
GROUP BY
status`,
@@ -1093,6 +1100,7 @@ WHERE
mwe.device_state = '%s' AND
h.platform = 'windows' AND
hmdm.is_server = 0 AND
hmdm.enrolled = 1 AND
%s
GROUP BY
status`,
+130 -8
View File
@@ -1136,8 +1136,6 @@ func setupPusher(s *integrationMDMTestSuite, t *testing.T, mdmDevice *mdmtest.Te
}
func createHostThenEnrollMDM(ds fleet.Datastore, fleetServerURL string, t *testing.T) (*fleet.Host, *mdmtest.TestAppleMDMClient) {
desktopToken := uuid.New().String()
mdmDevice := mdmtest.NewTestMDMClientAppleDesktopManual(fleetServerURL, desktopToken)
fleetHost, err := ds.NewHost(context.Background(), &fleet.Host{
DetailUpdatedAt: time.Now(),
LabelUpdatedAt: time.Now(),
@@ -1149,18 +1147,27 @@ func createHostThenEnrollMDM(ds fleet.Datastore, fleetServerURL string, t *testi
Platform: "darwin",
HardwareModel: "MacBookPro16,1",
UUID: mdmDevice.UUID,
HardwareSerial: mdmDevice.SerialNumber,
UUID: strings.ToUpper(uuid.NewString()),
HardwareSerial: mdmtest.RandSerialNumber(),
})
require.NoError(t, err)
mdmDevice := enrollMacOSHostInMDM(t, fleetHost, ds, fleetServerURL)
err = ds.SetOrUpdateDeviceAuthToken(context.Background(), fleetHost.ID, desktopToken)
return fleetHost, mdmDevice
}
func enrollMacOSHostInMDM(t *testing.T, host *fleet.Host, ds fleet.Datastore, fleetServerURL string) *mdmtest.TestAppleMDMClient {
desktopToken := uuid.New().String()
mdmDevice := mdmtest.NewTestMDMClientAppleDesktopManual(fleetServerURL, desktopToken)
mdmDevice.UUID = host.UUID
mdmDevice.SerialNumber = host.HardwareSerial
err := ds.SetOrUpdateDeviceAuthToken(context.Background(), host.ID, desktopToken)
require.NoError(t, err)
err = mdmDevice.Enroll()
require.NoError(t, err)
return fleetHost, mdmDevice
return mdmDevice
}
func (s *integrationMDMTestSuite) createAppleMobileHostThenEnrollMDM(platform string) (*fleet.Host, *mdmtest.TestAppleMDMClient) {
@@ -1201,6 +1208,11 @@ func (s *integrationMDMTestSuite) createAppleMobileHostThenEnrollMDM(platform st
func createWindowsHostThenEnrollMDM(ds fleet.Datastore, fleetServerURL string, t *testing.T) (*fleet.Host, *mdmtest.TestWindowsMDMClient) {
host := createOrbitEnrolledHost(t, "windows", "h1", ds)
mdmDevice := enrollWindowsHostInMDM(t, host, ds, fleetServerURL)
return host, mdmDevice
}
func enrollWindowsHostInMDM(t *testing.T, host *fleet.Host, ds fleet.Datastore, fleetServerURL string) *mdmtest.TestWindowsMDMClient {
mdmDevice := mdmtest.NewTestMDMClientWindowsProgramatic(fleetServerURL, *host.OrbitNodeKey)
err := mdmDevice.Enroll()
require.NoError(t, err)
@@ -1208,7 +1220,7 @@ func createWindowsHostThenEnrollMDM(ds fleet.Datastore, fleetServerURL string, t
require.NoError(t, err)
err = ds.SetOrUpdateMDMData(context.Background(), host.ID, false, true, fleetServerURL, false, fleet.WellKnownMDMFleet, "")
require.NoError(t, err)
return host, mdmDevice
return mdmDevice
}
func loadEnrollmentProfileDEPToken(t *testing.T, ds *mysql.Datastore) string {
@@ -14603,3 +14615,113 @@ func (s *integrationMDMTestSuite) TestUpcomingActivitiesTurnMDMOff() {
nil, http.StatusOK, &hostActivitiesResp)
require.Len(t, hostActivitiesResp.Activities, 0)
}
// Test for #24265
func (s *integrationMDMTestSuite) TestNonMDWindowsHostsIgnoredInDiskEncryptionStats() {
t := s.T()
ctx := context.Background()
s.setSkipWorkerJobs(t)
// get the All hosts label ID
ls, err := s.ds.LabelIDsByName(ctx, []string{"All Hosts"})
require.NoError(t, err)
require.Len(t, ls, 1)
allHostsLblID := ls["All Hosts"]
// create a couple Windows non-MDM-enrolled hosts
winHost1 := createOrbitEnrolledHost(t, "windows", "h1", s.ds)
winHost2 := createOrbitEnrolledHost(t, "windows", "h2", s.ds)
err = s.ds.SetOrUpdateMDMData(ctx, winHost1.ID, false, false, "", false, "", "")
require.NoError(t, err)
err = s.ds.SetOrUpdateMDMData(ctx, winHost2.ID, false, false, "", false, "", "")
require.NoError(t, err)
err = s.ds.AddLabelsToHost(ctx, winHost1.ID, []uint{allHostsLblID})
require.NoError(t, err)
err = s.ds.AddLabelsToHost(ctx, winHost2.ID, []uint{allHostsLblID})
require.NoError(t, err)
// enable disk encryption
s.Do("POST", "/api/latest/fleet/disk_encryption", updateDiskEncryptionRequest{EnableDiskEncryption: true}, http.StatusNoContent)
acResp := appConfigResponse{}
s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp)
assert.True(t, acResp.MDM.EnableDiskEncryption.Value)
pluckHostIDs := func(hosts []fleet.HostResponse) []uint {
if len(hosts) == 0 {
return nil
}
ids := make([]uint, len(hosts))
for i, h := range hosts {
ids[i] = h.ID
}
return ids
}
checkFilters := func(filter, value string, expectIDs ...uint) {
listHostsRes := listHostsResponse{}
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &listHostsRes, filter, value)
require.Len(t, listHostsRes.Hosts, len(expectIDs), value)
require.Equal(t, expectIDs, pluckHostIDs(listHostsRes.Hosts), value)
countResp := countHostsResponse{}
s.DoJSON("GET", "/api/latest/fleet/hosts/count", nil, http.StatusOK, &countResp, filter, value)
require.Equal(t, len(expectIDs), countResp.Count, value)
listHostsRes = listHostsResponse{}
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/labels/%d/hosts", allHostsLblID), nil, http.StatusOK, &listHostsRes, filter, value)
require.Len(t, listHostsRes.Hosts, len(expectIDs), value)
require.Equal(t, expectIDs, pluckHostIDs(listHostsRes.Hosts), value)
// The other hosts-filter-related endpoints (delete by filter, transfer by
// filter, hosts report) all use either ListHosts or ListsHostsInLabel.
}
// all profiles counts are expected to be 0 (no host is MDM-enrolled in Fleet)
s.checkMDMProfilesSummaries(t, nil, fleet.MDMProfilesSummary{}, nil)
// filter hosts with any OS Settings status, should have none
statuses := []fleet.OSSettingsStatus{
fleet.OSSettingsVerified, fleet.OSSettingsVerifying,
fleet.OSSettingsPending, fleet.OSSettingsFailed,
}
for _, status := range statuses {
checkFilters("os_settings", string(status))
}
// all disk encryption counts are expected to be 0 (no host is MDM-enrolled in Fleet)
s.checkMDMDiskEncryptionSummaries(t, nil, fleet.MDMDiskEncryptionSummary{}, false)
// filter hosts with any Disk Encryption status, should have none
diskStatuses := []fleet.DiskEncryptionStatus{
fleet.DiskEncryptionVerified, fleet.DiskEncryptionVerifying,
fleet.DiskEncryptionActionRequired, fleet.DiskEncryptionEnforcing,
fleet.DiskEncryptionFailed, fleet.DiskEncryptionRemovingEnforcement,
}
for _, status := range diskStatuses {
checkFilters("os_settings_disk_encryption", string(status))
}
// enroll a Windows host in Fleet MDM
enrollWindowsHostInMDM(t, winHost1, s.ds, s.server.URL)
// stats should now count this host
s.checkMDMProfilesSummaries(t, nil, fleet.MDMProfilesSummary{Pending: 1}, nil)
s.checkMDMDiskEncryptionSummaries(t, nil, fleet.MDMDiskEncryptionSummary{Enforcing: fleet.MDMPlatformsCounts{Windows: 1}}, false)
// filters should return this host
checkFilters("os_settings", string(fleet.OSSettingsPending), winHost1.ID)
checkFilters("os_settings_disk_encryption", string(fleet.DiskEncryptionEnforcing), winHost1.ID)
// enroll the other Windows host in a third-party MDM
err = s.ds.SetOrUpdateMDMData(ctx, winHost2.ID, false, true, "https://simplemdm.com", true, fleet.WellKnownMDMSimpleMDM, "")
require.NoError(t, err)
// stats should NOT count winHost2 (not in Fleet MDM)
s.checkMDMProfilesSummaries(t, nil, fleet.MDMProfilesSummary{Pending: 1}, nil)
s.checkMDMDiskEncryptionSummaries(t, nil, fleet.MDMDiskEncryptionSummary{Enforcing: fleet.MDMPlatformsCounts{Windows: 1}}, false)
// filters should NOT return this host
checkFilters("os_settings", string(fleet.OSSettingsPending), winHost1.ID)
checkFilters("os_settings_disk_encryption", string(fleet.DiskEncryptionEnforcing), winHost1.ID)
}