Experimental fleet server config for custom updates & disk encryption settings (#34598)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #33316 Merges in changes made in this community PR: https://github.com/fleetdm/fleet/pull/33665 Adds support for Windows and tests, also blocks the feature on fleet free # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually --------- Co-authored-by: Wesley Whetstone <wesw@stripe.com> Co-authored-by: Wesley Whetstone <jckwhet@gmail.com>
This commit is contained in:
co-authored by
Wesley Whetstone
Wesley Whetstone
parent
786c0ced44
commit
7593d102fb
@@ -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
|
||||
@@ -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")
|
||||
|
||||
+28
-25
@@ -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"),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(`<Replace><Target><LocURI>Custom/URI</LocURI></Target></Replace>`),
|
||||
},
|
||||
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(`<Replace><Target><LocURI>/Vendor/MSFT/Policy/Config/Update/something</LocURI></Target></Replace>`),
|
||||
},
|
||||
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(`<Replace><Target><LocURI>/Vendor/MSFT/Policy/Config/Update/something</LocURI></Target></Replace>`),
|
||||
},
|
||||
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(`<Replace><Target><LocURI>/Vendor/MSFT/BitLocker/something</LocURI></Target></Replace>`),
|
||||
},
|
||||
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(`<Replace><Target><LocURI>/Vendor/MSFT/BitLocker/something</LocURI></Target></Replace>`),
|
||||
},
|
||||
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 {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
@@ -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.`
|
||||
|
||||
Reference in New Issue
Block a user