diff --git a/changes/24862-disk-encryption-error-messages b/changes/24862-disk-encryption-error-messages
new file mode 100644
index 0000000000..bbfd51a443
--- /dev/null
+++ b/changes/24862-disk-encryption-error-messages
@@ -0,0 +1 @@
+Improved error messages when Fleet admin tries to upload a FileVault(macOS) or a BitLocker(Windows) configuration profile.
diff --git a/ee/server/service/mdm_profiles.go b/ee/server/service/mdm_profiles.go
index fa9e0b23cb..13a11df02f 100644
--- a/ee/server/service/mdm_profiles.go
+++ b/ee/server/service/mdm_profiles.go
@@ -1,6 +1,10 @@
package service
-import "text/template"
+import (
+ "text/template"
+
+ "github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
+)
type fileVaultProfileOptions struct {
PayloadIdentifier string
@@ -22,9 +26,9 @@ var fileVaultProfileTemplate = template.Must(template.New("").Option("missingkey
PayloadDisplayName
FileVault 2
PayloadIdentifier
- com.apple.MCX.FileVault2.3548D750-6357-4910-8DEA-D80ADCE2C787
+ ` + mobileconfig.FleetFileVaultPayloadType + `.3548D750-6357-4910-8DEA-D80ADCE2C787
PayloadType
- com.apple.MCX.FileVault2
+ ` + mobileconfig.FleetFileVaultPayloadType + `
PayloadUUID
3548D750-6357-4910-8DEA-D80ADCE2C787
PayloadVersion
@@ -44,9 +48,9 @@ var fileVaultProfileTemplate = template.Must(template.New("").Option("missingkey
PayloadDisplayName
FileVault Recovery Key Escrow
PayloadIdentifier
- com.apple.security.FDERecoveryKeyEscrow.3690D771-DCB8-4D5D-97D6-209A138DF03E
+ ` + mobileconfig.FleetRecoveryKeyEscrowPayloadType + `.3690D771-DCB8-4D5D-97D6-209A138DF03E
PayloadType
- com.apple.security.FDERecoveryKeyEscrow
+ ` + mobileconfig.FleetRecoveryKeyEscrowPayloadType + `
PayloadUUID
3C329F2B-3D47-4141-A2B5-5C52A2FD74F8
PayloadVersion
@@ -72,9 +76,9 @@ var fileVaultProfileTemplate = template.Must(template.New("").Option("missingkey
dontAllowFDEDisable
PayloadIdentifier
- com.apple.MCX.62024f29-105E-497A-A724-1D5BA4D9E854
+ ` + mobileconfig.FleetFileVaultOptionsPayloadType + `.62024f29-105E-497A-A724-1D5BA4D9E854
PayloadType
- com.apple.MCX
+ ` + mobileconfig.FleetFileVaultOptionsPayloadType + `
PayloadUUID
62024f29-105E-497A-A724-1D5BA4D9E854
PayloadVersion
diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx
index 6c849605a7..d938d033e0 100644
--- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx
+++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx
@@ -51,7 +51,23 @@ export const getErrorMessage = (err: AxiosResponse) => {
) {
return (
- {apiReason} To control these settings, go to Disk encryption.
+ Couldn't add. The configuration profile can't include
+ BitLocker settings. To control these settings, go to{" "}
+ Disk encryption.
+
+ );
+ }
+
+ if (
+ apiReason.includes(
+ "The configuration profile can't include FileVault settings."
+ )
+ ) {
+ return (
+
+ Couldn't add. The configuration profile can't include
+ FileVault settings. To control these settings, go to{" "}
+ Disk encryption.
);
}
diff --git a/server/fleet/apple_mdm_test.go b/server/fleet/apple_mdm_test.go
index 16155052db..56711b892d 100644
--- a/server/fleet/apple_mdm_test.go
+++ b/server/fleet/apple_mdm_test.go
@@ -114,17 +114,17 @@ func TestMDMAppleConfigProfileScreenPayloadContent(t *testing.T) {
{
testName: "AllFileVaultScreened",
payloadTypes: []string{"com.apple.security.FDERecoveryKeyEscrow", "com.apple.MCX.FileVault2", "com.apple.security.FDERecoveryRedirect"},
- shouldFail: []string{"com.apple.security.FDERecoveryKeyEscrow", "com.apple.MCX.FileVault2", "com.apple.security.FDERecoveryRedirect"},
+ shouldFail: []string{"The configuration profile can't include FileVault settings."},
},
{
testName: "FileVault2Screened",
payloadTypes: []string{"com.apple.MCX.FileVault2"},
- shouldFail: []string{"com.apple.MCX.FileVault2"},
+ shouldFail: []string{"The configuration profile can't include FileVault settings."},
},
{
testName: "FDERecoveryKeyEscrowScreened",
payloadTypes: []string{"com.apple.security.FDERecoveryKeyEscrow"},
- shouldFail: []string{"com.apple.security.FDERecoveryKeyEscrow"},
+ shouldFail: []string{"The configuration profile can't include FileVault settings."},
},
{
testName: "FDERecoveryRedirectScreened",
@@ -139,7 +139,7 @@ func TestMDMAppleConfigProfileScreenPayloadContent(t *testing.T) {
{
testName: "FileVaultMixedWithOtherPayloadTypes",
payloadTypes: []string{"com.apple.MCX.FileVault2", "com.apple.security.firewall", "com.apple.security.FDERecoveryKeyEscrow", "com.apple.MCX"},
- shouldFail: []string{"com.apple.MCX.FileVault2", "com.apple.security.FDERecoveryKeyEscrow"},
+ shouldFail: []string{"The configuration profile can't include FileVault settings."},
},
{
testName: "NoPayloadContent",
diff --git a/server/fleet/windows_mdm.go b/server/fleet/windows_mdm.go
index c06e18e1fe..9e079cd09f 100644
--- a/server/fleet/windows_mdm.go
+++ b/server/fleet/windows_mdm.go
@@ -146,8 +146,8 @@ func (m *MDMWindowsConfigProfile) ValidateUserProvided() error {
return nil
}
-var fleetProvidedLocURIValidationMap = map[string][2]string{
- syncml.FleetBitLockerTargetLocURI: {"BitLocker", "mdm.enable_disk_encryption"},
+var fleetProvidedLocURIValidationMap = map[string][]string{
+ syncml.FleetBitLockerTargetLocURI: nil,
syncml.FleetOSUpdateTargetLocURI: {"Windows updates", "mdm.windows_updates"},
}
@@ -155,7 +155,14 @@ func validateFleetProvidedLocURI(locURI string) error {
sanitizedLocURI := strings.TrimSpace(locURI)
for fleetLocURI, errHints := range fleetProvidedLocURIValidationMap {
if strings.Contains(sanitizedLocURI, fleetLocURI) {
- return fmt.Errorf("Custom configuration profiles can't include %s settings. To control these settings, use the %s option.", errHints[0], errHints[1])
+ if fleetLocURI == syncml.FleetBitLockerTargetLocURI {
+ return errors.New("The configuration profile can't include BitLocker settings. To control these settings use disk encryption endpoint.")
+ }
+ if len(errHints) == 2 {
+ return fmt.Errorf("Custom configuration profiles can't include %s settings. To control these settings, use the %s option.",
+ errHints[0], errHints[1])
+ }
+ return fmt.Errorf("Custom configuration profiles can't include these settings. %q", errHints)
}
}
diff --git a/server/fleet/windows_mdm_test.go b/server/fleet/windows_mdm_test.go
index 93f56f8b0a..d8fae918dc 100644
--- a/server/fleet/windows_mdm_test.go
+++ b/server/fleet/windows_mdm_test.go
@@ -65,7 +65,7 @@ func TestValidateUserProvided(t *testing.T) {
`),
},
- wantErr: "Custom configuration profiles can't include BitLocker settings.",
+ wantErr: "The configuration profile can't include BitLocker settings.",
},
{
name: "Reserved LocURI with implicit ./Device prefix",
@@ -78,7 +78,7 @@ func TestValidateUserProvided(t *testing.T) {
`),
},
- wantErr: "Custom configuration profiles can't include BitLocker settings.",
+ wantErr: "The configuration profile can't include BitLocker settings.",
},
{
name: "XML with Multiple Replace Elements",
@@ -121,7 +121,7 @@ func TestValidateUserProvided(t *testing.T) {
`),
},
- wantErr: "Custom configuration profiles can't include BitLocker settings",
+ wantErr: "The configuration profile can't include BitLocker settings.",
},
{
name: "XML with Mixed Replace and Add",
diff --git a/server/mdm/apple/mobileconfig/mobileconfig.go b/server/mdm/apple/mobileconfig/mobileconfig.go
index feb718a5fe..21e1e57baf 100644
--- a/server/mdm/apple/mobileconfig/mobileconfig.go
+++ b/server/mdm/apple/mobileconfig/mobileconfig.go
@@ -18,7 +18,10 @@ import (
const (
// FleetFileVaultPayloadIdentifier is the value for the PayloadIdentifier
// used by Fleet to configure FileVault and FileVault Escrow.
- FleetFileVaultPayloadIdentifier = "com.fleetdm.fleet.mdm.filevault"
+ FleetFileVaultPayloadIdentifier = "com.fleetdm.fleet.mdm.filevault"
+ FleetFileVaultPayloadType = "com.apple.MCX.FileVault2"
+ FleetFileVaultOptionsPayloadType = "com.apple.MCX"
+ FleetRecoveryKeyEscrowPayloadType = "com.apple.security.FDERecoveryKeyEscrow"
// FleetdConfigPayloadIdentifier is the value for the PayloadIdentifier used
// by fleetd to read configuration values from the system.
@@ -58,15 +61,12 @@ func FleetPayloadIdentifiers() map[string]struct{} {
// FleetPayloadTypes returns a map of PayloadType strings
// that are handled and delivered by Fleet.
-//
-// TODO(roperzh): when I was refactoring this, I noticed that the strings are
-// not constants, we should refactor that and use the constant in the templates
-// we use to generate the FileVault mobileconfig.
func FleetPayloadTypes() map[string]struct{} {
return map[string]struct{}{
- "com.apple.security.FDERecoveryKeyEscrow": {},
- "com.apple.MCX.FileVault2": {},
- "com.apple.security.FDERecoveryRedirect": {},
+ FleetRecoveryKeyEscrowPayloadType: {},
+ FleetFileVaultPayloadType: {},
+ FleetFileVaultOptionsPayloadType: {},
+ "com.apple.security.FDERecoveryRedirect": {}, // no longer supported in macOS 10.13 and later
}
}
@@ -249,6 +249,13 @@ func (mc *Mobileconfig) ScreenPayloads() error {
}
if len(screenedTypes) > 0 {
+ for _, t := range screenedTypes {
+ switch t {
+ case FleetFileVaultPayloadType, FleetFileVaultOptionsPayloadType, FleetRecoveryKeyEscrowPayloadType:
+ return errors.New("Couldn't add. The configuration profile can't include FileVault settings. " +
+ "To control these settings use disk encryption endpoint.")
+ }
+ }
return fmt.Errorf("unsupported PayloadType(s): %s", strings.Join(screenedTypes, ", "))
}
diff --git a/server/service/apple_mdm_test.go b/server/service/apple_mdm_test.go
index 152f4cffbb..96831b7274 100644
--- a/server/service/apple_mdm_test.go
+++ b/server/service/apple_mdm_test.go
@@ -1792,7 +1792,7 @@ func TestMDMBatchSetAppleProfiles(t *testing.T) {
false,
nil,
nil,
- [][]byte{[]byte(`
+ [][]byte{[]byte(fmt.Sprintf(`
@@ -1806,7 +1806,7 @@ func TestMDMBatchSetAppleProfiles(t *testing.T) {
PayloadIdentifier
com.apple.MCX.FileVault2.A5874654-D6BA-4649-84B5-43847953B369
PayloadType
- com.apple.MCX.FileVault2
+ %s
PayloadUUID
A5874654-D6BA-4649-84B5-43847953B369
PayloadVersion
@@ -1824,8 +1824,8 @@ func TestMDMBatchSetAppleProfiles(t *testing.T) {
PayloadVersion
1
- `)},
- "unsupported PayloadType(s)",
+ `, mobileconfig.FleetFileVaultPayloadType))},
+ "The configuration profile can't include FileVault settings.",
},
}
for name := range fleetmdm.FleetReservedProfileNames() {
diff --git a/server/service/integration_mdm_profiles_test.go b/server/service/integration_mdm_profiles_test.go
index fda94af6e6..a94d3ceab0 100644
--- a/server/service/integration_mdm_profiles_test.go
+++ b/server/service/integration_mdm_profiles_test.go
@@ -2350,7 +2350,12 @@ func (s *integrationMDMTestSuite) TestBatchSetMDMAppleProfiles() {
mobileconfigForTestWithContent("N1", "I1", "II1", p, ""),
}}, http.StatusUnprocessableEntity, "team_id", fmt.Sprint(tm.ID))
errMsg := extractServerErrorText(res.Body)
- require.Contains(t, errMsg, fmt.Sprintf("Validation Failed: unsupported PayloadType(s): %s", p))
+ switch p {
+ case mobileconfig.FleetFileVaultPayloadType, mobileconfig.FleetFileVaultOptionsPayloadType, mobileconfig.FleetRecoveryKeyEscrowPayloadType:
+ assert.Contains(t, errMsg, "Validation Failed: Couldn't add. The configuration profile can't include FileVault settings.")
+ default:
+ assert.Contains(t, errMsg, fmt.Sprintf("Validation Failed: unsupported PayloadType(s): %s", p))
+ }
}
// payloads with reserved identifiers
@@ -3203,8 +3208,10 @@ func (s *integrationMDMTestSuite) TestMDMConfigProfileCRUD() {
assertAppleDeclaration("foo.txt", "foo-ident", 0, nil, http.StatusBadRequest, "Couldn't add profile. The file should be a .mobileconfig, XML, or JSON file.")
// Windows-reserved LocURI
- assertWindowsProfile("bitlocker.xml", syncml.FleetBitLockerTargetLocURI, 0, nil, http.StatusBadRequest, "Couldn't add. Custom configuration profiles can't include BitLocker settings.")
- assertWindowsProfile("updates.xml", syncml.FleetOSUpdateTargetLocURI, testTeam.ID, nil, http.StatusBadRequest, "Couldn't add. Custom configuration profiles can't include Windows updates settings.")
+ assertWindowsProfile("bitlocker.xml", syncml.FleetBitLockerTargetLocURI, 0, nil, http.StatusBadRequest,
+ "Couldn't add. The configuration profile can't include BitLocker settings.")
+ assertWindowsProfile("updates.xml", syncml.FleetOSUpdateTargetLocURI, testTeam.ID, nil, http.StatusBadRequest,
+ "Couldn't add. Custom configuration profiles can't include Windows updates settings.")
// Fleet-reserved profiles
for name := range servermdm.FleetReservedProfileNames() {
@@ -4304,7 +4311,12 @@ func (s *integrationMDMTestSuite) TestBatchSetMDMProfiles() {
{Name: "N4", Contents: declarationForTest("D1")},
}}, http.StatusUnprocessableEntity, "team_id", fmt.Sprint(tm.ID))
errMsg := extractServerErrorText(res.Body)
- require.Contains(t, errMsg, fmt.Sprintf("Validation Failed: unsupported PayloadType(s): %s", p))
+ switch p {
+ case mobileconfig.FleetFileVaultPayloadType, mobileconfig.FleetFileVaultOptionsPayloadType, mobileconfig.FleetRecoveryKeyEscrowPayloadType:
+ assert.Contains(t, errMsg, "Validation Failed: Couldn't add. The configuration profile can't include FileVault settings.")
+ default:
+ assert.Contains(t, errMsg, fmt.Sprintf("Validation Failed: unsupported PayloadType(s): %s", p))
+ }
}
// payloads with reserved identifiers
@@ -4354,7 +4366,7 @@ func (s *integrationMDMTestSuite) TestBatchSetMDMProfiles() {
{Name: "N3", Contents: syncMLForTest("./Foo/Bar")},
}}, http.StatusUnprocessableEntity, "team_id", fmt.Sprint(tm.ID))
errMsg = extractServerErrorText(res.Body)
- require.Contains(t, errMsg, "Custom configuration profiles can't include BitLocker settings. To control these settings, use the mdm.enable_disk_encryption option.")
+ assert.Contains(t, errMsg, "Validation Failed: The configuration profile can't include BitLocker settings.")
// os updates
res = s.Do("POST", "/api/v1/fleet/mdm/profiles/batch", batchSetMDMProfilesRequest{Profiles: []fleet.MDMProfileBatchPayload{
@@ -4578,7 +4590,12 @@ func (s *integrationMDMTestSuite) TestBatchSetMDMProfilesBackwardsCompat() {
"N3": syncMLForTest("./Foo/Bar"),
}}, http.StatusUnprocessableEntity, "team_id", fmt.Sprint(tm.ID))
errMsg := extractServerErrorText(res.Body)
- require.Contains(t, errMsg, fmt.Sprintf("Validation Failed: unsupported PayloadType(s): %s", p))
+ switch p {
+ case mobileconfig.FleetFileVaultPayloadType, mobileconfig.FleetFileVaultOptionsPayloadType, mobileconfig.FleetRecoveryKeyEscrowPayloadType:
+ assert.Contains(t, errMsg, "Validation Failed: Couldn't add. The configuration profile can't include FileVault settings.")
+ default:
+ assert.Contains(t, errMsg, fmt.Sprintf("Validation Failed: unsupported PayloadType(s): %s", p))
+ }
}
// payloads with reserved identifiers
@@ -4599,7 +4616,7 @@ func (s *integrationMDMTestSuite) TestBatchSetMDMProfilesBackwardsCompat() {
"N3": syncMLForTest("./Foo/Bar"),
}}, http.StatusUnprocessableEntity, "team_id", fmt.Sprint(tm.ID))
errMsg := extractServerErrorText(res.Body)
- require.Contains(t, errMsg, "Custom configuration profiles can't include BitLocker settings. To control these settings, use the mdm.enable_disk_encryption option.")
+ assert.Contains(t, errMsg, "Validation Failed: The configuration profile can't include BitLocker settings.")
// os updates
res = s.Do("POST", "/api/v1/fleet/mdm/profiles/batch", map[string]any{"profiles": map[string][]byte{
diff --git a/server/service/mdm_test.go b/server/service/mdm_test.go
index 4402249658..4ca085b84b 100644
--- a/server/service/mdm_test.go
+++ b/server/service/mdm_test.go
@@ -9,6 +9,7 @@ import (
"crypto/x509/pkix"
"database/sql"
"errors"
+ "fmt"
"math/big"
"net/http"
"net/http/httptest"
@@ -17,6 +18,7 @@ import (
"testing"
"time"
+ "github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
nanodep_client "github.com/fleetdm/fleet/v4/server/mdm/nanodep/client"
nanodep_mock "github.com/fleetdm/fleet/v4/server/mock/nanodep"
"github.com/jmoiron/sqlx"
@@ -1216,7 +1218,9 @@ func TestUploadWindowsMDMConfigProfileValidations(t *testing.T) {
{"duplicate profile name", 0, `duplicate`, true, "configuration profile with this name already exists"},
{"multiple Replace", 0, `ab`, true, ""},
{"Replace and non-Replace", 0, `ab`, true, "Windows configuration profiles can only have or top level elements."},
- {"BitLocker profile", 0, `- ./Device/Vendor/MSFT/BitLocker/AllowStandardUserEncryption
`, true, "Custom configuration profiles can't include BitLocker settings."},
+ {"BitLocker profile", 0,
+ `- ./Device/Vendor/MSFT/BitLocker/AllowStandardUserEncryption
`, true,
+ "The configuration profile can't include BitLocker settings."},
{"Windows updates profile", 0, `- ./Device/Vendor/MSFT/Policy/Config/Update/ConfigureDeadlineNoAutoRebootForFeatureUpdates
`, true, "Custom configuration profiles can't include Windows updates settings."},
{"unsupported Fleet variable", 0, `$FLEET_VAR_BOZO`, true, "Fleet variable"},
@@ -1228,7 +1232,9 @@ func TestUploadWindowsMDMConfigProfileValidations(t *testing.T) {
{"team duplicate profile name", 1, `duplicate`, true, "configuration profile with this name already exists"},
{"team multiple Replace", 1, `ab`, true, ""},
{"team Replace and non-Replace", 1, `ab`, true, "Windows configuration profiles can only have or top level elements."},
- {"team BitLocker profile", 1, `- ./Device/Vendor/MSFT/BitLocker/AllowStandardUserEncryption
`, true, "Custom configuration profiles can't include BitLocker settings."},
+ {"team BitLocker profile", 1,
+ `- ./Device/Vendor/MSFT/BitLocker/AllowStandardUserEncryption
`, true,
+ "The configuration profile can't include BitLocker settings."},
{"team Windows updates profile", 1, `- ./Device/Vendor/MSFT/Policy/Config/Update/ConfigureDeadlineNoAutoRebootForFeatureUpdates
`, true, "Custom configuration profiles can't include Windows updates settings."},
{"invalid team", 2, ``, true, "not found"},
@@ -1541,7 +1547,7 @@ func TestMDMBatchSetProfiles(t *testing.T) {
nil,
[]fleet.MDMProfileBatchPayload{
{
- Name: "foo", Contents: []byte(`
+ Name: "foo", Contents: []byte(fmt.Sprintf(`
@@ -1555,7 +1561,7 @@ func TestMDMBatchSetProfiles(t *testing.T) {
PayloadIdentifier
com.apple.MCX.FileVault2.A5874654-D6BA-4649-84B5-43847953B369
PayloadType
- com.apple.MCX.FileVault2
+ %s
PayloadUUID
A5874654-D6BA-4649-84B5-43847953B369
PayloadVersion
@@ -1573,10 +1579,10 @@ func TestMDMBatchSetProfiles(t *testing.T) {
PayloadVersion
1
- `),
+ `, mobileconfig.FleetFileVaultPayloadType)),
},
},
- "unsupported PayloadType(s)",
+ "The configuration profile can't include FileVault settings.",
},
{
"unsupported Apple config profile Fleet variable",