From 4fc07c77384ba56d0bc896a89ef60a6927ea2411 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Wed, 23 Jul 2025 14:38:49 -0500 Subject: [PATCH] Add config for requiring BitLocker PIN (#31109) For #31063 # Details This PR adds the `RequireBitLockerPIN` config to app-wide and team configs. This maps to a new `windows_require_bitlocker_pin` JSON field for gitops and `fleetctl apply`. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. * Will add changelog when feature is complete - For new Fleet configuration settings - [X] Verified that the setting can be managed via GitOps, or confirmed that the setting is explicitly being excluded from GitOps. If managing via Gitops: - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [ ] Added the setting to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) * Will add to docs when feature is complete - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) - [ ] Verified that any relevant UI is disabled when GitOps mode is enabled * No UI yet - [X] Manual QA for all new/changed functionality * Tested No Team and team config via Postman API calls * Tested Gitops for no-team and team YML files using `fleetctl` * Tested `fleetctl generate-gitops` --- cmd/fleetctl/fleetctl/generate_gitops.go | 2 + cmd/fleetctl/fleetctl/gitops_test.go | 20 ++++++ .../expectedGetConfigAppConfigJson.json | 3 +- ...dGetConfigAppConfigTeamMaintainerJson.json | 3 +- ...edGetConfigAppConfigTeamMaintainerYaml.yml | 1 + .../expectedGetConfigAppConfigYaml.yml | 1 + ...ectedGetConfigIncludeServerConfigJson.json | 3 +- ...pectedGetConfigIncludeServerConfigYaml.yml | 1 + .../testdata/expectedGetTeamsJson.json | 4 +- .../testdata/expectedGetTeamsYaml.yml | 2 + .../expectedGlobalControls.yaml | 1 + .../test_dir_premium/teams/no-team.yml | 1 + .../test_dir_premium/teams/team-a.yml | 1 + .../gitops/global_config_no_paths.yml | 1 + .../testdata/gitops/team_config_no_paths.yml | 3 +- .../macosSetupExpectedAppConfigEmpty.yml | 1 + .../macosSetupExpectedAppConfigSet.yml | 1 + .../macosSetupExpectedTeam1And2Empty.yml | 2 + .../macosSetupExpectedTeam1And2Set.yml | 2 + .../testdata/macosSetupExpectedTeam1Empty.yml | 1 + .../testdata/macosSetupExpectedTeam1Set.yml | 1 + ee/server/service/teams.go | 63 ++++++++++++------- pkg/spec/gitops.go | 1 + pkg/spec/testdata/team_config_no_paths.yml | 1 + server/datastore/mysql/app_configs_test.go | 6 ++ server/datastore/mysql/schema.sql | 2 +- server/fleet/app.go | 2 + server/fleet/service.go | 4 +- server/fleet/teams.go | 7 +++ server/service/appconfig_test.go | 6 ++ server/service/apple_mdm.go | 2 +- server/service/apple_mdm_test.go | 2 +- server/service/client.go | 5 ++ server/service/mdm.go | 7 ++- .../generated_files/appconfig.txt | 1 + .../cloner-check/generated_files/teammdm.txt | 1 + 36 files changed, 130 insertions(+), 35 deletions(-) diff --git a/cmd/fleetctl/fleetctl/generate_gitops.go b/cmd/fleetctl/fleetctl/generate_gitops.go index 66d479ac41..9967b4dd65 100644 --- a/cmd/fleetctl/fleetctl/generate_gitops.go +++ b/cmd/fleetctl/fleetctl/generate_gitops.go @@ -323,6 +323,7 @@ func (cmd *GenerateGitopsCommand) Run() error { // We'll override this for teams other than no-team. mdmConfig := fleet.TeamMDM{ EnableDiskEncryption: cmd.AppConfig.MDM.EnableDiskEncryption.Value, + RequireBitLockerPIN: cmd.AppConfig.MDM.RequireBitLockerPIN.Value, MacOSUpdates: cmd.AppConfig.MDM.MacOSUpdates, IOSUpdates: cmd.AppConfig.MDM.IOSUpdates, IPadOSUpdates: cmd.AppConfig.MDM.IPadOSUpdates, @@ -913,6 +914,7 @@ func (cmd *GenerateGitopsCommand) generateControls(teamId *uint, teamName string if teamMdm != nil { result[jsonFieldName(mdmT, "EnableDiskEncryption")] = teamMdm.EnableDiskEncryption + result[jsonFieldName(mdmT, "RequireBitLockerPIN")] = teamMdm.RequireBitLockerPIN result[jsonFieldName(mdmT, "MacOSUpdates")] = teamMdm.MacOSUpdates result[jsonFieldName(mdmT, "IOSUpdates")] = teamMdm.IOSUpdates result[jsonFieldName(mdmT, "IPadOSUpdates")] = teamMdm.IPadOSUpdates diff --git a/cmd/fleetctl/fleetctl/gitops_test.go b/cmd/fleetctl/fleetctl/gitops_test.go index e575e85fae..d2fd32dc47 100644 --- a/cmd/fleetctl/fleetctl/gitops_test.go +++ b/cmd/fleetctl/fleetctl/gitops_test.go @@ -348,6 +348,8 @@ controls: ipados_updates: deadline: "2023-03-03" minimum_version: "18.0" + enable_disk_encryption: true + windows_require_bitlocker_pin: true queries: policies: labels: @@ -437,6 +439,9 @@ software: assert.Equal(t, "CustomScepProxy2", sceps[1].Name) assert.Equal(t, "https://custom.scep.proxy.com2", sceps[1].URL) assert.Equal(t, "challenge2", sceps[1].Challenge) + + require.True(t, savedAppConfig.MDM.EnableDiskEncryption.Value) + require.True(t, savedAppConfig.MDM.RequireBitLockerPIN.Value) } func TestGitOpsBasicTeam(t *testing.T) { @@ -1158,6 +1163,8 @@ func TestGitOpsFullTeam(t *testing.T) { testing_utils.StartSoftwareInstallerServer(t) t.Setenv("TEST_TEAM_NAME", teamName) + t.Setenv("ENABLE_DISK_ENCRYPTION", "true") + t.Setenv("WINDOWS_REQUIRE_BITLOCKER_PIN", "true") // Dry run const baseFilename = "team_config_no_paths.yml" @@ -1184,6 +1191,7 @@ func TestGitOpsFullTeam(t *testing.T) { assert.True(t, savedTeam.Config.Features.EnableHostUsers) assert.Equal(t, 30, savedTeam.Config.HostExpirySettings.HostExpiryWindow) assert.True(t, savedTeam.Config.MDM.EnableDiskEncryption) + assert.True(t, savedTeam.Config.MDM.RequireBitLockerPIN) assert.Len(t, enrolledSecrets, 2) assert.True(t, policyDeleted) assert.Len(t, appliedPolicySpecs, 5) @@ -1203,6 +1211,15 @@ func TestGitOpsFullTeam(t *testing.T) { assert.ElementsMatch(t, []string{fmt.Sprintf("echo 'uninstall' %s\n", packageID), uninstallScriptProcessed}, []string{appliedSoftwareInstallers[0].UninstallScript, appliedSoftwareInstallers[1].UninstallScript}) + // Change disk encryption settings + t.Setenv("ENABLE_DISK_ENCRYPTION", "false") + t.Setenv("WINDOWS_REQUIRE_BITLOCKER_PIN", "false") + _ = RunAppForTest(t, []string{"gitops", "-f", gitopsFile, "--dry-run"}) + _ = RunAppForTest(t, []string{"gitops", "-f", gitopsFile}) + require.NotNil(t, savedTeam) + assert.False(t, savedTeam.Config.MDM.EnableDiskEncryption) + assert.False(t, savedTeam.Config.MDM.RequireBitLockerPIN) + // Change team name newTeamName := "New Team Name" t.Setenv("TEST_TEAM_NAME", newTeamName) @@ -2204,6 +2221,9 @@ func TestGitOpsFullGlobalAndTeam(t *testing.T) { globalFile := "./testdata/gitops/global_config_no_paths.yml" teamFile := "./testdata/gitops/team_config_no_paths.yml" + t.Setenv("ENABLE_DISK_ENCRYPTION", "true") + t.Setenv("WINDOWS_REQUIRE_BITLOCKER_PIN", "true") + // Dry run _ = RunAppForTest(t, []string{"gitops", "-f", globalFile, "-f", teamFile, "--dry-run", "--delete-other-teams"}) assert.False(t, ds.SaveAppConfigFuncInvoked) diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigJson.json b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigJson.json index 3c9caee7fc..3f4fd1c581 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigJson.json +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigJson.json @@ -123,6 +123,7 @@ "grace_period_days": 3 }, "windows_migration_enabled": false, + "windows_require_bitlocker_pin": null, "macos_migration": { "enable": false, "mode": "", @@ -157,4 +158,4 @@ "repository_url": "" } } -} +} \ No newline at end of file diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerJson.json b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerJson.json index 5ac1c43739..67e3b5c318 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerJson.json +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerJson.json @@ -79,6 +79,7 @@ "volume_purchasing_program": null, "windows_enabled_and_configured": false, "enable_disk_encryption": false, + "windows_require_bitlocker_pin": null, "macos_updates": { "minimum_version": null, "deadline": null @@ -130,4 +131,4 @@ "repository_url": "" } } -} +} \ No newline at end of file diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerYaml.yml b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerYaml.yml index 0876d9aba2..ff6e7e86a1 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerYaml.yml +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigTeamMaintainerYaml.yml @@ -31,6 +31,7 @@ spec: volume_purchasing_program: null windows_enabled_and_configured: false enable_disk_encryption: false + windows_require_bitlocker_pin: null windows_migration_enabled: false macos_migration: enable: false diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml index 7e5e41c0d9..face4d1ec8 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml @@ -31,6 +31,7 @@ spec: volume_purchasing_program: null windows_enabled_and_configured: false enable_disk_encryption: false + windows_require_bitlocker_pin: null windows_migration_enabled: false macos_migration: enable: false diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json index 2a8f309cfa..a605a10bc6 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json @@ -55,6 +55,7 @@ "enabled_and_configured": false, "windows_enabled_and_configured": false, "enable_disk_encryption": false, + "windows_require_bitlocker_pin": null, "macos_updates": { "minimum_version": null, "deadline": null @@ -220,4 +221,4 @@ "repository_url": "" } } -} +} \ No newline at end of file diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml index 76b17918da..19e6e9ba89 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml @@ -31,6 +31,7 @@ spec: enabled_and_configured: false windows_enabled_and_configured: false enable_disk_encryption: false + windows_require_bitlocker_pin: null windows_migration_enabled: false macos_migration: enable: false diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsJson.json b/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsJson.json index f94cc8b618..8490e157f5 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsJson.json +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsJson.json @@ -32,6 +32,7 @@ }, "mdm": { "enable_disk_encryption": false, + "windows_require_bitlocker_pin": false, "macos_updates": { "minimum_version": null, "deadline": null @@ -119,6 +120,7 @@ }, "mdm": { "enable_disk_encryption": false, + "windows_require_bitlocker_pin": false, "macos_updates": { "minimum_version": "12.3.1", "deadline": "2021-12-14" @@ -156,4 +158,4 @@ "host_count": 43 } } -} +} \ No newline at end of file diff --git a/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsYaml.yml b/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsYaml.yml index 573e8520eb..c3259d5154 100644 --- a/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsYaml.yml +++ b/cmd/fleetctl/fleetctl/testdata/expectedGetTeamsYaml.yml @@ -14,6 +14,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_updates: minimum_version: null deadline: null @@ -69,6 +70,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_updates: minimum_version: "12.3.1" deadline: "2021-12-14" diff --git a/cmd/fleetctl/fleetctl/testdata/generateGitops/expectedGlobalControls.yaml b/cmd/fleetctl/fleetctl/testdata/generateGitops/expectedGlobalControls.yaml index 57854feb55..9dd7a201ad 100644 --- a/cmd/fleetctl/fleetctl/testdata/generateGitops/expectedGlobalControls.yaml +++ b/cmd/fleetctl/fleetctl/testdata/generateGitops/expectedGlobalControls.yaml @@ -26,6 +26,7 @@ windows_updates: grace_period_days: 2 windows_enabled_and_configured: true windows_migration_enabled: true +windows_require_bitlocker_pin: false enable_disk_encryption: true macos_migration: # Available in Fleet Premium enable: true diff --git a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/no-team.yml b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/no-team.yml index e375ad6b51..efd671b15e 100644 --- a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/no-team.yml +++ b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/no-team.yml @@ -18,6 +18,7 @@ controls: - path: ../lib/no-team/scripts/Script Z.ps1 windows_enabled_and_configured: true windows_migration_enabled: true + windows_require_bitlocker_pin: false windows_updates: deadline_days: 5 grace_period_days: 2 diff --git a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/team-a.yml b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/team-a.yml index 3aaa1cd2dc..5ee6c18cca 100644 --- a/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/team-a.yml +++ b/cmd/fleetctl/fleetctl/testdata/generateGitops/test_dir_premium/teams/team-a.yml @@ -34,6 +34,7 @@ controls: scripts: - path: ../lib/team-a/scripts/Script B.ps1 windows_enabled_and_configured: true + windows_require_bitlocker_pin: false windows_updates: deadline_days: 95 grace_period_days: 92 diff --git a/cmd/fleetctl/fleetctl/testdata/gitops/global_config_no_paths.yml b/cmd/fleetctl/fleetctl/testdata/gitops/global_config_no_paths.yml index e19164577a..3ba41c00e7 100644 --- a/cmd/fleetctl/fleetctl/testdata/gitops/global_config_no_paths.yml +++ b/cmd/fleetctl/fleetctl/testdata/gitops/global_config_no_paths.yml @@ -20,6 +20,7 @@ controls: # Controls added to "No team" scripts: - path: ./lib/collect-fleetd-logs.sh enable_disk_encryption: false + windows_require_bitlocker_pin: false macos_migration: enable: false mode: "" diff --git a/cmd/fleetctl/fleetctl/testdata/gitops/team_config_no_paths.yml b/cmd/fleetctl/fleetctl/testdata/gitops/team_config_no_paths.yml index d3db1bdd65..72747a9daa 100644 --- a/cmd/fleetctl/fleetctl/testdata/gitops/team_config_no_paths.yml +++ b/cmd/fleetctl/fleetctl/testdata/gitops/team_config_no_paths.yml @@ -43,7 +43,8 @@ controls: - path: ./lib/windows-screenlock.xml scripts: - path: ./lib/collect-fleetd-logs.sh - enable_disk_encryption: true + enable_disk_encryption: ${ENABLE_DISK_ENCRYPTION} + windows_require_bitlocker_pin: ${WINDOWS_REQUIRE_BITLOCKER_PIN} macos_migration: enable: false mode: "" diff --git a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml index 84ab99de9b..3d57b1adc9 100644 --- a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml +++ b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml @@ -31,6 +31,7 @@ spec: enabled_and_configured: true windows_enabled_and_configured: false enable_disk_encryption: false + windows_require_bitlocker_pin: null windows_migration_enabled: false macos_migration: enable: false diff --git a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml index 435e8c7786..e65340a4fd 100644 --- a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml +++ b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml @@ -31,6 +31,7 @@ spec: enabled_and_configured: true windows_enabled_and_configured: false enable_disk_encryption: false + windows_require_bitlocker_pin: null windows_migration_enabled: false macos_migration: enable: false diff --git a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml index cb3930cb4b..f29aba54a4 100644 --- a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml +++ b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml @@ -14,6 +14,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_settings: custom_settings: null windows_settings: @@ -60,6 +61,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_settings: custom_settings: null windows_settings: diff --git a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml index ac4f55344a..68f33d9e14 100644 --- a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml +++ b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml @@ -14,6 +14,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_settings: custom_settings: null windows_settings: @@ -60,6 +61,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_settings: custom_settings: null windows_settings: diff --git a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml index 28665e26ed..1feb18655d 100644 --- a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml +++ b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml @@ -14,6 +14,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_settings: custom_settings: null macos_setup: diff --git a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Set.yml b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Set.yml index 1418c61803..710e3cb7b6 100644 --- a/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Set.yml +++ b/cmd/fleetctl/fleetctl/testdata/macosSetupExpectedTeam1Set.yml @@ -13,6 +13,7 @@ spec: conditional_access_enabled: null mdm: enable_disk_encryption: false + windows_require_bitlocker_pin: null macos_settings: custom_settings: null windows_settings: diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 533fa7dbce..385ad9991d 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -219,6 +219,10 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T team.Config.MDM.EnableDiskEncryption = payload.MDM.EnableDiskEncryption.Value } + if payload.MDM.RequireBitLockerPIN.Valid { + team.Config.MDM.RequireBitLockerPIN = payload.MDM.RequireBitLockerPIN.Value + } + if payload.MDM.MacOSSetup != nil { if !appCfg.MDM.EnabledAndConfigured && team.Config.MDM.MacOSSetup.EnableEndUserAuthentication != payload.MDM.MacOSSetup.EnableEndUserAuthentication { return nil, ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("macos_setup.enable_end_user_authentication", @@ -1160,6 +1164,7 @@ func (svc *Service) createTeamFromSpec( Features: features, MDM: fleet.TeamMDM{ EnableDiskEncryption: enableDiskEncryption, + RequireBitLockerPIN: spec.MDM.RequireBitLockerPIN.Value, MacOSUpdates: spec.MDM.MacOSUpdates, WindowsUpdates: spec.MDM.WindowsUpdates, MacOSSettings: macOSSettings, @@ -1280,6 +1285,11 @@ func (svc *Service) editTeamFromSpec( if didUpdateDiskEncryption && team.Config.MDM.EnableDiskEncryption && svc.config.Server.PrivateKey == "" { return ctxerr.New(ctx, "Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key") } + + if spec.MDM.RequireBitLockerPIN.Valid { + team.Config.MDM.RequireBitLockerPIN = spec.MDM.RequireBitLockerPIN.Value + } + if !team.Config.MDM.MacOSSetup.EnableReleaseDeviceManually.Valid { team.Config.MDM.MacOSSetup.EnableReleaseDeviceManually = optjson.SetBool(false) } @@ -1638,8 +1648,9 @@ func unmarshalWithGlobalDefaults(b *json.RawMessage) (fleet.Features, error) { return *defaults, nil } -func (svc *Service) updateTeamMDMDiskEncryption(ctx context.Context, tm *fleet.Team, enable *bool) error { - var didUpdate bool +func (svc *Service) updateTeamMDMDiskEncryption(ctx context.Context, tm *fleet.Team, enable *bool, requireBitLockerPIN *bool) error { + var didUpdateEncryption bool + var didUpdateRequirePIN bool if enable != nil { if tm.Config.MDM.EnableDiskEncryption != *enable { if *enable && svc.config.Server.PrivateKey == "" { @@ -1647,34 +1658,42 @@ func (svc *Service) updateTeamMDMDiskEncryption(ctx context.Context, tm *fleet.T } tm.Config.MDM.EnableDiskEncryption = *enable - didUpdate = true + didUpdateEncryption = true + } + } + if requireBitLockerPIN != nil { + if tm.Config.MDM.RequireBitLockerPIN != *requireBitLockerPIN { + tm.Config.MDM.RequireBitLockerPIN = *requireBitLockerPIN + didUpdateRequirePIN = true } } - if didUpdate { + if didUpdateEncryption || didUpdateRequirePIN { if _, err := svc.ds.SaveTeam(ctx, tm); err != nil { return err } - appCfg, err := svc.ds.AppConfig(ctx) - if err != nil { - return err - } - if appCfg.MDM.EnabledAndConfigured { - var act fleet.ActivityDetails - if tm.Config.MDM.EnableDiskEncryption { - act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name} - if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &tm.ID); err != nil { - return ctxerr.Wrap(ctx, err, "enable team filevault and escrow") - } - } else { - act = fleet.ActivityTypeDisabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name} - if err := svc.MDMAppleDisableFileVaultAndEscrow(ctx, &tm.ID); err != nil { - return ctxerr.Wrap(ctx, err, "disable team filevault and escrow") - } + if didUpdateEncryption { + appCfg, err := svc.ds.AppConfig(ctx) + if err != nil { + return err } - if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), act); err != nil { - return ctxerr.Wrap(ctx, err, "create activity for team macos disk encryption") + if appCfg.MDM.EnabledAndConfigured { + var act fleet.ActivityDetails + if tm.Config.MDM.EnableDiskEncryption { + act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name} + if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &tm.ID); err != nil { + return ctxerr.Wrap(ctx, err, "enable team filevault and escrow") + } + } else { + act = fleet.ActivityTypeDisabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name} + if err := svc.MDMAppleDisableFileVaultAndEscrow(ctx, &tm.ID); err != nil { + return ctxerr.Wrap(ctx, err, "disable team filevault and escrow") + } + } + if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), act); err != nil { + return ctxerr.Wrap(ctx, err, "create activity for team macos disk encryption") + } } } } diff --git a/pkg/spec/gitops.go b/pkg/spec/gitops.go index 35d2d7261f..5340a4366d 100644 --- a/pkg/spec/gitops.go +++ b/pkg/spec/gitops.go @@ -38,6 +38,7 @@ type GitOpsControls struct { WindowsMigrationEnabled interface{} `json:"windows_migration_enabled"` EnableDiskEncryption interface{} `json:"enable_disk_encryption"` + RequireBitLockerPIN interface{} `json:"windows_require_bitlocker_pin,omitempty"` Scripts []BaseItem `json:"scripts"` diff --git a/pkg/spec/testdata/team_config_no_paths.yml b/pkg/spec/testdata/team_config_no_paths.yml index c66cc89415..71ffe21639 100644 --- a/pkg/spec/testdata/team_config_no_paths.yml +++ b/pkg/spec/testdata/team_config_no_paths.yml @@ -39,6 +39,7 @@ controls: scripts: - path: ./lib/collect-fleetd-logs.sh enable_disk_encryption: true + windows_require_bitlocker_pin: true macos_setup: bootstrap_package: null enable_end_user_authentication: false diff --git a/server/datastore/mysql/app_configs_test.go b/server/datastore/mysql/app_configs_test.go index 0c94265531..ca6335acec 100644 --- a/server/datastore/mysql/app_configs_test.go +++ b/server/datastore/mysql/app_configs_test.go @@ -447,6 +447,7 @@ func testGetConfigEnableDiskEncryption(t *testing.T, ds *Datastore) { ac, err := ds.AppConfig(ctx) require.NoError(t, err) require.False(t, ac.MDM.EnableDiskEncryption.Value) + require.False(t, ac.MDM.RequireBitLockerPIN.Value) enabled, err := ds.GetConfigEnableDiskEncryption(ctx, nil) require.NoError(t, err) @@ -454,11 +455,13 @@ func testGetConfigEnableDiskEncryption(t *testing.T, ds *Datastore) { // Enable disk encryption for no team ac.MDM.EnableDiskEncryption = optjson.SetBool(true) + ac.MDM.RequireBitLockerPIN = optjson.SetBool(true) err = ds.SaveAppConfig(ctx, ac) require.NoError(t, err) ac, err = ds.AppConfig(ctx) require.NoError(t, err) require.True(t, ac.MDM.EnableDiskEncryption.Value) + require.True(t, ac.MDM.RequireBitLockerPIN.Value) enabled, err = ds.GetConfigEnableDiskEncryption(ctx, nil) require.NoError(t, err) @@ -472,6 +475,7 @@ func testGetConfigEnableDiskEncryption(t *testing.T, ds *Datastore) { require.NoError(t, err) require.NotNil(t, tm) require.False(t, tm.Config.MDM.EnableDiskEncryption) + require.False(t, tm.Config.MDM.RequireBitLockerPIN) enabled, err = ds.GetConfigEnableDiskEncryption(ctx, &team1.ID) require.NoError(t, err) @@ -479,10 +483,12 @@ func testGetConfigEnableDiskEncryption(t *testing.T, ds *Datastore) { // Enable disk encryption for the team tm.Config.MDM.EnableDiskEncryption = true + tm.Config.MDM.RequireBitLockerPIN = true tm, err = ds.SaveTeam(ctx, tm) require.NoError(t, err) require.NotNil(t, tm) require.True(t, tm.Config.MDM.EnableDiskEncryption) + require.True(t, tm.Config.MDM.RequireBitLockerPIN) } func testIsEnrollSecretAvailable(t *testing.T, ds *Datastore) { diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 75177eb363..b8e76ed2a0 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -96,7 +96,7 @@ CREATE TABLE `app_config_json` ( PRIMARY KEY (`id`) ) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `app_config_json` VALUES (1,'{\"mdm\": {\"ios_updates\": {\"deadline\": null, \"minimum_version\": null}, \"macos_setup\": {\"script\": null, \"software\": null, \"bootstrap_package\": null, \"manual_agent_install\": null, \"macos_setup_assistant\": null, \"enable_end_user_authentication\": false, \"enable_release_device_manually\": false}, \"macos_updates\": {\"deadline\": null, \"minimum_version\": null}, \"ipados_updates\": {\"deadline\": null, \"minimum_version\": null}, \"macos_settings\": {\"custom_settings\": null}, \"macos_migration\": {\"mode\": \"\", \"enable\": false, \"webhook_url\": \"\"}, \"windows_updates\": {\"deadline_days\": null, \"grace_period_days\": null}, \"apple_server_url\": \"\", \"windows_settings\": {\"custom_settings\": null}, \"apple_bm_terms_expired\": false, \"apple_business_manager\": null, \"enable_disk_encryption\": false, \"enabled_and_configured\": false, \"end_user_authentication\": {\"idp_name\": \"\", \"metadata\": \"\", \"entity_id\": \"\", \"issuer_uri\": \"\", \"metadata_url\": \"\"}, \"volume_purchasing_program\": null, \"windows_migration_enabled\": false, \"android_enabled_and_configured\": false, \"windows_enabled_and_configured\": false, \"apple_bm_enabled_and_configured\": false}, \"gitops\": {\"repository_url\": \"\", \"gitops_mode_enabled\": false}, \"scripts\": null, \"features\": {\"enable_host_users\": true, \"enable_software_inventory\": false}, \"org_info\": {\"org_name\": \"\", \"contact_url\": \"\", \"org_logo_url\": \"\", \"org_logo_url_light_background\": \"\"}, \"integrations\": {\"jira\": null, \"zendesk\": null, \"digicert\": null, \"google_calendar\": null, \"ndes_scep_proxy\": null, \"custom_scep_proxy\": null, \"conditional_access_enabled\": null}, \"sso_settings\": {\"idp_name\": \"\", \"metadata\": \"\", \"entity_id\": \"\", \"enable_sso\": false, \"issuer_uri\": \"\", \"metadata_url\": \"\", \"idp_image_url\": \"\", \"enable_jit_role_sync\": false, \"enable_sso_idp_login\": false, \"enable_jit_provisioning\": false}, \"agent_options\": {\"config\": {\"options\": {\"logger_plugin\": \"tls\", \"pack_delimiter\": \"/\", \"logger_tls_period\": 10, \"distributed_plugin\": \"tls\", \"disable_distributed\": false, \"logger_tls_endpoint\": \"/api/osquery/log\", \"distributed_interval\": 10, \"distributed_tls_max_attempts\": 3}, \"decorators\": {\"load\": [\"SELECT uuid AS host_uuid FROM system_info;\", \"SELECT hostname AS hostname FROM system_info;\"]}}, \"overrides\": {}}, \"fleet_desktop\": {\"transparency_url\": \"\"}, \"smtp_settings\": {\"port\": 587, \"domain\": \"\", \"server\": \"\", \"password\": \"\", \"user_name\": \"\", \"configured\": false, \"enable_smtp\": false, \"enable_ssl_tls\": true, \"sender_address\": \"\", \"enable_start_tls\": true, \"verify_ssl_certs\": true, \"authentication_type\": \"0\", \"authentication_method\": \"0\"}, \"server_settings\": {\"server_url\": \"\", \"enable_analytics\": false, \"query_report_cap\": 0, \"scripts_disabled\": false, \"deferred_save_host\": false, \"live_query_disabled\": false, \"ai_features_disabled\": false, \"query_reports_disabled\": false}, \"webhook_settings\": {\"interval\": \"0s\", \"activities_webhook\": {\"destination_url\": \"\", \"enable_activities_webhook\": false}, \"host_status_webhook\": {\"days_count\": 0, \"destination_url\": \"\", \"host_percentage\": 0, \"enable_host_status_webhook\": false}, \"vulnerabilities_webhook\": {\"destination_url\": \"\", \"host_batch_size\": 0, \"enable_vulnerabilities_webhook\": false}, \"failing_policies_webhook\": {\"policy_ids\": null, \"destination_url\": \"\", \"host_batch_size\": 0, \"enable_failing_policies_webhook\": false}}, \"host_expiry_settings\": {\"host_expiry_window\": 0, \"host_expiry_enabled\": false}, \"vulnerability_settings\": {\"databases_path\": \"\"}, \"activity_expiry_settings\": {\"activity_expiry_window\": 0, \"activity_expiry_enabled\": false}}','2020-01-01 01:01:01','2020-01-01 01:01:01'); +INSERT INTO `app_config_json` VALUES (1,'{\"mdm\": {\"ios_updates\": {\"deadline\": null, \"minimum_version\": null}, \"macos_setup\": {\"script\": null, \"software\": null, \"bootstrap_package\": null, \"manual_agent_install\": null, \"macos_setup_assistant\": null, \"enable_end_user_authentication\": false, \"enable_release_device_manually\": false}, \"macos_updates\": {\"deadline\": null, \"minimum_version\": null}, \"ipados_updates\": {\"deadline\": null, \"minimum_version\": null}, \"macos_settings\": {\"custom_settings\": null}, \"macos_migration\": {\"mode\": \"\", \"enable\": false, \"webhook_url\": \"\"}, \"windows_updates\": {\"deadline_days\": null, \"grace_period_days\": null}, \"apple_server_url\": \"\", \"windows_settings\": {\"custom_settings\": null}, \"apple_bm_terms_expired\": false, \"apple_business_manager\": null, \"enable_disk_encryption\": false, \"enabled_and_configured\": false, \"end_user_authentication\": {\"idp_name\": \"\", \"metadata\": \"\", \"entity_id\": \"\", \"issuer_uri\": \"\", \"metadata_url\": \"\"}, \"volume_purchasing_program\": null, \"windows_migration_enabled\": false, \"windows_require_bitlocker_pin\": null, \"android_enabled_and_configured\": false, \"windows_enabled_and_configured\": false, \"apple_bm_enabled_and_configured\": false}, \"gitops\": {\"repository_url\": \"\", \"gitops_mode_enabled\": false}, \"scripts\": null, \"features\": {\"enable_host_users\": true, \"enable_software_inventory\": false}, \"org_info\": {\"org_name\": \"\", \"contact_url\": \"\", \"org_logo_url\": \"\", \"org_logo_url_light_background\": \"\"}, \"integrations\": {\"jira\": null, \"zendesk\": null, \"digicert\": null, \"google_calendar\": null, \"ndes_scep_proxy\": null, \"custom_scep_proxy\": null, \"conditional_access_enabled\": null}, \"sso_settings\": {\"idp_name\": \"\", \"metadata\": \"\", \"entity_id\": \"\", \"enable_sso\": false, \"issuer_uri\": \"\", \"metadata_url\": \"\", \"idp_image_url\": \"\", \"enable_jit_role_sync\": false, \"enable_sso_idp_login\": false, \"enable_jit_provisioning\": false}, \"agent_options\": {\"config\": {\"options\": {\"logger_plugin\": \"tls\", \"pack_delimiter\": \"/\", \"logger_tls_period\": 10, \"distributed_plugin\": \"tls\", \"disable_distributed\": false, \"logger_tls_endpoint\": \"/api/osquery/log\", \"distributed_interval\": 10, \"distributed_tls_max_attempts\": 3}, \"decorators\": {\"load\": [\"SELECT uuid AS host_uuid FROM system_info;\", \"SELECT hostname AS hostname FROM system_info;\"]}}, \"overrides\": {}}, \"fleet_desktop\": {\"transparency_url\": \"\"}, \"smtp_settings\": {\"port\": 587, \"domain\": \"\", \"server\": \"\", \"password\": \"\", \"user_name\": \"\", \"configured\": false, \"enable_smtp\": false, \"enable_ssl_tls\": true, \"sender_address\": \"\", \"enable_start_tls\": true, \"verify_ssl_certs\": true, \"authentication_type\": \"0\", \"authentication_method\": \"0\"}, \"server_settings\": {\"server_url\": \"\", \"enable_analytics\": false, \"query_report_cap\": 0, \"scripts_disabled\": false, \"deferred_save_host\": false, \"live_query_disabled\": false, \"ai_features_disabled\": false, \"query_reports_disabled\": false}, \"webhook_settings\": {\"interval\": \"0s\", \"activities_webhook\": {\"destination_url\": \"\", \"enable_activities_webhook\": false}, \"host_status_webhook\": {\"days_count\": 0, \"destination_url\": \"\", \"host_percentage\": 0, \"enable_host_status_webhook\": false}, \"vulnerabilities_webhook\": {\"destination_url\": \"\", \"host_batch_size\": 0, \"enable_vulnerabilities_webhook\": false}, \"failing_policies_webhook\": {\"policy_ids\": null, \"destination_url\": \"\", \"host_batch_size\": 0, \"enable_failing_policies_webhook\": false}}, \"host_expiry_settings\": {\"host_expiry_window\": 0, \"host_expiry_enabled\": false}, \"vulnerability_settings\": {\"databases_path\": \"\"}, \"activity_expiry_settings\": {\"activity_expiry_window\": 0, \"activity_expiry_enabled\": false}}','2020-01-01 01:01:01','2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `batch_script_execution_host_results` ( diff --git a/server/fleet/app.go b/server/fleet/app.go index c2cc2a268f..fdddad3b03 100644 --- a/server/fleet/app.go +++ b/server/fleet/app.go @@ -215,6 +215,8 @@ type MDM struct { EnableDiskEncryption optjson.Bool `json:"enable_disk_encryption"` + RequireBitLockerPIN optjson.Bool `json:"windows_require_bitlocker_pin"` + WindowsSettings WindowsSettings `json:"windows_settings"` VolumePurchasingProgram optjson.Slice[MDMAppleVolumePurchasingProgramInfo] `json:"volume_purchasing_program"` diff --git a/server/fleet/service.go b/server/fleet/service.go index 9d388b11d1..4131377d25 100644 --- a/server/fleet/service.go +++ b/server/fleet/service.go @@ -20,7 +20,7 @@ type EnterpriseOverrides struct { TeamByIDOrName func(ctx context.Context, id *uint, name *string) (*Team, error) // UpdateTeamMDMDiskEncryption is the team-specific service method for when // a team ID is provided to the UpdateMDMDiskEncryption method. - UpdateTeamMDMDiskEncryption func(ctx context.Context, tm *Team, enable *bool) error + UpdateTeamMDMDiskEncryption func(ctx context.Context, tm *Team, enable *bool, requireBitLockerPIN *bool) error // The next two functions are implemented by the ee/service, and called // properly when called from an ee/service method (e.g. Modify Team), but @@ -955,7 +955,7 @@ type Service interface { // UpdateMDMDiskEncryption updates the disk encryption setting for a // specified team or for hosts with no team. - UpdateMDMDiskEncryption(ctx context.Context, teamID *uint, enableDiskEncryption *bool) error + UpdateMDMDiskEncryption(ctx context.Context, teamID *uint, enableDiskEncryption *bool, requireBitLockerPIN *bool) error // VerifyMDMAppleConfigured verifies that the server is configured for // Apple MDM. If an error is returned, authorization is skipped so the diff --git a/server/fleet/teams.go b/server/fleet/teams.go index 57c40d7e04..0cbc0309c2 100644 --- a/server/fleet/teams.go +++ b/server/fleet/teams.go @@ -48,6 +48,9 @@ type TeamPayload struct { // so the fields are pointers to structs. type TeamPayloadMDM struct { EnableDiskEncryption optjson.Bool `json:"enable_disk_encryption"` + // RequireBitLockerPIN indicates whether BitLocker PIN is required for Windows devices + // in order for Fleet to consider them compliant. + RequireBitLockerPIN optjson.Bool `json:"windows_require_bitlocker_pin"` // MacOSUpdates defines the OS update settings for macOS devices. MacOSUpdates *AppleOSUpdateSettings `json:"macos_updates"` @@ -193,6 +196,7 @@ type TeamSpecAppStoreApp struct { type TeamMDM struct { EnableDiskEncryption bool `json:"enable_disk_encryption"` + RequireBitLockerPIN bool `json:"windows_require_bitlocker_pin"` MacOSUpdates AppleOSUpdateSettings `json:"macos_updates"` IOSUpdates AppleOSUpdateSettings `json:"ios_updates"` IPadOSUpdates AppleOSUpdateSettings `json:"ipados_updates"` @@ -255,6 +259,9 @@ func (t *TeamMDM) Copy() *TeamMDM { type TeamSpecMDM struct { EnableDiskEncryption optjson.Bool `json:"enable_disk_encryption"` + // RequireBitLockerPIN indicates whether BitLocker PIN is required for Windows devices + // in order for Fleet to consider them compliant. + RequireBitLockerPIN optjson.Bool `json:"windows_require_bitlocker_pin"` // MacOSUpdates defines the OS update settings for macOS devices. MacOSUpdates AppleOSUpdateSettings `json:"macos_updates"` diff --git a/server/service/appconfig_test.go b/server/service/appconfig_test.go index 408b32f75d..17d7146297 100644 --- a/server/service/appconfig_test.go +++ b/server/service/appconfig_test.go @@ -950,6 +950,7 @@ func TestMDMAppleConfig(t *testing.T) { WindowsSettings: fleet.WindowsSettings{ CustomSettings: optjson.Slice[fleet.MDMProfileSpec]{Set: true, Value: []fleet.MDMProfileSpec{}}, }, + RequireBitLockerPIN: optjson.Bool{Set: true, Value: false}, }, }, { name: "newDefaultTeamNoLicense", @@ -991,6 +992,7 @@ func TestMDMAppleConfig(t *testing.T) { WindowsSettings: fleet.WindowsSettings{ CustomSettings: optjson.Slice[fleet.MDMProfileSpec]{Set: true, Value: []fleet.MDMProfileSpec{}}, }, + RequireBitLockerPIN: optjson.Bool{Set: true, Value: false}, }, }, { name: "foundEdit", @@ -1017,6 +1019,7 @@ func TestMDMAppleConfig(t *testing.T) { WindowsSettings: fleet.WindowsSettings{ CustomSettings: optjson.Slice[fleet.MDMProfileSpec]{Set: true, Value: []fleet.MDMProfileSpec{}}, }, + RequireBitLockerPIN: optjson.Bool{Set: true, Value: false}, }, }, { name: "ssoFree", @@ -1049,6 +1052,7 @@ func TestMDMAppleConfig(t *testing.T) { WindowsSettings: fleet.WindowsSettings{ CustomSettings: optjson.Slice[fleet.MDMProfileSpec]{Set: true, Value: []fleet.MDMProfileSpec{}}, }, + RequireBitLockerPIN: optjson.Bool{Set: true, Value: false}, }, }, { name: "ssoAllFields", @@ -1082,6 +1086,7 @@ func TestMDMAppleConfig(t *testing.T) { WindowsSettings: fleet.WindowsSettings{ CustomSettings: optjson.Slice[fleet.MDMProfileSpec]{Set: true, Value: []fleet.MDMProfileSpec{}}, }, + RequireBitLockerPIN: optjson.Bool{Set: true, Value: false}, }, }, { name: "ssoShortEntityID", @@ -1147,6 +1152,7 @@ func TestMDMAppleConfig(t *testing.T) { WindowsSettings: fleet.WindowsSettings{ CustomSettings: optjson.Slice[fleet.MDMProfileSpec]{Set: true, Value: []fleet.MDMProfileSpec{}}, }, + RequireBitLockerPIN: optjson.Bool{Set: true, Value: false}, }, }, } diff --git a/server/service/apple_mdm.go b/server/service/apple_mdm.go index 55888e262f..d2ae43e7d5 100644 --- a/server/service/apple_mdm.go +++ b/server/service/apple_mdm.go @@ -2753,7 +2753,7 @@ func (r updateMDMAppleSettingsResponse) Status() int { return http.StatusNoConte // team endpoints only allow write access to admins. func updateMDMAppleSettingsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) { req := request.(*updateMDMAppleSettingsRequest) - if err := svc.UpdateMDMDiskEncryption(ctx, req.MDMAppleSettingsPayload.TeamID, req.MDMAppleSettingsPayload.EnableDiskEncryption); err != nil { + if err := svc.UpdateMDMDiskEncryption(ctx, req.MDMAppleSettingsPayload.TeamID, req.MDMAppleSettingsPayload.EnableDiskEncryption, nil); err != nil { return updateMDMAppleSettingsResponse{Err: err}, nil } return updateMDMAppleSettingsResponse{}, nil diff --git a/server/service/apple_mdm_test.go b/server/service/apple_mdm_test.go index 601fa0dea4..dac4241321 100644 --- a/server/service/apple_mdm_test.go +++ b/server/service/apple_mdm_test.go @@ -2143,7 +2143,7 @@ func TestUpdateMDMAppleSettings(t *testing.T) { } ctx = license.NewContext(ctx, &fleet.LicenseInfo{Tier: tier}) - err := svc.UpdateMDMDiskEncryption(ctx, tt.teamID, nil) + err := svc.UpdateMDMDiskEncryption(ctx, tt.teamID, nil, nil) if tt.wantErr == "" { require.NoError(t, err) return diff --git a/server/service/client.go b/server/service/client.go index 01ce6503bd..889a7c962e 100644 --- a/server/service/client.go +++ b/server/service/client.go @@ -2008,6 +2008,11 @@ func (c *Client) DoGitOps( } else { mdmAppConfig["enable_disk_encryption"] = false } + if config.Controls.RequireBitLockerPIN != nil { + mdmAppConfig["windows_require_bitlocker_pin"] = config.Controls.RequireBitLockerPIN + } else { + mdmAppConfig["windows_require_bitlocker_pin"] = false + } if config.TeamName != nil { team["gitops_filename"] = filename diff --git a/server/service/mdm.go b/server/service/mdm.go index 918636babc..d8efeede86 100644 --- a/server/service/mdm.go +++ b/server/service/mdm.go @@ -2276,6 +2276,7 @@ func (svc *Service) ListMDMConfigProfiles(ctx context.Context, teamID *uint, opt type updateDiskEncryptionRequest struct { TeamID *uint `json:"team_id"` EnableDiskEncryption bool `json:"enable_disk_encryption"` + RequireBitLockerPIN bool `json:"windows_require_bitlocker_pin"` } type updateMDMDiskEncryptionResponse struct { @@ -2288,13 +2289,13 @@ func (r updateMDMDiskEncryptionResponse) Status() int { return http.StatusNoCont func updateDiskEncryptionEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) { req := request.(*updateDiskEncryptionRequest) - if err := svc.UpdateMDMDiskEncryption(ctx, req.TeamID, &req.EnableDiskEncryption); err != nil { + if err := svc.UpdateMDMDiskEncryption(ctx, req.TeamID, &req.EnableDiskEncryption, &req.RequireBitLockerPIN); err != nil { return updateMDMDiskEncryptionResponse{Err: err}, nil } return updateMDMDiskEncryptionResponse{}, nil } -func (svc *Service) UpdateMDMDiskEncryption(ctx context.Context, teamID *uint, enableDiskEncryption *bool) error { +func (svc *Service) UpdateMDMDiskEncryption(ctx context.Context, teamID *uint, enableDiskEncryption *bool, requireBitLockerPIN *bool) error { // TODO(mna): this should all move to the ee package when we remove the // `PATCH /api/v1/fleet/mdm/apple/settings` endpoint, but for now it's better // leave here so both endpoints can reuse the same logic. @@ -2317,7 +2318,7 @@ func (svc *Service) UpdateMDMDiskEncryption(ctx context.Context, teamID *uint, e if err != nil { return err } - return svc.EnterpriseOverrides.UpdateTeamMDMDiskEncryption(ctx, tm, enableDiskEncryption) + return svc.EnterpriseOverrides.UpdateTeamMDMDiskEncryption(ctx, tm, enableDiskEncryption, requireBitLockerPIN) } return svc.updateAppConfigMDMDiskEncryption(ctx, enableDiskEncryption) } diff --git a/tools/cloner-check/generated_files/appconfig.txt b/tools/cloner-check/generated_files/appconfig.txt index 1a612a3a53..5c15421c1f 100644 --- a/tools/cloner-check/generated_files/appconfig.txt +++ b/tools/cloner-check/generated_files/appconfig.txt @@ -183,6 +183,7 @@ github.com/fleetdm/fleet/v4/server/fleet/MDM EndUserAuthentication fleet.MDMEndU github.com/fleetdm/fleet/v4/server/fleet/MDMEndUserAuthentication SSOProviderSettings fleet.SSOProviderSettings github.com/fleetdm/fleet/v4/server/fleet/MDM WindowsEnabledAndConfigured bool github.com/fleetdm/fleet/v4/server/fleet/MDM EnableDiskEncryption optjson.Bool +github.com/fleetdm/fleet/v4/server/fleet/MDM RequireBitLockerPIN optjson.Bool github.com/fleetdm/fleet/v4/server/fleet/MDM WindowsSettings fleet.WindowsSettings github.com/fleetdm/fleet/v4/server/fleet/WindowsSettings CustomSettings optjson.Slice[github.com/fleetdm/fleet/v4/server/fleet.MDMProfileSpec] github.com/fleetdm/fleet/v4/pkg/optjson/Slice[github.com/fleetdm/fleet/v4/server/fleet.MDMProfileSpec] Set bool diff --git a/tools/cloner-check/generated_files/teammdm.txt b/tools/cloner-check/generated_files/teammdm.txt index 40512898b1..33e68be51a 100644 --- a/tools/cloner-check/generated_files/teammdm.txt +++ b/tools/cloner-check/generated_files/teammdm.txt @@ -1,4 +1,5 @@ github.com/fleetdm/fleet/v4/server/fleet/TeamMDM EnableDiskEncryption bool +github.com/fleetdm/fleet/v4/server/fleet/TeamMDM RequireBitLockerPIN bool github.com/fleetdm/fleet/v4/server/fleet/TeamMDM MacOSUpdates fleet.AppleOSUpdateSettings github.com/fleetdm/fleet/v4/server/fleet/AppleOSUpdateSettings MinimumVersion optjson.String github.com/fleetdm/fleet/v4/pkg/optjson/String Set bool