diff --git a/changes/15817-disk-encryption b/changes/15817-disk-encryption new file mode 100644 index 0000000000..418c47a358 --- /dev/null +++ b/changes/15817-disk-encryption @@ -0,0 +1 @@ +* Fix a bug that didn't allow to enable team disk encryption if macOS MDM was not configured. diff --git a/cmd/fleet/cron.go b/cmd/fleet/cron.go index 6c695c0515..c36757f9f8 100644 --- a/cmd/fleet/cron.go +++ b/cmd/fleet/cron.go @@ -848,7 +848,7 @@ func verifyDiskEncryptionKeys( config *config.FleetConfig, ) error { if !config.MDM.IsAppleSCEPSet() { - logger.Log("inf", "skipping verification of encryption keys as MDM is not fully configured") + logger.Log("inf", "skipping verification of macOS encryption keys as MDM is not fully configured") return nil } diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 8168cf5597..4204611a50 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -1127,7 +1127,18 @@ func (svc *Service) updateTeamMDMAppleSettings(ctx context.Context, tm *fleet.Te if _, err := svc.ds.SaveTeam(ctx, tm); err != nil { return err } - if didUpdateMacOSDiskEncryption { + + appCfg, err := svc.ds.AppConfig(ctx) + if err != nil { + return err + } + + // macOS-specific stuff. For legacy reasons we check if apple is configured + // via `appCfg.MDM.EnabledAndConfigured` + // + // TODO: is there a missing bitlocker activity feed item? (see same TODO on + // other methods that deal with disk encryption) + if appCfg.MDM.EnabledAndConfigured && didUpdateMacOSDiskEncryption { var act fleet.ActivityDetails if tm.Config.MDM.EnableDiskEncryption { act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name} diff --git a/server/service/handler.go b/server/service/handler.go index fa59f1d9e5..482adce9e7 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -533,7 +533,6 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC mdmAppleMW.POST("/api/_version_/fleet/mdm/hosts/{id:[0-9]+}/wipe", deviceWipeEndpoint, deviceWipeRequest{}) mdmAppleMW.GET("/api/_version_/fleet/mdm/hosts/{id:[0-9]+}/profiles", getHostProfilesEndpoint, getHostProfilesRequest{}) - mdmAppleMW.PATCH("/api/_version_/fleet/mdm/apple/settings", updateMDMAppleSettingsEndpoint, updateMDMAppleSettingsRequest{}) mdmAppleMW.PATCH("/api/_version_/fleet/mdm/apple/setup", updateMDMAppleSetupEndpoint, updateMDMAppleSetupRequest{}) mdmAppleMW.GET("/api/_version_/fleet/mdm/apple", getAppleMDMEndpoint, nil) @@ -556,6 +555,10 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC mdmAnyMW.GET("/api/_version_/fleet/mdm/profiles/{profile_uuid}", getMDMConfigProfileEndpoint, getMDMConfigProfileRequest{}) mdmAnyMW.DELETE("/api/_version_/fleet/mdm/profiles/{profile_uuid}", deleteMDMConfigProfileEndpoint, deleteMDMConfigProfileRequest{}) mdmAnyMW.GET("/api/_version_/fleet/mdm/profiles", listMDMConfigProfilesEndpoint, listMDMConfigProfilesRequest{}) + // TODO: this endpoint is being used as a platform-agnostic endpoint, but it + // contains "apple" in the path and the implementation is possibly very + // apple-biased. See issue #15884 + mdmAnyMW.PATCH("/api/_version_/fleet/mdm/apple/settings", updateMDMAppleSettingsEndpoint, updateMDMAppleSettingsRequest{}) // the following set of mdm endpoints must always be accessible (even // if MDM is not configured) as it bootstraps the setup of MDM diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index cee78ad388..b462a175d5 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -3598,6 +3598,36 @@ func (s *integrationMDMTestSuite) TestAppConfigMDMAppleDiskEncryption() { s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp) assert.True(t, acResp.MDM.EnableDiskEncryption.Value) assert.Equal(t, []string{"b"}, acResp.MDM.MacOSSettings.CustomSettings) + + // mdm/apple/settings works for windows as well as it's being used by + // clients (UI) this way + appConf, err := s.ds.AppConfig(context.Background()) + require.NoError(s.T(), err) + appConf.MDM.EnabledAndConfigured = false + appConf.MDM.WindowsEnabledAndConfigured = true + err = s.ds.SaveAppConfig(context.Background(), appConf) + require.NoError(s.T(), err) + defer func() { + appConf, err := s.ds.AppConfig(context.Background()) + require.NoError(s.T(), err) + appConf.MDM.EnabledAndConfigured = true + appConf.MDM.WindowsEnabledAndConfigured = true + err = s.ds.SaveAppConfig(context.Background(), appConf) + require.NoError(s.T(), err) + }() + + // flip and verify the value + s.Do("PATCH", "/api/latest/fleet/mdm/apple/settings", + fleet.MDMAppleSettingsPayload{EnableDiskEncryption: ptr.Bool(false)}, http.StatusNoContent) + acResp = appConfigResponse{} + s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp) + assert.False(t, acResp.MDM.EnableDiskEncryption.Value) + + s.Do("PATCH", "/api/latest/fleet/mdm/apple/settings", + fleet.MDMAppleSettingsPayload{EnableDiskEncryption: ptr.Bool(true)}, http.StatusNoContent) + acResp = appConfigResponse{} + s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp) + assert.True(t, acResp.MDM.EnableDiskEncryption.Value) } func (s *integrationMDMTestSuite) TestMDMAppleDiskEncryptionAggregate() { @@ -4011,6 +4041,36 @@ func (s *integrationMDMTestSuite) TestTeamsMDMAppleDiskEncryption() { // use the MDM settings endpoint with an unknown team id s.Do("PATCH", "/api/latest/fleet/mdm/apple/settings", fleet.MDMAppleSettingsPayload{TeamID: ptr.Uint(9999)}, http.StatusNotFound) + + // mdm/apple/settings works for windows as well as it's being used by + // clients (UI) this way + appConf, err := s.ds.AppConfig(context.Background()) + require.NoError(s.T(), err) + appConf.MDM.EnabledAndConfigured = false + appConf.MDM.WindowsEnabledAndConfigured = true + err = s.ds.SaveAppConfig(context.Background(), appConf) + require.NoError(s.T(), err) + defer func() { + appConf, err := s.ds.AppConfig(context.Background()) + require.NoError(s.T(), err) + appConf.MDM.EnabledAndConfigured = true + appConf.MDM.WindowsEnabledAndConfigured = true + err = s.ds.SaveAppConfig(context.Background(), appConf) + require.NoError(s.T(), err) + }() + + // flip and verify the value + s.Do("PATCH", "/api/latest/fleet/mdm/apple/settings", + fleet.MDMAppleSettingsPayload{TeamID: ptr.Uint(team.ID), EnableDiskEncryption: ptr.Bool(false)}, http.StatusNoContent) + teamResp = getTeamResponse{} + s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), nil, http.StatusOK, &teamResp) + require.False(t, teamResp.Team.Config.MDM.EnableDiskEncryption) + + s.Do("PATCH", "/api/latest/fleet/mdm/apple/settings", + fleet.MDMAppleSettingsPayload{TeamID: ptr.Uint(team.ID), EnableDiskEncryption: ptr.Bool(true)}, http.StatusNoContent) + teamResp = getTeamResponse{} + s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), nil, http.StatusOK, &teamResp) + require.True(t, teamResp.Team.Config.MDM.EnableDiskEncryption) } func (s *integrationMDMTestSuite) TestBatchSetMDMAppleProfiles() {