diff --git a/changes/33665-custom-os-updates-and-filevault b/changes/33665-custom-os-updates-and-filevault
new file mode 100644
index 0000000000..c52ce4c9c7
--- /dev/null
+++ b/changes/33665-custom-os-updates-and-filevault
@@ -0,0 +1 @@
+* Added experimental FLEET_MDM_ENABLE_CUSTOM_OS_UPDATES_AND_FILEVAULT configuration to allow deploying custom OS settings including Filevault payloads and macOS and Windows update settings
diff --git a/cmd/fleet/serve.go b/cmd/fleet/serve.go
index 17a93adc46..9db37922b9 100644
--- a/cmd/fleet/serve.go
+++ b/cmd/fleet/serve.go
@@ -471,6 +471,11 @@ the way that the Fleet server works.
}
}
+ if config.MDM.EnableCustomOSUpdatesAndFileVault && !license.IsPremium() {
+ config.MDM.EnableCustomOSUpdatesAndFileVault = false
+ level.Warn(logger).Log("msg", "Disabling custom OS updates and FileVault management because Fleet Premium license is not present")
+ }
+
mdmStorage, err := mds.NewMDMAppleMDMStorage()
if err != nil {
initFatal(err, "initialize mdm apple MySQL storage")
diff --git a/server/config/config.go b/server/config/config.go
index f93afa531a..b444e976d4 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -737,7 +737,8 @@ type MDMConfig struct {
microsoftWSTEPCertPEM []byte
microsoftWSTEPKeyPEM []byte
- SSORateLimitPerMinute int `yaml:"sso_rate_limit_per_minute"`
+ SSORateLimitPerMinute int `yaml:"sso_rate_limit_per_minute"`
+ EnableCustomOSUpdatesAndFileVault bool `yaml:"enable_custom_os_updates_and_filevault"`
}
type CalendarConfig struct {
@@ -1473,6 +1474,7 @@ func (man Manager) addConfigs() {
man.addConfigString("mdm.windows_wstep_identity_cert_bytes", "", "Microsoft WSTEP PEM-encoded certificate bytes")
man.addConfigString("mdm.windows_wstep_identity_key_bytes", "", "Microsoft WSTEP PEM-encoded private key bytes")
man.addConfigInt("mdm.sso_rate_limit_per_minute", 0, "Number of allowed requests per minute to MDM SSO endpoints (default is sharing login rate limit bucket)")
+ man.addConfigBool("mdm.enable_custom_os_updates_and_filevault", false, "Experimental feature: allows usage of specific Apple MDM profiles for OS updates and FileVault")
// Calendar integration
man.addConfigDuration(
@@ -1741,30 +1743,31 @@ func (man Manager) LoadConfig() FleetConfig {
},
},
MDM: MDMConfig{
- AppleAPNsCert: man.getConfigString("mdm.apple_apns_cert"),
- AppleAPNsCertBytes: man.getConfigString("mdm.apple_apns_cert_bytes"),
- AppleAPNsKey: man.getConfigString("mdm.apple_apns_key"),
- AppleAPNsKeyBytes: man.getConfigString("mdm.apple_apns_key_bytes"),
- AppleSCEPCert: man.getConfigString("mdm.apple_scep_cert"),
- AppleSCEPCertBytes: man.getConfigString("mdm.apple_scep_cert_bytes"),
- AppleSCEPKey: man.getConfigString("mdm.apple_scep_key"),
- AppleSCEPKeyBytes: man.getConfigString("mdm.apple_scep_key_bytes"),
- AppleBMServerToken: man.getConfigString("mdm.apple_bm_server_token"),
- AppleBMServerTokenBytes: man.getConfigString("mdm.apple_bm_server_token_bytes"),
- AppleBMCert: man.getConfigString("mdm.apple_bm_cert"),
- AppleBMCertBytes: man.getConfigString("mdm.apple_bm_cert_bytes"),
- AppleBMKey: man.getConfigString("mdm.apple_bm_key"),
- AppleBMKeyBytes: man.getConfigString("mdm.apple_bm_key_bytes"),
- AppleEnable: man.getConfigBool("mdm.apple_enable"),
- AppleSCEPSignerValidityDays: man.getConfigInt("mdm.apple_scep_signer_validity_days"),
- AppleSCEPSignerAllowRenewalDays: man.getConfigInt("mdm.apple_scep_signer_allow_renewal_days"),
- AppleSCEPChallenge: man.getConfigString("mdm.apple_scep_challenge"),
- AppleDEPSyncPeriodicity: man.getConfigDuration("mdm.apple_dep_sync_periodicity"),
- WindowsWSTEPIdentityCert: man.getConfigString("mdm.windows_wstep_identity_cert"),
- WindowsWSTEPIdentityKey: man.getConfigString("mdm.windows_wstep_identity_key"),
- WindowsWSTEPIdentityCertBytes: man.getConfigString("mdm.windows_wstep_identity_cert_bytes"),
- WindowsWSTEPIdentityKeyBytes: man.getConfigString("mdm.windows_wstep_identity_key_bytes"),
- SSORateLimitPerMinute: man.getConfigInt("mdm.sso_rate_limit_per_minute"),
+ AppleAPNsCert: man.getConfigString("mdm.apple_apns_cert"),
+ AppleAPNsCertBytes: man.getConfigString("mdm.apple_apns_cert_bytes"),
+ AppleAPNsKey: man.getConfigString("mdm.apple_apns_key"),
+ AppleAPNsKeyBytes: man.getConfigString("mdm.apple_apns_key_bytes"),
+ AppleSCEPCert: man.getConfigString("mdm.apple_scep_cert"),
+ AppleSCEPCertBytes: man.getConfigString("mdm.apple_scep_cert_bytes"),
+ AppleSCEPKey: man.getConfigString("mdm.apple_scep_key"),
+ AppleSCEPKeyBytes: man.getConfigString("mdm.apple_scep_key_bytes"),
+ AppleBMServerToken: man.getConfigString("mdm.apple_bm_server_token"),
+ AppleBMServerTokenBytes: man.getConfigString("mdm.apple_bm_server_token_bytes"),
+ AppleBMCert: man.getConfigString("mdm.apple_bm_cert"),
+ AppleBMCertBytes: man.getConfigString("mdm.apple_bm_cert_bytes"),
+ AppleBMKey: man.getConfigString("mdm.apple_bm_key"),
+ AppleBMKeyBytes: man.getConfigString("mdm.apple_bm_key_bytes"),
+ AppleEnable: man.getConfigBool("mdm.apple_enable"),
+ AppleSCEPSignerValidityDays: man.getConfigInt("mdm.apple_scep_signer_validity_days"),
+ AppleSCEPSignerAllowRenewalDays: man.getConfigInt("mdm.apple_scep_signer_allow_renewal_days"),
+ AppleSCEPChallenge: man.getConfigString("mdm.apple_scep_challenge"),
+ AppleDEPSyncPeriodicity: man.getConfigDuration("mdm.apple_dep_sync_periodicity"),
+ WindowsWSTEPIdentityCert: man.getConfigString("mdm.windows_wstep_identity_cert"),
+ WindowsWSTEPIdentityKey: man.getConfigString("mdm.windows_wstep_identity_key"),
+ WindowsWSTEPIdentityCertBytes: man.getConfigString("mdm.windows_wstep_identity_cert_bytes"),
+ WindowsWSTEPIdentityKeyBytes: man.getConfigString("mdm.windows_wstep_identity_key_bytes"),
+ SSORateLimitPerMinute: man.getConfigInt("mdm.sso_rate_limit_per_minute"),
+ EnableCustomOSUpdatesAndFileVault: man.getConfigBool("mdm.enable_custom_os_updates_and_filevault"),
},
Calendar: CalendarConfig{
Periodicity: man.getConfigDuration("calendar.periodicity"),
diff --git a/server/fleet/apple_mdm.go b/server/fleet/apple_mdm.go
index 437e5027b1..f23f299642 100644
--- a/server/fleet/apple_mdm.go
+++ b/server/fleet/apple_mdm.go
@@ -281,7 +281,7 @@ func ValidateNoSecretsInProfileName(xmlContent []byte) error {
return nil
}
-func (cp MDMAppleConfigProfile) ValidateUserProvided() error {
+func (cp MDMAppleConfigProfile) ValidateUserProvided(allowCustomOSUpdatesAndFileVault bool) error {
// first screen the top-level object for reserved identifiers and names
if _, ok := mobileconfig.FleetPayloadIdentifiers()[cp.Identifier]; ok {
return fmt.Errorf("payload identifier %s is not allowed", cp.Identifier)
@@ -292,7 +292,7 @@ func (cp MDMAppleConfigProfile) ValidateUserProvided() error {
}
// then screen the payload content for reserved identifiers, names, and types
- return cp.Mobileconfig.ScreenPayloads()
+ return cp.Mobileconfig.ScreenPayloads(allowCustomOSUpdatesAndFileVault)
}
// HostMDMAppleProfile represents the status of an Apple MDM profile in a host.
@@ -715,12 +715,14 @@ var ForbiddenDeclTypes = map[string]struct{}{
"com.apple.configuration.watch.enrollment": {},
}
-func (r *MDMAppleRawDeclaration) ValidateUserProvided() error {
+func (r *MDMAppleRawDeclaration) ValidateUserProvided(allowCustomOSUpdatesAndFileVault bool) error {
var err error
// Check against types we don't allow
if r.Type == `com.apple.configuration.softwareupdate.enforcement.specific` {
- return NewInvalidArgumentError(r.Type, "Declaration profile can’t include OS updates settings. To control these settings, go to OS updates.")
+ if !allowCustomOSUpdatesAndFileVault {
+ return NewInvalidArgumentError(r.Type, "Declaration profile can’t include OS updates settings. To control these settings, go to OS updates.")
+ }
}
if _, forbidden := ForbiddenDeclTypes[r.Type]; forbidden {
diff --git a/server/fleet/apple_mdm_test.go b/server/fleet/apple_mdm_test.go
index ac0be40bbe..40fbed8aad 100644
--- a/server/fleet/apple_mdm_test.go
+++ b/server/fleet/apple_mdm_test.go
@@ -156,7 +156,8 @@ func TestMDMAppleConfigProfileScreenPayloadContent(t *testing.T) {
require.Equal(t, "ValidName", parsed.Name)
require.Equal(t, "ValidIdentifier", parsed.Identifier)
- err = parsed.ValidateUserProvided()
+ // Test with allowCustomOSUpdatesAndFileVault = false (default behavior)
+ err = parsed.ValidateUserProvided(false)
for _, pt := range c.shouldFail {
require.Error(t, err)
require.ErrorContains(t, err, pt)
@@ -168,6 +169,83 @@ func TestMDMAppleConfigProfileScreenPayloadContent(t *testing.T) {
}
}
+func TestMDMAppleConfigProfileAllowCustomOSUpdatesAndFileVault(t *testing.T) {
+ cases := []struct {
+ testName string
+ payloadTypes []string
+ }{
+ {
+ testName: "FileVault2Allowed",
+ payloadTypes: []string{"com.apple.MCX.FileVault2"},
+ },
+ {
+ testName: "FDERecoveryKeyEscrowAllowed",
+ payloadTypes: []string{"com.apple.security.FDERecoveryKeyEscrow"},
+ },
+ {
+ testName: "AllFileVaultTypesAllowed",
+ payloadTypes: []string{"com.apple.security.FDERecoveryKeyEscrow", "com.apple.MCX.FileVault2"},
+ },
+ {
+ testName: "FileVaultMixedWithOtherPayloadTypes",
+ payloadTypes: []string{"com.apple.MCX.FileVault2", "com.apple.security.firewall", "com.apple.security.FDERecoveryKeyEscrow"},
+ },
+ }
+
+ for _, c := range cases {
+ t.Run(c.testName, func(t *testing.T) {
+ mc := MobileconfigForTest("ValidName", "ValidIdentifier", uuid.NewString(), mcPayloadContentForTest(c.payloadTypes))
+ parsed, err := NewMDMAppleConfigProfile(mc, nil)
+ require.NoError(t, err)
+ require.Equal(t, "ValidName", parsed.Name)
+ require.Equal(t, "ValidIdentifier", parsed.Identifier)
+
+ // When allowCustomOSUpdatesAndFileVault = true, these profiles should be allowed
+ err = parsed.ValidateUserProvided(true)
+ require.NoError(t, err)
+ })
+ }
+}
+
+func TestMDMAppleDeclarationAllowCustomOSUpdatesAndFileVault(t *testing.T) {
+ t.Run("OSUpdateDeclarationBlockedByDefault", func(t *testing.T) {
+ decl := &MDMAppleRawDeclaration{
+ Type: "com.apple.configuration.softwareupdate.enforcement.specific",
+ Identifier: "test-os-update",
+ }
+
+ // Should fail when allowCustomOSUpdatesAndFileVault = false
+ err := decl.ValidateUserProvided(false)
+ require.Error(t, err)
+ require.ErrorContains(t, err, "Declaration profile can’t include OS updates settings")
+ })
+
+ t.Run("OSUpdateDeclarationAllowedWhenFlagEnabled", func(t *testing.T) {
+ decl := &MDMAppleRawDeclaration{
+ Type: "com.apple.configuration.softwareupdate.enforcement.specific",
+ Identifier: "test-os-update",
+ }
+
+ // Should succeed when allowCustomOSUpdatesAndFileVault = true
+ err := decl.ValidateUserProvided(true)
+ require.NoError(t, err)
+ })
+
+ t.Run("OtherDeclarationsUnaffected", func(t *testing.T) {
+ decl := &MDMAppleRawDeclaration{
+ Type: "com.apple.configuration.passcode.settings",
+ Identifier: "test-passcode",
+ }
+
+ // Should succeed regardless of flag
+ err := decl.ValidateUserProvided(false)
+ require.NoError(t, err)
+
+ err = decl.ValidateUserProvided(true)
+ require.NoError(t, err)
+ })
+}
+
func TestMDMAppleConfigProfileScreenPayloadIdentifiers(t *testing.T) {
cases := []struct {
testName string
@@ -214,7 +292,7 @@ func TestMDMAppleConfigProfileScreenPayloadIdentifiers(t *testing.T) {
require.Equal(t, "ValidName", parsed.Name)
require.Equal(t, "ValidIdentifier", parsed.Identifier)
- err = parsed.ValidateUserProvided()
+ err = parsed.ValidateUserProvided(false)
for _, pt := range c.shouldFail {
require.Error(t, err)
require.ErrorContains(t, err, pt)
@@ -260,7 +338,7 @@ func TestMDMAppleConfigProfileScreenReservedNames(t *testing.T) {
require.Equal(t, c.toplevelName, parsed.Name)
require.Equal(t, "ValidIdentifier", parsed.Identifier)
- err = parsed.ValidateUserProvided()
+ err = parsed.ValidateUserProvided(false)
if c.shouldFail {
require.Error(t, err)
if c.toplevelName == "unreserved name" {
diff --git a/server/fleet/windows_mdm.go b/server/fleet/windows_mdm.go
index d28dd50822..9061c436a2 100644
--- a/server/fleet/windows_mdm.go
+++ b/server/fleet/windows_mdm.go
@@ -59,7 +59,7 @@ type MDMWindowsConfigProfile struct {
//
// [1]: http://www.w3.org/TR/2006/REC-xml-20060816
// [2]: https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-MDM/%5bMS-MDM%5d.pdf
-func (m *MDMWindowsConfigProfile) ValidateUserProvided() error {
+func (m *MDMWindowsConfigProfile) ValidateUserProvided(enableCustomOSUpdates bool) error {
if len(bytes.TrimSpace(m.SyncML)) == 0 {
return errors.New("The file should include valid XML.")
}
@@ -137,7 +137,7 @@ func (m *MDMWindowsConfigProfile) ValidateUserProvided() error {
case xml.CharData:
if inLocURI {
- if err := validateFleetProvidedLocURI(string(t)); err != nil {
+ if err := validateFleetProvidedLocURI(string(t), enableCustomOSUpdates); err != nil {
return err
}
}
@@ -152,10 +152,13 @@ var fleetProvidedLocURIValidationMap = map[string][]string{
syncml.FleetOSUpdateTargetLocURI: {"Windows updates", "mdm.windows_updates"},
}
-func validateFleetProvidedLocURI(locURI string) error {
+func validateFleetProvidedLocURI(locURI string, enableCustomOSUpdates bool) error {
sanitizedLocURI := strings.TrimSpace(locURI)
for fleetLocURI, errHints := range fleetProvidedLocURIValidationMap {
if strings.Contains(sanitizedLocURI, fleetLocURI) {
+ if fleetLocURI == syncml.FleetOSUpdateTargetLocURI && enableCustomOSUpdates {
+ continue
+ }
if fleetLocURI == syncml.FleetBitLockerTargetLocURI {
return errors.New(syncml.DiskEncryptionProfileRestrictionErrMsg)
}
diff --git a/server/fleet/windows_mdm_test.go b/server/fleet/windows_mdm_test.go
index d756391f7e..694e690d08 100644
--- a/server/fleet/windows_mdm_test.go
+++ b/server/fleet/windows_mdm_test.go
@@ -10,9 +10,10 @@ import (
func TestValidateUserProvided(t *testing.T) {
tests := []struct {
- name string
- profile MDMWindowsConfigProfile
- wantErr string
+ name string
+ profile MDMWindowsConfigProfile
+ allowCustomOSUpdates bool
+ wantErr string
}{
{
name: "Valid XML with Replace",
@@ -407,6 +408,51 @@ func TestValidateUserProvided(t *testing.T) {
},
wantErr: `Profile name "Windows OS Updates" is not allowed`,
},
+ {
+ name: "Valid XML with reserved name but experimental allow custom OS updates flag enabled is still not allowed",
+ profile: MDMWindowsConfigProfile{
+ Name: mdm.FleetWindowsOSUpdatesProfileName,
+ SyncML: []byte(`Custom/URI`),
+ },
+ allowCustomOSUpdates: true,
+ wantErr: `Profile name "Windows OS Updates" is not allowed`,
+ },
+ {
+ name: "Valid XML with Windows Update LocURI without experimental allow custom OS updates flag enabled is blocked",
+ profile: MDMWindowsConfigProfile{
+ Name: "FleetieUpdater",
+ SyncML: []byte(`/Vendor/MSFT/Policy/Config/Update/something`),
+ },
+ allowCustomOSUpdates: false,
+ wantErr: "Custom configuration profiles can't include Windows updates settings. To control these settings, use the mdm.windows_updates option.",
+ },
+ {
+ name: "Valid XML with Windows Update LocURI but experimental allow custom OS updates flag enabled is allowed",
+ profile: MDMWindowsConfigProfile{
+ Name: "FleetieUpdater",
+ SyncML: []byte(`/Vendor/MSFT/Policy/Config/Update/something`),
+ },
+ allowCustomOSUpdates: true,
+ wantErr: "",
+ },
+ {
+ name: "Valid XML with Bitlocker LocURI without experimental allow custom OS updates flag enabled is blocked",
+ profile: MDMWindowsConfigProfile{
+ Name: "FleetieUpdater",
+ SyncML: []byte(`/Vendor/MSFT/BitLocker/something`),
+ },
+ allowCustomOSUpdates: false,
+ wantErr: "Couldn't add. The configuration profile can't include BitLocker settings.",
+ },
+ {
+ name: "Valid XML with Bitlocker LocURI without experimental allow custom OS updates flag enabled is blocked",
+ profile: MDMWindowsConfigProfile{
+ Name: "FleetieUpdater",
+ SyncML: []byte(`/Vendor/MSFT/BitLocker/something`),
+ },
+ allowCustomOSUpdates: true,
+ wantErr: "Couldn't add. The configuration profile can't include BitLocker settings.",
+ },
{
name: "XML with top level comment",
profile: MDMWindowsConfigProfile{
@@ -554,7 +600,7 @@ func TestValidateUserProvided(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- err := tt.profile.ValidateUserProvided()
+ err := tt.profile.ValidateUserProvided(tt.allowCustomOSUpdates)
if tt.wantErr != "" {
require.ErrorContains(t, err, tt.wantErr)
} else {
diff --git a/server/mdm/apple/mobileconfig/mobileconfig.go b/server/mdm/apple/mobileconfig/mobileconfig.go
index 0dd88d48b3..73619c1826 100644
--- a/server/mdm/apple/mobileconfig/mobileconfig.go
+++ b/server/mdm/apple/mobileconfig/mobileconfig.go
@@ -208,7 +208,7 @@ func (mc Mobileconfig) payloadSummary() ([]payloadSummary, error) {
return result, nil
}
-func (mc *Mobileconfig) ScreenPayloads() error {
+func (mc *Mobileconfig) ScreenPayloads(allowCustomOSUpdatesAndFileVault bool) error {
pct, err := mc.payloadSummary()
if err != nil {
// don't error if there's nothing for us to screen.
@@ -240,13 +240,15 @@ func (mc *Mobileconfig) ScreenPayloads() error {
for _, t := range screenedTypes {
switch t {
case FleetFileVaultPayloadType, FleetRecoveryKeyEscrowPayloadType:
- return errors.New(DiskEncryptionProfileRestrictionErrMsg)
+ if !allowCustomOSUpdatesAndFileVault {
+ return errors.New(DiskEncryptionProfileRestrictionErrMsg)
+ }
case FleetCustomSettingsPayloadType:
contains, err := ContainsFDEFileVaultOptionsPayload(*mc)
if err != nil {
return fmt.Errorf("checking for FDEVileVaultOptions payload: %w", err)
}
- if contains {
+ if contains && !allowCustomOSUpdatesAndFileVault {
return errors.New(DiskEncryptionProfileRestrictionErrMsg)
}
default:
diff --git a/server/mdm/apple/profile_matcher.go b/server/mdm/apple/profile_matcher.go
index 4092edc9a4..c91eee477d 100644
--- a/server/mdm/apple/profile_matcher.go
+++ b/server/mdm/apple/profile_matcher.go
@@ -54,7 +54,7 @@ func (p *profileMatcher) PreassignProfile(ctx context.Context, payload fleet.MDM
// team ID is not relevant at this stage, this is just for validation
if cp, err := fleet.NewMDMAppleConfigProfile(payload.Profile, nil); err != nil {
invArg.Append("profile", err.Error())
- } else if err := cp.ValidateUserProvided(); err != nil {
+ } else if err := cp.ValidateUserProvided(false); err != nil {
invArg.Append("profile", err.Error())
}
}
diff --git a/server/service/apple_mdm.go b/server/service/apple_mdm.go
index 5b8b41b5ae..0f9ca22fd4 100644
--- a/server/service/apple_mdm.go
+++ b/server/service/apple_mdm.go
@@ -428,7 +428,7 @@ func (svc *Service) NewMDMAppleConfigProfile(ctx context.Context, teamID uint, d
})
}
- if err := cp.ValidateUserProvided(); err != nil {
+ if err := cp.ValidateUserProvided(svc.config.MDM.EnableCustomOSUpdatesAndFileVault); err != nil {
if strings.Contains(err.Error(), mobileconfig.DiskEncryptionProfileRestrictionErrMsg) {
return nil, ctxerr.Wrap(ctx, &fleet.BadRequestError{Message: err.Error() + ` To control these settings use disk encryption endpoint.`})
}
@@ -1052,7 +1052,7 @@ func (svc *Service) NewMDMAppleDeclaration(ctx context.Context, teamID uint, dat
}
// After validation, we should no longer need to keep the expanded secrets.
- if err := rawDecl.ValidateUserProvided(); err != nil {
+ if err := rawDecl.ValidateUserProvided(svc.config.MDM.EnableCustomOSUpdatesAndFileVault); err != nil {
return nil, err
}
@@ -1443,7 +1443,7 @@ func (svc *Service) DeleteMDMAppleDeclaration(ctx context.Context, declUUID stri
if err := json.Unmarshal(decl.RawJSON, &d); err != nil {
return ctxerr.Wrap(ctx, err, "unmarshalling declaration")
}
- if err := d.ValidateUserProvided(); err != nil {
+ if err := d.ValidateUserProvided(svc.config.MDM.EnableCustomOSUpdatesAndFileVault); err != nil {
return ctxerr.Wrap(ctx, &fleet.BadRequestError{Message: err.Error()})
}
}
@@ -2745,7 +2745,7 @@ func (svc *Service) BatchSetMDMAppleProfiles(ctx context.Context, tmID *uint, tm
"invalid mobileconfig profile")
}
- if err := mdmProf.ValidateUserProvided(); err != nil {
+ if err := mdmProf.ValidateUserProvided(svc.config.MDM.EnableCustomOSUpdatesAndFileVault); err != nil {
return ctxerr.Wrap(ctx,
fleet.NewInvalidArgumentError(fmt.Sprintf("profiles[%d]", i), err.Error()))
}
diff --git a/server/service/mdm.go b/server/service/mdm.go
index 52f9943035..ee00d096c3 100644
--- a/server/service/mdm.go
+++ b/server/service/mdm.go
@@ -1709,7 +1709,7 @@ func (svc *Service) NewMDMWindowsConfigProfile(ctx context.Context, teamID uint,
Name: profileName,
SyncML: data,
}
- if err := cp.ValidateUserProvided(); err != nil {
+ if err := cp.ValidateUserProvided(svc.config.MDM.EnableCustomOSUpdatesAndFileVault); err != nil {
msg := err.Error()
if strings.Contains(msg, syncml.DiskEncryptionProfileRestrictionErrMsg) {
return nil, ctxerr.Wrap(ctx,
@@ -2044,12 +2044,12 @@ func (svc *Service) BatchSetMDMProfiles(
return ctxerr.Wrap(ctx, err, "validating profiles")
}
- appleProfiles, appleDecls, err := getAppleProfiles(ctx, tmID, appCfg, profilesWithSecrets, labelMap)
+ appleProfiles, appleDecls, err := getAppleProfiles(ctx, tmID, appCfg, profilesWithSecrets, labelMap, svc.config.MDM.EnableCustomOSUpdatesAndFileVault)
if err != nil {
return ctxerr.Wrap(ctx, err, "validating macOS profiles")
}
- windowsProfiles, err := getWindowsProfiles(ctx, tmID, appCfg, profilesWithSecrets, labelMap)
+ windowsProfiles, err := getWindowsProfiles(ctx, tmID, appCfg, profilesWithSecrets, labelMap, svc.config.MDM.EnableCustomOSUpdatesAndFileVault)
if err != nil {
return ctxerr.Wrap(ctx, err, "validating Windows profiles")
}
@@ -2330,6 +2330,7 @@ func getAppleProfiles(
appCfg *fleet.AppConfig,
profiles map[int]fleet.MDMProfileBatchPayload,
labelMap map[string]fleet.ConfigurationProfileLabel,
+ allowCustomOSUpdatesAndFileVault bool,
) (map[int]*fleet.MDMAppleConfigProfile, map[int]*fleet.MDMAppleDeclaration, error) {
// any duplicate identifier or name in the provided set results in an error
profs := make(map[int]*fleet.MDMAppleConfigProfile, len(profiles))
@@ -2350,7 +2351,7 @@ func getAppleProfiles(
return nil, nil, err
}
- if err := rawDecl.ValidateUserProvided(); err != nil {
+ if err := rawDecl.ValidateUserProvided(allowCustomOSUpdatesAndFileVault); err != nil {
return nil, nil, err
}
@@ -2448,7 +2449,7 @@ func getAppleProfiles(
}
}
- if err := mdmProf.ValidateUserProvided(); err != nil {
+ if err := mdmProf.ValidateUserProvided(allowCustomOSUpdatesAndFileVault); err != nil {
var iae *fleet.InvalidArgumentError
if strings.Contains(err.Error(), mobileconfig.DiskEncryptionProfileRestrictionErrMsg) {
iae = fleet.NewInvalidArgumentError(prof.Name,
@@ -2505,6 +2506,7 @@ func getWindowsProfiles(
appCfg *fleet.AppConfig,
profiles map[int]fleet.MDMProfileBatchPayload,
labelMap map[string]fleet.ConfigurationProfileLabel,
+ enableCustomOSUpdatesAndFileVault bool,
) (map[int]*fleet.MDMWindowsConfigProfile, error) {
profs := make(map[int]*fleet.MDMWindowsConfigProfile, len(profiles))
@@ -2548,7 +2550,7 @@ func getWindowsProfiles(
}
}
- if err := mdmProf.ValidateUserProvided(); err != nil {
+ if err := mdmProf.ValidateUserProvided(enableCustomOSUpdatesAndFileVault); err != nil {
msg := err.Error()
if strings.Contains(msg, syncml.DiskEncryptionProfileRestrictionErrMsg) {
msg += ` To control disk encryption use config API endpoint or add "enable_disk_encryption" to your YAML file.`