diff --git a/.github/workflows/build-orbit.yaml b/.github/workflows/build-orbit.yaml
index 41ec1816c1be..229b6612b778 100644
--- a/.github/workflows/build-orbit.yaml
+++ b/.github/workflows/build-orbit.yaml
@@ -2,9 +2,15 @@ name: Build, Sign and Notarize Orbit for macOS
on:
workflow_dispatch: # allow manual action
+ push:
+ paths:
+ # The workflow can be triggered by modifying ORBIT_VERSION env.
+ - '.github/workflows/build-orbit.yaml'
pull_request:
paths:
- 'orbit/**.go'
+ # The workflow can be triggered by modifying ORBIT_VERSION env.
+ - '.github/workflows/build-orbit.yaml'
env:
ORBIT_VERSION: 1.17.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56c28a4c9857..c18bd7fe755c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Fleet 4.38.1 (Oct 5, 2023)
+
+### Bug Fixes
+
+* Fixed a bug that would cause live queries to stall if a detail query override was set for a team.
+
## Fleet 4.38.0 (Sep 25, 2023)
### Changes
diff --git a/CODEOWNERS b/CODEOWNERS
index 4a7bc630f41f..b952d8777f0f 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -72,7 +72,6 @@ go.mod @fleetdm/go
#
# (see website/config/custom.js for DRIs of other paths not listed here)
##############################################################################################
-/website/views/pages/pricing.ejs @mikermcneil # « CEO is DRI for pricing
/handbook/company/pricing-features-table.yml @mikermcneil # « CEO is current DRI for features table
##############################################################################################
diff --git a/articles/fleet-4.37.0.md b/articles/fleet-4.37.0.md
index 0f4cf5ed80f8..f3a2c7c37bac 100644
--- a/articles/fleet-4.37.0.md
+++ b/articles/fleet-4.37.0.md
@@ -1,4 +1,4 @@
-# Fleet 4.37.0 | Remote script execution & Puppet support.
+# Fleet 4.37.0 | Puppet support.
![Fleet 4.37.0](../website/assets/images/articles/fleet-4.37.0-1600x900@2x.png)
@@ -13,11 +13,12 @@ For upgrade instructions, see our [upgrade guide](https://fleetdm.com/docs/deplo
* Puppet support
* Web user interface improvements
+
### Vulnerability dashboard
diff --git a/articles/introducing-cross-platform-script-execution.md b/articles/introducing-cross-platform-script-execution
similarity index 100%
rename from articles/introducing-cross-platform-script-execution.md
rename to articles/introducing-cross-platform-script-execution
diff --git a/changes/12927-disk-encryption-settings b/changes/12927-disk-encryption-settings
new file mode 100644
index 000000000000..a9464b7d5bac
--- /dev/null
+++ b/changes/12927-disk-encryption-settings
@@ -0,0 +1 @@
+* Deprecate `mdm.macos_settings.enable_disk_encryption` in favor of `mdm.enable_disk_encryption`
diff --git a/changes/12932-bitlocker-api-updates b/changes/12932-bitlocker-api-updates
new file mode 100644
index 000000000000..0ce9b45e8a1b
--- /dev/null
+++ b/changes/12932-bitlocker-api-updates
@@ -0,0 +1,4 @@
+- Added `GET /mdm/disk_encryption/summary` endpoint to get the disk encryption summary for macOS and
+ Windows devices.
+- Added `os_settings` and `os_settings_disk_encryption` filters to `GET /hosts`, `GET /hosts/count`,
+ `GET /api/v1/fleet/labels/{id}/hosts` endpoints to filter hosts by OS settings.
diff --git a/changes/12933-bitlocker-host-details-api b/changes/12933-bitlocker-host-details-api
new file mode 100644
index 000000000000..ccb11df8b74e
--- /dev/null
+++ b/changes/12933-bitlocker-host-details-api
@@ -0,0 +1 @@
+- Added `mdm.os_settings` to `GET /api/v1/hosts/{id}` response.
diff --git a/changes/bug-13894-failing-policies-styling b/changes/bug-13894-failing-policies-styling
new file mode 100644
index 000000000000..5bd83a7b0961
--- /dev/null
+++ b/changes/bug-13894-failing-policies-styling
@@ -0,0 +1 @@
+* Fix styling for host details/device user failing policies call out
\ No newline at end of file
diff --git a/changes/issue-13953-changes-to-controls-page-for-bitlocker b/changes/issue-13953-changes-to-controls-page-for-bitlocker
new file mode 100644
index 000000000000..728d93122e02
--- /dev/null
+++ b/changes/issue-13953-changes-to-controls-page-for-bitlocker
@@ -0,0 +1 @@
+- change Controls/Disk Encryption and host details page to include windows bitlocker information.
diff --git a/changes/issue-13954-orbit-disk-encryption-key b/changes/issue-13954-orbit-disk-encryption-key
new file mode 100644
index 000000000000..82767942ec0b
--- /dev/null
+++ b/changes/issue-13954-orbit-disk-encryption-key
@@ -0,0 +1 @@
+* Added the `POST /api/fleet/orbit/disk_encryption_key` endpoint for Windows hosts to report the bitlocker encryption key.
diff --git a/changes/issue-14007-support-get-windows-encryption-key b/changes/issue-14007-support-get-windows-encryption-key
new file mode 100644
index 000000000000..0705f8e974f6
--- /dev/null
+++ b/changes/issue-14007-support-get-windows-encryption-key
@@ -0,0 +1 @@
+* Added support to return the decrypted disk encryption key of a Windows host.
diff --git a/charts/fleet/Chart.yaml b/charts/fleet/Chart.yaml
index e9d974fbcbeb..655c606998bb 100644
--- a/charts/fleet/Chart.yaml
+++ b/charts/fleet/Chart.yaml
@@ -8,4 +8,4 @@ version: v5.0.1
home: https://github.com/fleetdm/fleet
sources:
- https://github.com/fleetdm/fleet.git
-appVersion: v4.38.0
+appVersion: v4.38.1
diff --git a/charts/fleet/values.yaml b/charts/fleet/values.yaml
index d9394eea3407..4c01fb7ab5e7 100644
--- a/charts/fleet/values.yaml
+++ b/charts/fleet/values.yaml
@@ -2,7 +2,7 @@
# All settings related to how Fleet is deployed in Kubernetes
hostName: fleet.localhost
replicas: 3 # The number of Fleet instances to deploy
-imageTag: v4.38.0 # Version of Fleet to deploy
+imageTag: v4.38.1 # Version of Fleet to deploy
podAnnotations: {} # Additional annotations to add to the Fleet pod
serviceAccountAnnotations: {} # Additional annotations to add to the Fleet service account
resources:
diff --git a/cmd/fleet/cron.go b/cmd/fleet/cron.go
index 4835eb3e1930..50120b0434e0 100644
--- a/cmd/fleet/cron.go
+++ b/cmd/fleet/cron.go
@@ -18,6 +18,7 @@ import (
"github.com/fleetdm/fleet/v4/server/contexts/license"
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
"github.com/fleetdm/fleet/v4/server/fleet"
+ "github.com/fleetdm/fleet/v4/server/mdm"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
"github.com/fleetdm/fleet/v4/server/policies"
"github.com/fleetdm/fleet/v4/server/ptr"
@@ -838,7 +839,7 @@ func verifyDiskEncryptionKeys(
if key.UpdatedAt.After(latest) {
latest = key.UpdatedAt
}
- if _, err := apple_mdm.DecryptBase64CMS(key.Base64Encrypted, cert.Leaf, cert.PrivateKey); err != nil {
+ if _, err := mdm.DecryptBase64CMS(key.Base64Encrypted, cert.Leaf, cert.PrivateKey); err != nil {
undecryptable = append(undecryptable, key.HostID)
continue
}
diff --git a/cmd/fleetctl/apply_test.go b/cmd/fleetctl/apply_test.go
index 395fe0a6cdc2..8110239cac80 100644
--- a/cmd/fleetctl/apply_test.go
+++ b/cmd/fleetctl/apply_test.go
@@ -1044,13 +1044,13 @@ spec:
foo: qux
name: Team1
mdm:
+ enable_disk_encryption: false
macos_updates:
minimum_version: 10.10.10
deadline: 1992-03-01
macos_settings:
custom_settings:
- %s
- enable_disk_encryption: false
secrets:
- secret: BBB
`, mobileConfigPath))
@@ -1062,9 +1062,9 @@ spec:
require.Equal(t, "[+] applied 1 teams\n", runAppForTest(t, []string{"apply", "-f", name}))
assert.JSONEq(t, string(json.RawMessage(`{"config":{"views":{"foo":"qux"}}}`)), string(*savedTeam.Config.AgentOptions))
assert.Equal(t, fleet.TeamMDM{
+ EnableDiskEncryption: false,
MacOSSettings: fleet.MacOSSettings{
- CustomSettings: []string{mobileConfigPath},
- EnableDiskEncryption: false,
+ CustomSettings: []string{mobileConfigPath},
},
MacOSUpdates: fleet.MacOSUpdates{
MinimumVersion: optjson.SetString("10.10.10"),
@@ -1097,9 +1097,9 @@ spec:
require.True(t, ds.NewJobFuncInvoked)
// all left untouched, only setup assistant added
assert.Equal(t, fleet.TeamMDM{
+ EnableDiskEncryption: false,
MacOSSettings: fleet.MacOSSettings{
- CustomSettings: []string{mobileConfigPath},
- EnableDiskEncryption: false,
+ CustomSettings: []string{mobileConfigPath},
},
MacOSUpdates: fleet.MacOSUpdates{
MinimumVersion: optjson.SetString("10.10.10"),
@@ -1129,9 +1129,9 @@ spec:
require.Equal(t, "[+] applied 1 teams\n", runAppForTest(t, []string{"apply", "-f", name}))
// all left untouched, only bootstrap package added
assert.Equal(t, fleet.TeamMDM{
+ EnableDiskEncryption: false,
MacOSSettings: fleet.MacOSSettings{
- CustomSettings: []string{mobileConfigPath},
- EnableDiskEncryption: false,
+ CustomSettings: []string{mobileConfigPath},
},
MacOSUpdates: fleet.MacOSUpdates{
MinimumVersion: optjson.SetString("10.10.10"),
@@ -2886,7 +2886,7 @@ spec:
macos_settings:
enable_disk_encryption: true
`,
- wantErr: `Couldn't update macos_settings because MDM features aren't turned on in Fleet.`,
+ wantErr: `Couldn't edit enable_disk_encryption. Neither macOS MDM nor Windows is turned on`,
},
{
desc: "app config macos_settings.enable_disk_encryption false",
diff --git a/cmd/fleetctl/get.go b/cmd/fleetctl/get.go
index 3136dfd5b6a9..baa6cf5c613e 100644
--- a/cmd/fleetctl/get.go
+++ b/cmd/fleetctl/get.go
@@ -13,6 +13,7 @@ import (
"time"
"github.com/fatih/color"
+ "github.com/fleetdm/fleet/v4/pkg/rawjson"
"github.com/fleetdm/fleet/v4/pkg/secure"
kithttp "github.com/go-kit/kit/transport/http"
"gopkg.in/guregu/null.v3"
@@ -167,12 +168,15 @@ func (eacp enrichedAppConfigPresenter) MarshalJSON() ([]byte, error) {
*fleet.VulnerabilitiesConfig
}
- return json.Marshal(&struct {
- fleet.EnrichedAppConfig
+ enrichedJSON, err := json.Marshal(fleet.EnrichedAppConfig(eacp))
+ if err != nil {
+ return nil, err
+ }
+
+ extraFieldsJSON, err := json.Marshal(&struct {
UpdateInterval UpdateIntervalConfigPresenter `json:"update_interval,omitempty"`
Vulnerabilities VulnerabilitiesConfigPresenter `json:"vulnerabilities,omitempty"`
}{
- EnrichedAppConfig: fleet.EnrichedAppConfig(eacp),
UpdateInterval: UpdateIntervalConfigPresenter{
eacp.UpdateInterval.OSQueryDetail.String(),
eacp.UpdateInterval.OSQueryPolicy.String(),
@@ -184,6 +188,13 @@ func (eacp enrichedAppConfigPresenter) MarshalJSON() ([]byte, error) {
eacp.Vulnerabilities,
},
})
+ if err != nil {
+ return nil, err
+ }
+
+ // we need to marshal and combine both groups separately because
+ // enrichedAppConfig has a custom marshaler.
+ return rawjson.CombineRoots(enrichedJSON, extraFieldsJSON)
}
func printConfig(c *cli.Context, config interface{}) error {
diff --git a/cmd/fleetctl/get_test.go b/cmd/fleetctl/get_test.go
index a57d06413bd2..187264987480 100644
--- a/cmd/fleetctl/get_test.go
+++ b/cmd/fleetctl/get_test.go
@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -168,15 +167,15 @@ func TestGetTeams(t *testing.T) {
}, nil
}
- b, err := ioutil.ReadFile(filepath.Join("testdata", "expectedGetTeamsText.txt"))
+ b, err := os.ReadFile(filepath.Join("testdata", "expectedGetTeamsText.txt"))
require.NoError(t, err)
expectedText := string(b)
- b, err = ioutil.ReadFile(filepath.Join("testdata", "expectedGetTeamsYaml.yml"))
+ b, err = os.ReadFile(filepath.Join("testdata", "expectedGetTeamsYaml.yml"))
require.NoError(t, err)
expectedYaml := string(b)
- b, err = ioutil.ReadFile(filepath.Join("testdata", "expectedGetTeamsJson.json"))
+ b, err = os.ReadFile(filepath.Join("testdata", "expectedGetTeamsJson.json"))
require.NoError(t, err)
// must read each JSON value separately and compact it
var buf bytes.Buffer
@@ -206,8 +205,8 @@ func TestGetTeams(t *testing.T) {
errBuffer.Reset()
actualJSON, err := runWithErrWriter([]string{"get", "teams", "--json"}, &errBuffer)
require.NoError(t, err)
- require.Equal(t, expectedJson, actualJSON.String())
require.Equal(t, errBuffer.String() == expiredBanner.String(), tt.shouldHaveExpiredBanner)
+ require.Equal(t, expectedJson, actualJSON.String())
errBuffer.Reset()
actualYaml, err := runWithErrWriter([]string{"get", "teams", "--yaml"}, &errBuffer)
@@ -433,7 +432,7 @@ func TestGetHosts(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- expected, err := ioutil.ReadFile(filepath.Join("testdata", tt.goldenFile))
+ expected, err := os.ReadFile(filepath.Join("testdata", tt.goldenFile))
require.NoError(t, err)
expectedResults := tt.scanner(string(expected))
actualResult := tt.scanner(runAppForTest(t, tt.args))
@@ -536,7 +535,7 @@ func TestGetHostsMDM(t *testing.T) {
}
if tt.goldenFile != "" {
- expected, err := ioutil.ReadFile(filepath.Join("testdata", tt.goldenFile))
+ expected, err := os.ReadFile(filepath.Join("testdata", tt.goldenFile))
require.NoError(t, err)
if ext := filepath.Ext(tt.goldenFile); ext == ".json" {
// the output of --json is not a json array, but a list of
diff --git a/cmd/fleetctl/testdata/expectedGetConfigAppConfigJson.json b/cmd/fleetctl/testdata/expectedGetConfigAppConfigJson.json
index e6ae712e28c2..2f0c98c7408e 100644
--- a/cmd/fleetctl/testdata/expectedGetConfigAppConfigJson.json
+++ b/cmd/fleetctl/testdata/expectedGetConfigAppConfigJson.json
@@ -85,6 +85,7 @@
"enabled_and_configured": false,
"apple_bm_default_team": "",
"windows_enabled_and_configured": false,
+ "enable_disk_encryption": false,
"macos_updates": {
"minimum_version": null,
"deadline": null
@@ -95,8 +96,7 @@
"webhook_url": ""
},
"macos_settings": {
- "custom_settings": null,
- "enable_disk_encryption": false
+ "custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,
diff --git a/cmd/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml b/cmd/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml
index 1c0d7786853f..e7a5843214ce 100644
--- a/cmd/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml
+++ b/cmd/fleetctl/testdata/expectedGetConfigAppConfigYaml.yml
@@ -19,6 +19,7 @@ spec:
enabled_and_configured: false
apple_bm_default_team: ""
windows_enabled_and_configured: false
+ enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
@@ -28,7 +29,6 @@ spec:
deadline: null
macos_settings:
custom_settings:
- enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false
diff --git a/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json b/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json
index 2030db5afecb..94c6e70a7795 100644
--- a/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json
+++ b/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigJson.json
@@ -43,6 +43,7 @@
"apple_bm_enabled_and_configured": false,
"enabled_and_configured": false,
"windows_enabled_and_configured": false,
+ "enable_disk_encryption": false,
"macos_updates": {
"minimum_version": null,
"deadline": null
@@ -53,8 +54,7 @@
"webhook_url": ""
},
"macos_settings": {
- "custom_settings": null,
- "enable_disk_encryption": false
+ "custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,
diff --git a/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml b/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml
index 9d3bf00ace46..1b03fe13d3e4 100644
--- a/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml
+++ b/cmd/fleetctl/testdata/expectedGetConfigIncludeServerConfigYaml.yml
@@ -19,6 +19,7 @@ spec:
apple_bm_terms_expired: false
enabled_and_configured: false
windows_enabled_and_configured: false
+ enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
@@ -28,7 +29,6 @@ spec:
deadline: null
macos_settings:
custom_settings:
- enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false
diff --git a/cmd/fleetctl/testdata/expectedGetTeamsJson.json b/cmd/fleetctl/testdata/expectedGetTeamsJson.json
index 19152a690cd9..6a99943e9440 100644
--- a/cmd/fleetctl/testdata/expectedGetTeamsJson.json
+++ b/cmd/fleetctl/testdata/expectedGetTeamsJson.json
@@ -24,13 +24,13 @@
"enable_software_inventory": true
},
"mdm": {
+ "enable_disk_encryption": false,
"macos_updates": {
"minimum_version": null,
"deadline": null
},
"macos_settings": {
- "custom_settings": null,
- "enable_disk_encryption": false
+ "custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,
@@ -84,13 +84,13 @@
}
},
"mdm": {
+ "enable_disk_encryption": false,
"macos_updates": {
"minimum_version": "12.3.1",
"deadline": "2021-12-14"
},
"macos_settings": {
- "custom_settings": null,
- "enable_disk_encryption": false
+ "custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,
diff --git a/cmd/fleetctl/testdata/expectedGetTeamsYaml.yml b/cmd/fleetctl/testdata/expectedGetTeamsYaml.yml
index 2b571ae8b5bb..a6905cf569ee 100644
--- a/cmd/fleetctl/testdata/expectedGetTeamsYaml.yml
+++ b/cmd/fleetctl/testdata/expectedGetTeamsYaml.yml
@@ -7,12 +7,12 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
+ enable_disk_encryption: false
macos_updates:
minimum_version: null
deadline: null
macos_settings:
custom_settings:
- enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false
@@ -36,12 +36,12 @@ spec:
enable_host_users: false
enable_software_inventory: false
mdm:
+ enable_disk_encryption: false
macos_updates:
minimum_version: "12.3.1"
deadline: "2021-12-14"
macos_settings:
custom_settings:
- enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false
diff --git a/cmd/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml b/cmd/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml
index 4fc311a8dd21..d641e98b0a1f 100644
--- a/cmd/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml
+++ b/cmd/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml
@@ -19,13 +19,13 @@ spec:
apple_bm_terms_expired: false
enabled_and_configured: true
windows_enabled_and_configured: false
+ enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
webhook_url: ""
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: null
enable_end_user_authentication: false
diff --git a/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml b/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml
index 72b5d2c59969..433d80c586e8 100644
--- a/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml
+++ b/cmd/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml
@@ -19,13 +19,13 @@ spec:
apple_bm_terms_expired: false
enabled_and_configured: true
windows_enabled_and_configured: false
+ enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
webhook_url: ""
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: %s
enable_end_user_authentication: false
diff --git a/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml b/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml
index 346bbc2eb753..a3668e64b391 100644
--- a/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml
+++ b/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Empty.yml
@@ -7,9 +7,9 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
+ enable_disk_encryption: false
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: null
enable_end_user_authentication: false
@@ -27,9 +27,9 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
+ enable_disk_encryption: false
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: null
macos_setup_assistant: null
diff --git a/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml b/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml
index 45f1733019c1..95e49d032146 100644
--- a/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml
+++ b/cmd/fleetctl/testdata/macosSetupExpectedTeam1And2Set.yml
@@ -7,9 +7,9 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
+ enable_disk_encryption: false
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: %s
enable_end_user_authentication: false
@@ -27,9 +27,9 @@ spec:
enable_host_users: false
enable_software_inventory: false
mdm:
+ enable_disk_encryption: false
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: %s
macos_setup_assistant: %s
diff --git a/cmd/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml b/cmd/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml
index 21d9b9d8db20..8ad10fc6c51a 100644
--- a/cmd/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml
+++ b/cmd/fleetctl/testdata/macosSetupExpectedTeam1Empty.yml
@@ -7,9 +7,9 @@ spec:
enable_host_users: false
enable_software_inventory: false
mdm:
+ enable_disk_encryption: false
macos_settings:
custom_settings: null
- enable_disk_encryption: false
macos_setup:
bootstrap_package: null
enable_end_user_authentication: false
diff --git a/docs/Configuration/configuration-files/README.md b/docs/Configuration/configuration-files/README.md
index 9cc12b3321ac..8b8f34b8cf62 100644
--- a/docs/Configuration/configuration-files/README.md
+++ b/docs/Configuration/configuration-files/README.md
@@ -529,8 +529,10 @@ Use with caution as this may break Fleet ingestion of hosts data.
```yaml
features:
detail_query_overrides:
- # null allows to disable the "users" query from running on hosts.
+ # null disables the "users" query from running on hosts.
users: null
+ # "" disables the "disk_encryption_linux" query from running on hosts.
+ disk_encryption_linux: ""
# this replaces the hardcoded "mdm" detail query.
mdm: "SELECT enrolled, server_url, installed_from_dep, payload_identifier FROM mdm;"
```
diff --git a/docs/Contributing/API-for-contributors.md b/docs/Contributing/API-for-contributors.md
index 7724b770b74e..ddefdb2e9a53 100644
--- a/docs/Contributing/API-for-contributors.md
+++ b/docs/Contributing/API-for-contributors.md
@@ -533,6 +533,7 @@ The MDM endpoints exist to support the related command-line interface sub-comman
- [Complete SSO during DEP enrollment](#complete-sso-during-dep-enrollment)
- [Preassign profiles to devices](#preassign-profiles-to-devices)
- [Match preassigned profiles](#match-preassigned-profiles)
+- [Get FileVault statistics](#get-filevault-statistics)
### Generate Apple DEP Key Pair
@@ -701,6 +702,44 @@ This endpoint stores a profile to be assigned to a host at some point in the fut
`Status: 204`
+### Get FileVault statistics
+
+_Available in Fleet Premium_
+
+Get aggregate status counts of disk encryption enforced on macOS hosts.
+
+The summary can optionally be filtered by team id.
+
+`GET /api/v1/fleet/mdm/apple/filevault/summary`
+
+#### Parameters
+
+| Name | Type | In | Description |
+| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
+| team_id | string | query | _Available in Fleet Premium_ The team id to filter the summary. |
+
+#### Example
+
+Get aggregate status counts of Apple disk encryption profiles applying to macOS hosts enrolled to Fleet's MDM that are not assigned to any team.
+
+`GET /api/v1/fleet/mdm/apple/filevault/summary`
+
+##### Default response
+
+`Status: 200`
+
+```json
+{
+ "verified": 123,
+ "verifying": 123,
+ "action_required": 123,
+ "enforcing": 123,
+ "failed": 123,
+ "removing_enforcement": 123
+}
+```
+
+
### Match preassigned profiles
_Available in Fleet Premium_
@@ -2291,7 +2330,9 @@ Gets all information required by Fleet Desktop, this includes things like the nu
{
"failing_policies_count": 3,
"notifications": {
- "needs_mdm_migration": true
+ "needs_mdm_migration": true,
+ "renew_enrollment_profile": false,
+ "enforce_bitlocker_encryption": false,
},
"config": {
"org_info": {
@@ -2313,6 +2354,7 @@ In regards to the `notifications` key:
- `needs_mdm_migration` means that the device fits all the requirements to allow the user to initiate an MDM migration to Fleet.
- `renew_enrollment_profile` means that the device is currently unmanaged from MDM but should be DEP enrolled into Fleet.
+- `enforce_bitlocker_encryption` applies only to Windows devices and means that it should encrypt the disk and report the encryption key back to Fleet.
#### Get device's policies
diff --git a/docs/Contributing/FAQ.md b/docs/Contributing/FAQ.md
index 3d3f69c92bfa..c7522aa537bc 100644
--- a/docs/Contributing/FAQ.md
+++ b/docs/Contributing/FAQ.md
@@ -93,6 +93,7 @@ If you also have Fleetd running on hosts, it will need access to these API endpo
* `/api/fleet/orbit/ping`
* `/api/fleet/orbit/scripts/request`
* `/api/fleet/orbit/scripts/result`
+* `/api/fleet/orbit/disk_encryption_key`
* `/api/osquery/log`
diff --git a/docs/Get started/anatomy.md b/docs/Get started/anatomy.md
index 757c9614a148..7bc314d2454b 100644
--- a/docs/Get started/anatomy.md
+++ b/docs/Get started/anatomy.md
@@ -12,7 +12,7 @@ Fleetctl (pronouced “fleet control”) is a CLI (command line interface) tool
## Fleetd
-Fleetd is a bundle of agents provided by Fleet to gather information about your devices. Fleetd includes [osquery](https://www.osquery.io/), Orbit, and Fleet Desktop. [Docs](https://fleetdm.com/docs/using-fleet/fleet-ui).
+Fleetd is a bundle of agents provided by Fleet to gather information about your devices. Fleetd includes [osquery](https://www.osquery.io/), Orbit, and Fleet Desktop. [Docs](https://fleetdm.com/docs/using-fleet/fleetd).
## Osquery
Osquery is an open-source tool for gathering information about the state of any device that the osquery agent has been installed on. [Learn more](https://www.osquery.io/).
diff --git a/docs/REST API/rest-api.md b/docs/REST API/rest-api.md
index a40f5daa3950..753288389aa9 100644
--- a/docs/REST API/rest-api.md
+++ b/docs/REST API/rest-api.md
@@ -1829,14 +1829,14 @@ the `software` table.
| page | integer | query | Page number of the results to fetch. |
| per_page | integer | query | Results per page. |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
-| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. **Note:** Use `page` instead of `after`. |
-| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
-| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
-| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an `@`, no space, etc.). |
-| additional_info_filters | string | query | A comma-delimited list of fields to include in each host's additional information object. See [Fleet Configuration Options](https://fleetdm.com/docs/using-fleet/fleetctl-cli#fleet-configuration-options) for an example configuration with hosts' additional information. Use `*` to get all stored fields. |
+| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. **Note:** Use `page` instead of `after` |
+| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
+| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
+| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an '@', no space, etc.). |
+| additional_info_filters | string | query | A comma-delimited list of fields to include in each host's additional information object. See [Fleet Configuration Options](https://fleetdm.com/docs/using-fleet/fleetctl-cli#fleet-configuration-options) for an example configuration with hosts' additional information. Use '*' to get all stored fields. |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| policy_id | integer | query | The ID of the policy to filter hosts by. |
-| policy_response | string | query | Valid options are `passing` or `failing`. `policy_id` must also be specified with `policy_response`. |
+| policy_response | string | query | Valid options are 'passing' or 'failing'. `policy_id` must also be specified with `policy_response`. |
| software_id | integer | query | The ID of the software to filter hosts by. |
| os_id | integer | query | The ID of the operating system to filter hosts by. |
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
@@ -1849,8 +1849,11 @@ the `software` table.
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| disable_failing_policies| boolean | query | If "true", hosts will return failing policies as 0 regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
-| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of `verified`, `verifying`, `action_required`, `enforcing`, `failed`, or `removing_enforcement`. |
-| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of `installed`, `pending`, or `failed`. |
+| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of 'verified', 'verifying', 'action_required', 'enforcing', 'failed', or 'removing_enforcement'. |
+| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of 'installed', 'pending', or 'failed'. |
+| os_settings | string | query | Filters the hosts by the status of the operating system settings applied to the hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| os_settings_disk_encryption | string | query | Filters the hosts by the status of the disk encryption setting applied to the hosts. Can be one of 'verified', 'verifying', 'action_required', 'enforcing', 'failed', or 'removing_enforcement'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+
If `additional_info_filters` is not specified, no `additional` information will be returned.
@@ -1858,9 +1861,9 @@ If `software_id` is specified, an additional top-level key `"software"` is retur
If `mdm_id` is specified, an additional top-level key `"mobile_device_management_solution"` is returned with the information corresponding to the `mdm_id`.
-If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
+If `mdm_id`, `mdm_name`, `mdm_enrollment_status`, `os_settings`, or `os_settings_disk_encryption` is specified, then Windows Servers are excluded from the results.
-If `munki_issue_id` is specified, an additional top-level key `"munki_issue"` is returned with the information corresponding to the `munki_issue_id`.
+If `munki_issue_id` is specified, an additional top-level key `munki_issue` is returned with the information corresponding to the `munki_issue_id`.
If `after` is being used with `created_at` or `updated_at`, the table must be specified in `order_key`. Those columns become `h.created_at` and `h.updated_at`.
@@ -1988,13 +1991,13 @@ Response payload with the `munki_issue_id` filter provided:
| Name | Type | In | Description |
| ----------------------- | ------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
-| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
+| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. |
-| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
-| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an `@`, no space, etc.). |
+| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
+| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an '@', no space, etc.). |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| policy_id | integer | query | The ID of the policy to filter hosts by. |
-| policy_response | string | query | Valid options are `passing` or `failing`. `policy_id` must also be specified with `policy_response`. |
+| policy_response | string | query | Valid options are 'passing' or 'failing'. `policy_id` must also be specified with `policy_response`. |
| software_id | integer | query | The ID of the software to filter hosts by. |
| os_id | integer | query | The ID of the operating system to filter hosts by. |
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
@@ -2006,8 +2009,10 @@ Response payload with the `munki_issue_id` filter provided:
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
-| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of `verified`, `verifying`, `action_required`, `enforcing`, `failed`, or `removing_enforcement`. |
-| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of `installed`, `pending`, or `failed`. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of 'verified', 'verifying', 'action_required', 'enforcing', 'failed', or 'removing_enforcement'. |
+| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of 'installed', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| os_settings | string | query | Filters the hosts by the status of the operating system settings applied to the hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| os_settings_disk_encryption | string | query | Filters the hosts by the status of the disk encryption setting applied to the hosts. Can be one of 'verified', 'verifying', 'action_required', 'enforcing', 'failed', or 'removing_enforcement'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
If `additional_info_filters` is not specified, no `additional` information will be returned.
@@ -2555,6 +2560,9 @@ Returns the information of the host specified using the `uuid`, `osquery_host_id
"bootstrap_package_status": "installed",
"detail": ""
},
+ "os_settings": {
+ "disk_encryption": null
+ },
"profiles": [
{
"profile_id": 999,
@@ -2743,6 +2751,9 @@ This is the API route used by the **My device** page in Fleet desktop to display
"detail": "",
"bootstrap_package_name": "test.pkg"
},
+ "os_settings": {
+ "disk_encryption": null
+ },
"profiles": [
{
"profile_id": 999,
@@ -3291,12 +3302,12 @@ requested by a web browser.
| format | string | query | **Required**, must be "csv" (only supported format for now). |
| columns | string | query | Comma-delimited list of columns to include in the report (returns all columns if none is specified). |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
-| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
-| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
+| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
+| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an `@`, no space, etc.). |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| policy_id | integer | query | The ID of the policy to filter hosts by. |
-| policy_response | string | query | Valid options are `passing` or `failing`. `policy_id` must also be specified with `policy_response`. **Note: If `policy_id` is specified _without_ including `policy_response`, this will also return hosts where the policy is not configured to run or failed to run.** |
+| policy_response | string | query | Valid options are 'passing' or 'failing'. `policy_id` must also be specified with `policy_response`. **Note: If `policy_id` is specified _without_ including `policy_response`, this will also return hosts where the policy is not configured to run or failed to run.** |
| software_id | integer | query | The ID of the software to filter hosts by. |
| os_id | integer | query | The ID of the operating system to filter hosts by. |
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
@@ -3308,7 +3319,7 @@ requested by a web browser.
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| label_id | integer | query | A valid label ID. Can only be used in combination with `order_key`, `order_direction`, `status`, `query` and `team_id`. |
-| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of `installed`, `pending`, or `failed`. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of 'installed', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| disable_failing_policies | boolean | query | If `true`, hosts will return failing policies as 0 (returned as the `issues` column) regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
@@ -3330,7 +3341,7 @@ created_at,updated_at,id,detail_updated_at,label_updated_at,policy_updated_at,la
### Get host's disk encryption key
-Requires the [macadmins osquery extension](https://github.com/macadmins/osquery-extension) which comes bundled
+For macOS, requires the [macadmins osquery extension](https://github.com/macadmins/osquery-extension) which comes bundled
in [Fleet's osquery installers](https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer).
Requires Fleet's MDM properly [enabled and configured](https://fleetdm.com/docs/using-fleet/mdm-macos-setup).
@@ -3724,9 +3735,9 @@ Returns a list of the hosts that belong to the specified label.
| page | integer | query | Page number of the results to fetch. |
| per_page | integer | query | Results per page. |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
-| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
+| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. |
-| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
+| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, and `ipv4`. |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| disable_failing_policies | boolean | query | If "true", hosts will return failing policies as 0 regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
@@ -3735,10 +3746,12 @@ Returns a list of the hosts that belong to the specified label.
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
-| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of `verified`, `verifying`, `action_required`, `enforcing`, `failed`, or `removing_enforcement`. |
-| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of `installed`, `pending`, or `failed`. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of 'verified', 'verifying', 'action_required', 'enforcing', 'failed', or 'removing_enforcement'. |
+| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of 'installed', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| os_settings | string | query | Filters the hosts by the status of the operating system settings applied to the hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
+| os_settings_disk_encryption | string | query | Filters the hosts by the status of the disk encryption setting applied to the hosts. Can be one of 'verified', 'verifying', 'action_required', 'enforcing', 'failed', or 'removing_enforcement'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
-If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
+If `mdm_id`, `mdm_name`, `mdm_enrollment_status`, `os_settings`, or `os_settings_disk_encryption` is specified, then Windows Servers are excluded from the results.
#### Example
@@ -4090,23 +4103,23 @@ _Available in Fleet Premium_
_Available in Fleet Premium_
-Get aggregate status counts of disk encryption enforced on hosts.
+Get aggregate status counts of disk encryption enforced on macOS and Windows hosts.
The summary can optionally be filtered by team id.
-`GET /api/v1/fleet/mdm/apple/filevault/summary`
+`GET /api/v1/fleet/mdm/disk_encryption/summary`
#### Parameters
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
-| team_id | string | query | _Available in Fleet Premium_ The team id to filter the summary. |
+| team_id | string | query | _Available in Fleet Premium_ The team id to filter the summary. |
#### Example
-Get aggregate status counts of Apple disk encryption profiles applying to macOS hosts enrolled to Fleet's MDM that are not assigned to any team.
+Get aggregate disk encryption status counts of macOS and Windows hosts enrolled to Fleet's MDM that are not assigned to any team.
-`GET /api/v1/fleet/mdm/apple/filevault/summary`
+`GET /api/v1/fleet/mdm/disk_encryption/summary`
##### Default response
@@ -4114,12 +4127,12 @@ Get aggregate status counts of Apple disk encryption profiles applying to macOS
```json
{
- "verified": 123,
- "verifying": 123,
- "action_required": 123,
- "enforcing": 123,
- "failed": 123,
- "removing_enforcement": 123
+ "verified": {"macos": 123, "windows": 123},
+ "verifying": {"macos": 123, "windows": 0},
+ "action_required": {"macos": 123, "windows": 0},
+ "enforcing": {"macos": 123, "windows": 123},
+ "failed": {"macos": 123, "windows": 123},
+ "removing_enforcement": {"macos": 123, "windows": 0},
}
```
@@ -6600,7 +6613,8 @@ Deletes the session specified by ID. When the user associated with the session n
"epss_probability": 0.01537,
"cisa_known_exploit": false,
"cve_published": "2022-01-01 12:32:00",
- "cve_description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match."
+ "cve_description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.",
+ "resolved_in_version": "2.28"
}
],
"hosts_count": 1
diff --git a/docs/Using Fleet/CIS-Benchmarks.md b/docs/Using Fleet/CIS-Benchmarks.md
index 5d92bc4607ad..632caf0ae665 100644
--- a/docs/Using Fleet/CIS-Benchmarks.md
+++ b/docs/Using Fleet/CIS-Benchmarks.md
@@ -170,127 +170,11 @@ The following CIS benchmark checks cannot be automated and must be addressed man
Fleet's policies have been written against v1.12.0 of the benchmark. You can refer to the [CIS website](https://www.cisecurity.org/cis-benchmarks) for full details about this version.
-### Checks that require a Group Policy Template
+### Checks that require a Group Policy template
-38 items require Group Policy Template in place in order to audit them.
+Several items require Group Policy templates in place in order to audit them.
These items are tagged with the label `CIS_group_policy_template_required` in the YAML file, and details about the required Group Policy templates can be found in each item's `resolution`.
-```
-18.3.1 CIS - Ensure 'Apply UAC restrictions to local accounts on network logons' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Apply UAC restrictions to local accounts on network logons'
-
-18.3.2 CIS - Ensure 'Configure SMB v1 client driver' is set to 'Enabled: Disable driver (recommended)'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Configure SMB v1 client driver'
-
-18.3.3 CIS - Ensure 'Configure SMB v1 server' is set to 'Disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Configure SMB v1 server'
-
-18.3.4 CIS - Ensure 'Enable Structured Exception Handling Overwrite Protection (SEHOP)' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Enable Structured Exception Handling Overwrite Protection (SEHOP)'
-
-18.3.5 CIS - Ensure 'Limits print driver installation to Administrators' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Limits print driver installation to Administrators'
-
-18.3.6 CIS - Ensure 'NetBT NodeType configuration' is set to 'Enabled: P-node (recommended)'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\NetBT NodeType configuration'
-
-18.3.7 CIS - Ensure 'WDigest Authentication' is set to 'Disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\WDigest Authentication (disabling may require KB2871997)'
-
-18.4.1 CIS - Ensure 'MSS: (AutoAdminLogon) Enable Automatic Logon (not recommended)' is set to 'Disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (AutoAdminLogon) Enable Automatic Logon (not recommended)'
-
-18.4.2 CIS - Ensure 'MSS: (DisableIPSourceRouting IPv6) IP source routing protection level (protects against packet spoofing)' is set to 'Enabled: Highest protection, source routing is completely disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (DisableIPSourceRouting IPv6) IP source routing protection level (protects against packet spoofing)'
-
-18.4.3 CIS - Ensure 'MSS: (DisableIPSourceRouting) IP source routing protection level (protects against packet spoofing)' is set to 'Enabled: Highest protection, source routing is completely disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (DisableIPSourceRouting) IP source routing protection level (protects against packet spoofing)'
-
-18.4.4 CIS - Ensure 'MSS: (DisableSavePassword) Prevent the dial-up password from being saved' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS:(DisableSavePassword) Prevent the dial-up password from being saved'
-
-18.4.5 CIS - Ensure 'MSS: (EnableICMPRedirect) Allow ICMP redirects to override OSPF generated routes' is set to 'Disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (EnableICMPRedirect) Allow ICMP redirects to override OSPF generated routes'
-
-18.4.6 CIS - Ensure 'MSS: (KeepAliveTime) How often keep-alive packets are sent in milliseconds' is set to 'Enabled: 300,000 or 5 minutes'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (KeepAliveTime) How often keep-alive packets are sent in milliseconds'
-
-18.4.7 CIS - Ensure 'MSS: (NoNameReleaseOnDemand) Allow the computer to ignore NetBIOS name release requests except from WINS servers' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (NoNameReleaseOnDemand) Allow the computer to ignore NetBIOS name release requests except from WINS servers'
-
-18.4.8 CIS - Ensure 'MSS: (PerformRouterDiscovery) Allow IRDP to detect and configure Default Gateway addresses (could lead to DoS)' is set to 'Disabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (PerformRouterDiscovery) Allow IRDP to detect and configure Default Gateway addresses (could lead to DoS)'
-
-18.4.9 CIS - Ensure 'MSS: (SafeDllSearchMode) Enable Safe DLL search mode (recommended)' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (SafeDllSearchMode) Enable Safe DLL search mode (recommended)'
-
-18.4.10 CIS - Ensure 'MSS: (ScreenSaverGracePeriod) The time in seconds before the screen saver grace period expires (0 recommended)' is set to 'Enabled: 5 or fewer seconds'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (ScreenSaverGracePeriod) The time in seconds before the screen saver grace period expires (0 recommended)'
-
-18.4.11 CIS - Ensure 'MSS: (TcpMaxDataRetransmissions IPv6) How many times unacknowledged data is retransmitted' is set to 'Enabled: 3'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS:(TcpMaxDataRetransmissions IPv6) How many times unacknowledged data is retransmitted'
-
-18.4.12 CIS - Ensure 'MSS: (TcpMaxDataRetransmissions) How many times unacknowledged data is retransmitted' is set to 'Enabled: 3'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS:(TcpMaxDataRetransmissions) How many times unacknowledged data is retransmitted'
-
-18.4.13 CIS - Ensure 'MSS: (WarningLevel) Percentage threshold for the security event log at which the system will generate a warning' is set to 'Enabled: 90% or less'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (WarningLevel) Percentage threshold for the security event log at which the system will generate a warning'
-
-18.8.21.2 CIS - Ensure 'Configure registry policy processing: Do not apply during periodic background processing' is set to 'Enabled: FALSE'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Group Policy\Configure registry policy processing'
-
-18.8.22.1.1 CIS - Ensure 'Turn off access to the Store' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off access to the Store'
-
-18.8.22.1.2 CIS - Ensure 'Turn off downloading of print drivers over HTTP' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off downloading of print drivers over HTTP'
-
-18.8.22.1.3 CIS - Ensure 'Turn off handwriting personalization data sharing' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off handwriting personalization data sharing'
-
-18.8.22.1.4 CIS - Ensure 'Turn off handwriting recognition error reporting' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off handwriting recognition error reporting'
-
-18.8.22.1.5 CIS - Ensure 'Turn off Internet Connection Wizard if URL connection is referring to Microsoft.com' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Internet Connection Wizard if URL connection is referring to Microsoft.com'
-
-18.8.22.1.6 CIS - Ensure 'Turn off Internet download for Web publishing and online ordering wizards' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Internet download for Web publishing and online ordering wizards'
-
-18.8.22.1.7 CIS - Ensure 'Turn off printing over HTTP' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off printing over HTTP'
-
-18.8.22.1.8 CIS - Ensure 'Turn off Registration if URL connection is referring to Microsoft.com' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Registration if URL connection is referring to Microsoft.com'
-
-18.8.22.1.9 CIS - Ensure 'Turn off Search Companion content file updates' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Search Companion content file updates'
-
-18.8.22.1.10 CIS - Ensure 'Turn off the "Order Prints" picture task' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off the "Order Prints" picture task'
-
-18.8.22.1.11 CIS - Ensure 'Turn off the "Publish to Web" task for files and folders' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off the "Publish to Web" task for files and folders'
-
-18.8.22.1.12 CIS - Ensure 'Turn off the Windows Messenger Customer Experience Improvement Program' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off the Windows Messenger Customer Experience Improvement Program'
-
-18.8.22.1.13 CIS - Ensure 'Turn off Windows Customer Experience Improvement Program' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Windows Customer Experience Improvement Program'
-
-18.8.22.1.14 CIS - Ensure 'Turn off Windows Error Reporting' is set to 'Enabled'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Windows Error Reporting'
-
-18.8.25.1 CIS - Ensure 'Support device authentication using certificate' is set to 'Enabled: Automatic'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Kerberos\Support device authentication using certificate'
-
-18.8.26.1 CIS - Ensure 'Enumeration policy for external devices incompatible with Kernel DMA Protection' is set to 'Enabled: Block All'
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Kernel DMA Protection\Enumeration policy for external devices incompatible with Kernel DMA Protection'
-
-18.8.27.1 CIS - Ensure 'Disallow copying of user input methods to the system account for sign-in' is set to 'Enabled' (Automated)
-Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Locale Services\Disallow copying of user input methods to the system account for sign-in'
-```
-
## Performance testing
In August 2023, we completed scale testing on 10k Windows hosts and 70k macOS hosts. Ultimately, we validated both server and host performance at that scale.
diff --git a/docs/Using Fleet/manage-access.md b/docs/Using Fleet/manage-access.md
index 48c1a2152600..90774c86e1a7 100644
--- a/docs/Using Fleet/manage-access.md
+++ b/docs/Using Fleet/manage-access.md
@@ -75,7 +75,7 @@ GitOps is an API-only and write-only role that can be used on CI/CD pipelines.
| View Apple mobile device management (MDM) certificate information | | | | ✅ | |
| View Apple business manager (BM) information | | | | ✅ | |
| Generate Apple mobile device management (MDM) certificate signing request (CSR) | | | | ✅ | |
-| View disk encryption key for macOS hosts | ✅ | ✅ | ✅ | ✅ | |
+| View disk encryption key for macOS and Windows hosts | ✅ | ✅ | ✅ | ✅ | |
| Create edit and delete configuration profiles for macOS hosts | | | ✅ | ✅ | ✅ |
| Execute MDM commands on macOS and Windows hosts*** | | | ✅ | ✅ | |
| View results of MDM commands executed on macOS and Windows hosts*** | ✅ | ✅ | ✅ | ✅ | |
diff --git a/ee/server/service/mdm.go b/ee/server/service/mdm.go
index afd304a6c8f9..37cf53721821 100644
--- a/ee/server/service/mdm.go
+++ b/ee/server/service/mdm.go
@@ -15,6 +15,7 @@ import (
"strings"
"github.com/fleetdm/fleet/v4/pkg/file"
+ "github.com/fleetdm/fleet/v4/pkg/optjson"
"github.com/fleetdm/fleet/v4/server/authz"
"github.com/fleetdm/fleet/v4/server/contexts/ctxdb"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
@@ -890,12 +891,7 @@ func (svc *Service) getOrCreatePreassignTeam(ctx context.Context, groups []strin
}
payload.MDM = &fleet.TeamPayloadMDM{
- MacOSSettings: &fleet.MacOSSettings{
- // teams created by the match endpoint have disk encryption
- // enabled by default.
- // TODO: maybe make this configurable?
- EnableDiskEncryption: true,
- },
+ EnableDiskEncryption: optjson.SetBool(true),
MacOSSetup: &fleet.MacOSSetup{
MacOSSetupAssistant: ac.MDM.MacOSSetup.MacOSSetupAssistant,
// NOTE: BootstrapPackage is currently ignored by svc.ModifyTeam and gets set
@@ -968,3 +964,51 @@ func teamNameFromPreassignGroups(groups []string) string {
return strings.Join(groups, " - ")
}
+
+func (svc *Service) GetMDMDiskEncryptionSummary(ctx context.Context, teamID *uint) (*fleet.MDMDiskEncryptionSummary, error) {
+ // TODO: Consider adding a new generic OSSetting type or Windows-specific type for authz checks
+ // like this.
+ if err := svc.authz.Authorize(ctx, fleet.MDMAppleConfigProfile{TeamID: teamID}, fleet.ActionRead); err != nil {
+ return nil, ctxerr.Wrap(ctx, err)
+ }
+ var macOS fleet.MDMAppleFileVaultSummary
+ if m, err := svc.ds.GetMDMAppleFileVaultSummary(ctx, teamID); err != nil {
+ return nil, ctxerr.Wrap(ctx, err, "getting filevault summary")
+ } else if m != nil {
+ macOS = *m
+ }
+
+ var windows fleet.MDMWindowsBitLockerSummary
+ if w, err := svc.ds.GetMDMWindowsBitLockerSummary(ctx, teamID); err != nil {
+ return nil, ctxerr.Wrap(ctx, err, "getting bitlocker summary")
+ } else if w != nil {
+ windows = *w
+ }
+
+ return &fleet.MDMDiskEncryptionSummary{
+ Verified: fleet.MDMPlatformsCounts{
+ MacOS: macOS.Verified,
+ Windows: windows.Verified,
+ },
+ Verifying: fleet.MDMPlatformsCounts{
+ MacOS: macOS.Verifying,
+ Windows: windows.Verifying,
+ },
+ ActionRequired: fleet.MDMPlatformsCounts{
+ MacOS: macOS.ActionRequired,
+ Windows: windows.ActionRequired,
+ },
+ Enforcing: fleet.MDMPlatformsCounts{
+ MacOS: macOS.Enforcing,
+ Windows: windows.Enforcing,
+ },
+ Failed: fleet.MDMPlatformsCounts{
+ MacOS: macOS.Failed,
+ Windows: windows.Failed,
+ },
+ RemovingEnforcement: fleet.MDMPlatformsCounts{
+ MacOS: macOS.RemovingEnforcement,
+ Windows: windows.RemovingEnforcement,
+ },
+ }, nil
+}
diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go
index 33a777323f1b..529408de47b0 100644
--- a/ee/server/service/teams.go
+++ b/ee/server/service/teams.go
@@ -150,13 +150,13 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T
}
}
- if payload.MDM.MacOSSettings != nil {
- if !appCfg.MDM.EnabledAndConfigured && payload.MDM.MacOSSettings.EnableDiskEncryption {
+ if payload.MDM.EnableDiskEncryption.Valid {
+ macOSDiskEncryptionUpdated = team.Config.MDM.EnableDiskEncryption != payload.MDM.EnableDiskEncryption.Value
+ if macOSDiskEncryptionUpdated && !appCfg.MDM.EnabledAndConfigured {
return nil, fleet.NewInvalidArgumentError("macos_settings.enable_disk_encryption",
`Couldn't update macos_settings because MDM features aren't turned on in Fleet. Use fleetctl generate mdm-apple and then fleet serve with mdm configuration to turn on MDM features.`)
}
- macOSDiskEncryptionUpdated = team.Config.MDM.MacOSSettings.EnableDiskEncryption != payload.MDM.MacOSSettings.EnableDiskEncryption
- team.Config.MDM.MacOSSettings.EnableDiskEncryption = payload.MDM.MacOSSettings.EnableDiskEncryption
+ team.Config.MDM.EnableDiskEncryption = payload.MDM.EnableDiskEncryption.Value
}
if payload.MDM.MacOSSetup != nil {
@@ -225,7 +225,7 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T
}
if macOSDiskEncryptionUpdated {
var act fleet.ActivityDetails
- if team.Config.MDM.MacOSSettings.EnableDiskEncryption {
+ if team.Config.MDM.EnableDiskEncryption {
act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &team.ID, TeamName: &team.Name}
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &team.ID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "enable team filevault and escrow")
@@ -802,6 +802,17 @@ func (svc *Service) createTeamFromSpec(
`Couldn't update macos_setup because MDM features aren't turned on in Fleet. Use fleetctl generate mdm-apple and then fleet serve with mdm configuration to turn on MDM features.`))
}
}
+ enableDiskEncryption := spec.MDM.EnableDiskEncryption.Value
+ if !spec.MDM.EnableDiskEncryption.Valid {
+ if de := macOSSettings.DeprecatedEnableDiskEncryption; de != nil {
+ enableDiskEncryption = *de
+ }
+ }
+
+ if enableDiskEncryption && !defaults.MDM.AtLeastOnePlatformEnabledAndConfigured() {
+ return nil, ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("mdm",
+ `Couldn't edit enable_disk_encryption. Neither macOS MDM nor Windows is turned on. Visit https://fleetdm.com/docs/using-fleet to learn how to turn on MDM.`))
+ }
if dryRun {
return &fleet.Team{Name: spec.Name}, nil
@@ -813,9 +824,10 @@ func (svc *Service) createTeamFromSpec(
AgentOptions: agentOptions,
Features: features,
MDM: fleet.TeamMDM{
- MacOSUpdates: spec.MDM.MacOSUpdates,
- MacOSSettings: macOSSettings,
- MacOSSetup: macOSSetup,
+ EnableDiskEncryption: enableDiskEncryption,
+ MacOSUpdates: spec.MDM.MacOSUpdates,
+ MacOSSettings: macOSSettings,
+ MacOSSetup: macOSSetup,
},
},
Secrets: secrets,
@@ -824,7 +836,7 @@ func (svc *Service) createTeamFromSpec(
return nil, err
}
- if macOSSettings.EnableDiskEncryption {
+ if enableDiskEncryption && defaults.MDM.EnabledAndConfigured {
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &tm.ID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "enable team filevault and escrow")
}
@@ -871,11 +883,23 @@ func (svc *Service) editTeamFromSpec(
team.Config.MDM.MacOSUpdates = spec.MDM.MacOSUpdates
}
- oldMacOSDiskEncryption := team.Config.MDM.MacOSSettings.EnableDiskEncryption
+ oldMacOSDiskEncryption := team.Config.MDM.EnableDiskEncryption
if err := svc.applyTeamMacOSSettings(ctx, spec, &team.Config.MDM.MacOSSettings); err != nil {
return err
}
- newMacOSDiskEncryption := team.Config.MDM.MacOSSettings.EnableDiskEncryption
+
+ // 1. if the spec has the new setting, use that
+ // 2. else if the spec has the deprecated setting, use that
+ // 3. otherwise, leave the setting untouched
+ if spec.MDM.EnableDiskEncryption.Valid {
+ team.Config.MDM.EnableDiskEncryption = spec.MDM.EnableDiskEncryption.Value
+ } else if de := team.Config.MDM.MacOSSettings.DeprecatedEnableDiskEncryption; de != nil {
+ team.Config.MDM.EnableDiskEncryption = *de
+ }
+ if team.Config.MDM.EnableDiskEncryption && !appCfg.MDM.AtLeastOnePlatformEnabledAndConfigured() {
+ return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("mdm",
+ `Couldn't edit enable_disk_encryption. Neither macOS MDM nor Windows is turned on. Visit https://fleetdm.com/docs/using-fleet to learn how to turn on MDM.`))
+ }
oldMacOSSetup := team.Config.MDM.MacOSSetup
if spec.MDM.MacOSSetup.MacOSSetupAssistant.Set || spec.MDM.MacOSSetup.BootstrapPackage.Set {
@@ -925,9 +949,9 @@ func (svc *Service) editTeamFromSpec(
return err
}
}
- if oldMacOSDiskEncryption != newMacOSDiskEncryption {
+ if appCfg.MDM.EnabledAndConfigured && oldMacOSDiskEncryption != team.Config.MDM.EnableDiskEncryption {
var act fleet.ActivityDetails
- if team.Config.MDM.MacOSSettings.EnableDiskEncryption {
+ if team.Config.MDM.EnableDiskEncryption {
act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &team.ID, TeamName: &team.Name}
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &team.ID); err != nil {
return ctxerr.Wrap(ctx, err, "enable team filevault and escrow")
@@ -982,7 +1006,7 @@ func (svc *Service) applyTeamMacOSSettings(ctx context.Context, spec *fleet.Team
}
if (setFields["custom_settings"] && len(applyUpon.CustomSettings) > 0) ||
- (setFields["enable_disk_encryption"] && applyUpon.EnableDiskEncryption) {
+ (setFields["enable_disk_encryption"] && *applyUpon.DeprecatedEnableDiskEncryption) {
field := "custom_settings"
if !setFields["custom_settings"] {
field = "enable_disk_encryption"
@@ -1016,8 +1040,8 @@ func unmarshalWithGlobalDefaults(b *json.RawMessage) (fleet.Features, error) {
func (svc *Service) updateTeamMDMAppleSettings(ctx context.Context, tm *fleet.Team, payload fleet.MDMAppleSettingsPayload) error {
var didUpdate, didUpdateMacOSDiskEncryption bool
if payload.EnableDiskEncryption != nil {
- if tm.Config.MDM.MacOSSettings.EnableDiskEncryption != *payload.EnableDiskEncryption {
- tm.Config.MDM.MacOSSettings.EnableDiskEncryption = *payload.EnableDiskEncryption
+ if tm.Config.MDM.EnableDiskEncryption != *payload.EnableDiskEncryption {
+ tm.Config.MDM.EnableDiskEncryption = *payload.EnableDiskEncryption
didUpdate = true
didUpdateMacOSDiskEncryption = true
}
@@ -1029,7 +1053,7 @@ func (svc *Service) updateTeamMDMAppleSettings(ctx context.Context, tm *fleet.Te
}
if didUpdateMacOSDiskEncryption {
var act fleet.ActivityDetails
- if tm.Config.MDM.MacOSSettings.EnableDiskEncryption {
+ 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")
diff --git a/frontend/__mocks__/configMock.ts b/frontend/__mocks__/configMock.ts
index 9f9e8f638cca..7b5131a2da52 100644
--- a/frontend/__mocks__/configMock.ts
+++ b/frontend/__mocks__/configMock.ts
@@ -126,6 +126,7 @@ const DEFAULT_CONFIG_MOCK: IConfig = {
},
fleet_desktop: { transparency_url: "https://fleetdm.com/transparency" },
mdm: {
+ enable_disk_encryption: false,
windows_enabled_and_configured: true,
apple_bm_default_team: "Apples",
apple_bm_enabled_and_configured: true,
diff --git a/frontend/__mocks__/hostMock.ts b/frontend/__mocks__/hostMock.ts
index c2e0993649e2..6834d0c7037a 100644
--- a/frontend/__mocks__/hostMock.ts
+++ b/frontend/__mocks__/hostMock.ts
@@ -1,7 +1,7 @@
import { IHost } from "interfaces/host";
-import { IHostMacMdmProfile } from "interfaces/mdm";
+import { IHostMdmProfile } from "interfaces/mdm";
-const DEFAULT_HOST_PROFILE_MOCK: IHostMacMdmProfile = {
+const DEFAULT_HOST_PROFILE_MOCK: IHostMdmProfile = {
profile_id: 1,
name: "Test Profile",
operation_type: "install",
@@ -10,8 +10,8 @@ const DEFAULT_HOST_PROFILE_MOCK: IHostMacMdmProfile = {
};
export const createMockHostMacMdmProfile = (
- overrides?: Partial
-): IHostMacMdmProfile => {
+ overrides?: Partial
+): IHostMdmProfile => {
return { ...DEFAULT_HOST_PROFILE_MOCK, ...overrides };
};
@@ -53,6 +53,11 @@ const DEFAULT_HOST_MOCK: IHost = {
enrollment_status: "Off",
server_url: "https://www.example.com/1",
profiles: [],
+ os_settings: {
+ disk_encryption: {
+ status: null,
+ },
+ },
macos_settings: {
disk_encryption: null,
action_required: null,
diff --git a/frontend/__mocks__/mdmMock.ts b/frontend/__mocks__/mdmMock.ts
index c0584bf66aaf..5ffebcdbc30d 100644
--- a/frontend/__mocks__/mdmMock.ts
+++ b/frontend/__mocks__/mdmMock.ts
@@ -36,6 +36,11 @@ const DEFAULT_HOST_MDM_DATA: IHostMdmData = {
name: "MDM Solution",
id: 1,
profiles: [],
+ os_settings: {
+ disk_encryption: {
+ status: "verified",
+ },
+ },
macos_settings: {
disk_encryption: null,
action_required: null,
diff --git a/frontend/components/InfoBanner/InfoBanner.tsx b/frontend/components/InfoBanner/InfoBanner.tsx
index f1af1558b52c..1e02b38b6e21 100644
--- a/frontend/components/InfoBanner/InfoBanner.tsx
+++ b/frontend/components/InfoBanner/InfoBanner.tsx
@@ -3,6 +3,7 @@ import classNames from "classnames";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
+import { IconNames } from "components/icons";
const baseClass = "info-banner";
@@ -11,28 +12,36 @@ export interface IInfoBannerProps {
className?: string;
/** default light purple */
color?: "purple" | "purple-bold-border" | "yellow" | "grey";
+ /** default 4px */
+ borderRadius?: "large" | "xlarge";
pageLevel?: boolean;
/** cta and link are mutually exclusive */
cta?: JSX.Element;
/** closable and link are mutually exclusive */
closable?: boolean;
link?: string;
+ icon?: IconNames;
}
const InfoBanner = ({
children,
className,
color = "purple",
+ borderRadius,
pageLevel,
cta,
closable,
link,
+ icon,
}: IInfoBannerProps): JSX.Element => {
const wrapperClasses = classNames(
baseClass,
`${baseClass}__${color}`,
{
+ [`${baseClass}__${color}`]: !!color,
+ [`${baseClass}__border-radius-${borderRadius}`]: !!borderRadius,
[`${baseClass}__page-banner`]: !!pageLevel,
+ [`${baseClass}__icon`]: !!icon,
},
className
);
@@ -42,6 +51,7 @@ const InfoBanner = ({
const content = (
<>
{children}
+
{(cta || closable) && (
{cta}
diff --git a/frontend/components/InfoBanner/_styles.scss b/frontend/components/InfoBanner/_styles.scss
index f5977b57f5c3..81635a106270 100644
--- a/frontend/components/InfoBanner/_styles.scss
+++ b/frontend/components/InfoBanner/_styles.scss
@@ -34,6 +34,20 @@
width: auto;
}
+ &__border-radius-large {
+ border-radius: $border-radius-large;
+ }
+
+ &__border-radius-xlarge {
+ border-radius: $border-radius-xlarge;
+ }
+
+ &__info {
+ display: flex;
+ flex-direction: column;
+ gap: $pad-small;
+ }
+
&__cta {
display: flex;
align-items: center;
@@ -59,4 +73,8 @@
}
}
}
+
+ p {
+ margin: 0;
+ }
}
diff --git a/frontend/components/StatusIndicatorWithIcon/StatusIndicatorWithIcon.tsx b/frontend/components/StatusIndicatorWithIcon/StatusIndicatorWithIcon.tsx
index e510748a7a35..95ae8d5659e6 100644
--- a/frontend/components/StatusIndicatorWithIcon/StatusIndicatorWithIcon.tsx
+++ b/frontend/components/StatusIndicatorWithIcon/StatusIndicatorWithIcon.tsx
@@ -23,7 +23,10 @@ interface IStatusIndicatorWithIconProps {
tooltipText: string | JSX.Element;
position?: "top" | "bottom";
};
+ layout?: "horizontal" | "vertical";
className?: string;
+ /** Classname to add to the value text */
+ valueClassName?: string;
}
const statusIconNameMapping: Record = {
@@ -38,13 +41,18 @@ const StatusIndicatorWithIcon = ({
status,
value,
tooltip,
+ layout = "horizontal",
className,
+ valueClassName,
}: IStatusIndicatorWithIconProps) => {
const classNames = classnames(baseClass, className);
const id = `status-${uniqueId()}`;
+ const valueClasses = classnames(`${baseClass}__value`, valueClassName, {
+ [`${baseClass}__value-vertical`]: layout === "vertical",
+ });
const valueContent = (
-
+ {value}
diff --git a/frontend/components/StatusIndicatorWithIcon/_styles.scss b/frontend/components/StatusIndicatorWithIcon/_styles.scss
index 6dea8de69713..12d60c0f2d63 100644
--- a/frontend/components/StatusIndicatorWithIcon/_styles.scss
+++ b/frontend/components/StatusIndicatorWithIcon/_styles.scss
@@ -1,4 +1,5 @@
.status-indicator-with-icon {
+ // default layout is horizontal
&__value {
display: inline-flex;
align-items: center;
@@ -8,4 +9,10 @@
margin-right: $pad-xsmall;
}
}
+
+ // overrides for different layout
+ &__value-vertical {
+ flex-direction: column;
+ gap: $pad-xsmall;
+ }
}
diff --git a/frontend/interfaces/config.ts b/frontend/interfaces/config.ts
index 1d42508ee4b2..cf15ccca6463 100644
--- a/frontend/interfaces/config.ts
+++ b/frontend/interfaces/config.ts
@@ -1,95 +1,11 @@
/* Config interface is a flattened version of the fleet/config API response */
-
import {
IWebhookHostStatus,
IWebhookFailingPolicies,
IWebhookSoftwareVulnerabilities,
} from "interfaces/webhook";
-import PropTypes from "prop-types";
import { IIntegrations } from "./integration";
-export default PropTypes.shape({
- org_name: PropTypes.string,
- org_logo_url: PropTypes.string,
- contact_url: PropTypes.string,
- server_url: PropTypes.string,
- live_query_disabled: PropTypes.bool,
- enable_analytics: PropTypes.bool,
- enable_smtp: PropTypes.bool,
- configured: PropTypes.bool,
- sender_address: PropTypes.string,
- server: PropTypes.string,
- port: PropTypes.number,
- authentication_type: PropTypes.string,
- user_name: PropTypes.string,
- password: PropTypes.string,
- enable_ssl_tls: PropTypes.bool,
- authentication_method: PropTypes.string,
- domain: PropTypes.string,
- verify_sll_certs: PropTypes.bool,
- enable_start_tls: PropTypes.bool,
- entity_id: PropTypes.string,
- idp_image_url: PropTypes.string,
- metadata: PropTypes.string,
- metadata_url: PropTypes.string,
- idp_name: PropTypes.string,
- enable_sso: PropTypes.bool,
- enable_sso_idp_login: PropTypes.bool,
- enable_jit_provisioning: PropTypes.bool,
- host_expiry_enabled: PropTypes.bool,
- host_expiry_window: PropTypes.number,
- agent_options: PropTypes.string,
- tier: PropTypes.string,
- organization: PropTypes.string,
- device_count: PropTypes.number,
- expiration: PropTypes.string,
- mdm: PropTypes.shape({
- enabled_and_configured: PropTypes.bool,
- apple_bm_terms_expired: PropTypes.bool,
- apple_bm_enabled_and_configured: PropTypes.bool,
- windows_enabled_and_configured: PropTypes.bool,
- macos_updates: PropTypes.shape({
- minimum_version: PropTypes.string,
- deadline: PropTypes.string,
- }),
- }),
- note: PropTypes.string,
- // vulnerability_settings: PropTypes.any, TODO
- enable_host_status_webhook: PropTypes.bool,
- destination_url: PropTypes.string,
- host_percentage: PropTypes.number,
- days_count: PropTypes.number,
- logging: PropTypes.shape({
- debug: PropTypes.bool,
- json: PropTypes.bool,
- result: PropTypes.shape({
- plugin: PropTypes.string,
- config: PropTypes.shape({
- status_log_file: PropTypes.string,
- result_log_file: PropTypes.string,
- enable_log_rotation: PropTypes.bool,
- enable_log_compression: PropTypes.bool,
- }),
- }),
- status: PropTypes.shape({
- plugin: PropTypes.string,
- config: PropTypes.shape({
- status_log_file: PropTypes.string,
- result_log_file: PropTypes.string,
- enable_log_rotation: PropTypes.bool,
- enable_log_compression: PropTypes.bool,
- }),
- }),
- }),
- email: PropTypes.shape({
- backend: PropTypes.string,
- config: PropTypes.shape({
- region: PropTypes.string,
- source_arn: PropTypes.string,
- }),
- }),
-});
-
export interface ILicense {
tier: string;
device_count: number;
@@ -113,6 +29,7 @@ export interface IMacOsMigrationSettings {
}
export interface IMdmConfig {
+ enable_disk_encryption: boolean;
enabled_and_configured: boolean;
apple_bm_default_team?: string;
apple_bm_terms_expired: boolean;
@@ -286,7 +203,10 @@ export interface IConfig {
};
};
mdm: IMdmConfig;
- mdm_enabled?: boolean; // TODO: remove when windows MDM is released. Only used for windows MDM dev currently.
+ /** This is the flag that determines if the windwos mdm feature flag is enabled.
+ TODO: WINDOWS FEATURE FLAG: remove when windows MDM is released. Only used for windows MDM dev currently.
+ */
+ mdm_enabled?: boolean;
}
export interface IWebhookSettings {
diff --git a/frontend/interfaces/host.ts b/frontend/interfaces/host.ts
index 1927351b7dd8..ebfde247f461 100644
--- a/frontend/interfaces/host.ts
+++ b/frontend/interfaces/host.ts
@@ -8,9 +8,10 @@ import hostQueryResult from "./campaign";
import queryStatsInterface, { IQueryStats } from "./query_stats";
import { ILicense, IDeviceGlobalConfig } from "./config";
import {
- IHostMacMdmProfile,
+ IHostMdmProfile,
MdmEnrollmentStatus,
BootstrapPackageStatus,
+ DiskEncryptionStatus,
} from "./mdm";
export default PropTypes.shape({
@@ -90,18 +91,16 @@ export interface IMunkiData {
version: string;
}
-type MacDiskEncryptionState =
- | "applied"
- | "action_required"
- | "enforcing"
- | "failed"
- | "removing_enforcement"
- | null;
-
type MacDiskEncryptionActionRequired = "log_out" | "rotate_key" | null;
+export interface IOSSettings {
+ disk_encryption: {
+ status: DiskEncryptionStatus | null;
+ };
+}
+
interface IMdmMacOsSettings {
- disk_encryption: MacDiskEncryptionState | null;
+ disk_encryption: DiskEncryptionStatus | null;
action_required: MacDiskEncryptionActionRequired | null;
}
@@ -117,7 +116,8 @@ export interface IHostMdmData {
name?: string;
server_url: string | null;
id?: number;
- profiles: IHostMacMdmProfile[] | null;
+ profiles: IHostMdmProfile[] | null;
+ os_settings?: IOSSettings;
macos_settings?: IMdmMacOsSettings;
macos_setup?: IMdmMacOsSetup;
}
@@ -210,7 +210,7 @@ export interface IHost {
osquery_version: string;
os_version: string;
build: string;
- platform_like: string;
+ platform_like: string; // TODO: replace with more specific union type
code_name: string;
uptime: number;
memory: number;
diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts
index 25f0f0d7ec8b..1120e1ab625c 100644
--- a/frontend/interfaces/mdm.ts
+++ b/frontend/interfaces/mdm.ts
@@ -22,8 +22,6 @@ export const MDM_ENROLLMENT_STATUS = {
export type MdmEnrollmentStatus = keyof typeof MDM_ENROLLMENT_STATUS;
-export type ProfileSummaryResponse = Record;
-
export interface IMdmStatusCardData {
status: MdmEnrollmentStatus;
hosts: number;
@@ -74,16 +72,15 @@ export type MdmProfileStatus = "verified" | "verifying" | "pending" | "failed";
export type MacMdmProfileOperationType = "remove" | "install";
-export interface IHostMacMdmProfile {
+export interface IHostMdmProfile {
profile_id: number;
name: string;
- // identifier?: string; // TODO: add when API is updated to return this
- operation_type: MacMdmProfileOperationType;
+ operation_type: MacMdmProfileOperationType | null;
status: MdmProfileStatus;
detail: string;
}
-export type FileVaultProfileStatus =
+export type DiskEncryptionStatus =
| "verified"
| "verifying"
| "action_required"
@@ -91,9 +88,18 @@ export type FileVaultProfileStatus =
| "failed"
| "removing_enforcement";
-// // TODO: update when list profiles API returns identifier
-// export const FLEET_FILEVAULT_PROFILE_IDENTIFIER =
-// "com.fleetdm.fleet.mdm.filevault";
+/** Currently windows disk enxryption status will only be one of these four
+values. In the future we may add more. */
+export type IWindowsDiskEncryptionStatus = Extract<
+ DiskEncryptionStatus,
+ "verified" | "verifying" | "enforcing" | "failed"
+>;
+
+export const isWindowsDiskEncryptionStatus = (
+ status: DiskEncryptionStatus
+): status is IWindowsDiskEncryptionStatus => {
+ return !["action_required", "removing_enforcement"].includes(status);
+};
export const FLEET_FILEVAULT_PROFILE_DISPLAY_NAME = "Disk encryption";
diff --git a/frontend/interfaces/team.ts b/frontend/interfaces/team.ts
index 3c06c11c36c8..4487dba48d86 100644
--- a/frontend/interfaces/team.ts
+++ b/frontend/interfaces/team.ts
@@ -44,6 +44,7 @@ export interface ITeam extends ITeamSummary {
secrets?: IEnrollSecret[];
role?: UserRole; // role value is included when the team is in the context of a user
mdm?: {
+ enable_disk_encryption: boolean;
macos_updates: {
minimum_version: string;
deadline: string;
diff --git a/frontend/pages/LoginSuccessfulPage/_styles.scss b/frontend/pages/LoginSuccessfulPage/_styles.scss
index 07e1429fa755..b3b962d3c9b9 100644
--- a/frontend/pages/LoginSuccessfulPage/_styles.scss
+++ b/frontend/pages/LoginSuccessfulPage/_styles.scss
@@ -3,7 +3,7 @@
margin-top: 20px;
padding: $pad-xxlarge;
text-align: center;
- border-radius: 10px;
+ border-radius: $border-radius-xlarge;
z-index: 0;
align-self: center;
transform: translateY(80px);
diff --git a/frontend/pages/ManageControlsPage/OSSettings/AggregateMacSettingsIndicators/AggregateMacSettingsIndicators.tsx b/frontend/pages/ManageControlsPage/OSSettings/AggregateMacSettingsIndicators/AggregateMacSettingsIndicators.tsx
deleted file mode 100644
index 7c4b4906011b..000000000000
--- a/frontend/pages/ManageControlsPage/OSSettings/AggregateMacSettingsIndicators/AggregateMacSettingsIndicators.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import React from "react";
-
-import paths from "router/paths";
-import { buildQueryStringFromParams } from "utilities/url";
-import { MdmProfileStatus, ProfileSummaryResponse } from "interfaces/mdm";
-import MacSettingsIndicator from "pages/hosts/details/MacSettingsIndicator";
-
-import { IconNames } from "components/icons";
-import Spinner from "components/Spinner";
-
-const baseClass = "aggregate-mac-settings-indicators";
-
-interface IAggregateDisplayOption {
- value: MdmProfileStatus;
- text: string;
- iconName: IconNames;
- tooltipText: string;
-}
-
-const AGGREGATE_STATUS_DISPLAY_OPTIONS: IAggregateDisplayOption[] = [
- {
- value: "verified",
- text: "Verified",
- iconName: "success",
- tooltipText:
- "These hosts installed all configuration profiles. Fleet verified with osquery.",
- },
- {
- value: "verifying",
- text: "Verifying",
- iconName: "success-partial",
- tooltipText:
- "These hosts acknowledged all MDM commands to install configuration profiles. " +
- "Fleet is verifying the profiles are installed with osquery.",
- },
- {
- value: "pending",
- text: "Pending",
- iconName: "pending-partial",
- tooltipText:
- "These hosts will receive MDM commands to install configuration profiles when the hosts come online.",
- },
- {
- value: "failed",
- text: "Failed",
- iconName: "error",
- tooltipText:
- "These hosts failed to install configuration profiles. Click on a host to view error(s).",
- },
-];
-
-interface AggregateMacSettingsIndicatorsProps {
- isLoading: boolean;
- teamId: number;
- aggregateProfileStatusData?: ProfileSummaryResponse;
-}
-
-const AggregateMacSettingsIndicators = ({
- isLoading,
- teamId,
- aggregateProfileStatusData,
-}: AggregateMacSettingsIndicatorsProps) => {
- const indicators = AGGREGATE_STATUS_DISPLAY_OPTIONS.map((status) => {
- if (!aggregateProfileStatusData) return null;
-
- const { value, text, iconName, tooltipText } = status;
- const count = aggregateProfileStatusData[value];
-
- return (
-
;
+};
+
+export default ProfileStatusAggregate;
diff --git a/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts
new file mode 100644
index 000000000000..8dbe94abf8fe
--- /dev/null
+++ b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts
@@ -0,0 +1,43 @@
+import { MdmProfileStatus } from "interfaces/mdm";
+import { IndicatorStatus } from "components/StatusIndicatorWithIcon/StatusIndicatorWithIcon";
+
+interface IAggregateDisplayOption {
+ value: MdmProfileStatus;
+ text: string;
+ iconName: IndicatorStatus;
+ tooltipText: string;
+}
+
+const AGGREGATE_STATUS_DISPLAY_OPTIONS: IAggregateDisplayOption[] = [
+ {
+ value: "verified",
+ text: "Verified",
+ iconName: "success",
+ tooltipText:
+ "These hosts applied all OS settings. Fleet verified with osquery.",
+ },
+ {
+ value: "verifying",
+ text: "Verifying",
+ iconName: "successPartial",
+ tooltipText:
+ "These hosts acknowledged all MDM commands to apply OS settings. " +
+ "Fleet is verifying the OS settings are applied with osquery.",
+ },
+ {
+ value: "pending",
+ text: "Pending",
+ iconName: "pendingPartial",
+ tooltipText:
+ "These hosts will receive MDM command to apply OS settings when the host come online.",
+ },
+ {
+ value: "failed",
+ text: "Failed",
+ iconName: "error",
+ tooltipText:
+ "These host failed to apply the latest OS settings. Click on a host to view error(s).",
+ },
+];
+
+export default AGGREGATE_STATUS_DISPLAY_OPTIONS;
diff --git a/frontend/pages/ManageControlsPage/OSSettings/AggregateMacSettingsIndicators/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/_styles.scss
similarity index 73%
rename from frontend/pages/ManageControlsPage/OSSettings/AggregateMacSettingsIndicators/_styles.scss
rename to frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/_styles.scss
index 76659544939a..89744cf6cc71 100644
--- a/frontend/pages/ManageControlsPage/OSSettings/AggregateMacSettingsIndicators/_styles.scss
+++ b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/_styles.scss
@@ -1,16 +1,16 @@
-.aggregate-mac-settings-indicators {
+.profile-status-aggregate {
display: flex;
height: 94px;
border-top: 1px solid #e2e4ea;
border-bottom: 1px solid #e2e4ea;
border-left: 1px solid #e2e4ea;
- border-radius: 6px;
+ border-radius: $border-radius-large;
&__loading-spinner {
margin: auto;
}
- .aggregate-mac-settings-indicator {
+ &__profile-status-count {
flex-grow: 1;
display: flex;
@@ -29,13 +29,17 @@
font-weight: $regular;
}
- .settings-indicator {
+ .profile-status-indicator {
flex-direction: column;
}
}
- .aggregate-mac-settings-indicator:last-child {
+ &__profile-status-count:last-child {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
}
+
+ &__status-indicator-value {
+ font-weight: $bold;
+ }
}
diff --git a/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/index.ts b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/index.ts
new file mode 100644
index 000000000000..a29bd5e10d5f
--- /dev/null
+++ b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/index.ts
@@ -0,0 +1 @@
+export { default } from "./ProfileStatusAggregate";
diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/DiskEncryption.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/DiskEncryption.tsx
index 6edd4f35f5f2..c8cd1d2bc37b 100644
--- a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/DiskEncryption.tsx
+++ b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/DiskEncryption.tsx
@@ -31,7 +31,7 @@ const DiskEncryption = ({
const defaultShowDiskEncryption = currentTeamId
? false
- : config?.mdm.macos_settings.enable_disk_encryption ?? false;
+ : config?.mdm.enable_disk_encryption ?? false;
const [isLoadingTeam, setIsLoadingTeam] = useState(true);
@@ -67,8 +67,7 @@ const DiskEncryption = ({
enabled: currentTeamId !== 0,
select: (res) => res.team,
onSuccess: (res) => {
- const enableDiskEncryption =
- res.mdm?.macos_settings.enable_disk_encryption ?? false;
+ const enableDiskEncryption = res.mdm?.enable_disk_encryption ?? false;
setDiskEncryptionEnabled(enableDiskEncryption);
setShowAggregate(enableDiskEncryption);
setIsLoadingTeam(false);
@@ -100,6 +99,19 @@ const DiskEncryption = ({
setIsLoadingTeam(false);
}
+ const createDescriptionText = () => {
+ // table is showing disk encryption status.
+ if (showAggregate) {
+ return "If turned on, hosts' disk encryption keys will be stored in Fleet. ";
+ }
+
+ const isWindowsFeatureFlagEnabled = config?.mdm_enabled ?? false;
+ const dynamicText = isWindowsFeatureFlagEnabled
+ ? " and “BitLocker” on Windows"
+ : "";
+ return `Also known as “FileVault” on macOS${dynamicText}. If turned on, hosts' disk encryption keys will be stored in Fleet. `;
+ };
+
return (
Disk encryption
@@ -124,8 +136,7 @@ const DiskEncryption = ({
On
- Apple calls this “FileVault.” If turned on, hosts' disk
- encryption keys will be stored in Fleet.{" "}
+ {createDescriptionText()}
{
+ const { config } = useContext(AppContext);
+
const {
data: diskEncryptionStatusData,
error: diskEncryptionStatusError,
- } = useQuery(
+ } = useQuery(
["disk-encryption-summary", currentTeamId],
- () => mdmAPI.getDiskEncryptionAggregate(currentTeamId),
+ () => mdmAPI.getDiskEncryptionSummary(currentTeamId),
{
refetchOnWindowFocus: false,
retry: false,
}
);
- const tableHeaders = generateTableHeaders();
-
- const tableData = generateTableData(diskEncryptionStatusData, currentTeamId);
+ // TODO: WINDOWS FEATURE FLAG: remove this when windows feature flag is removed.
+ // this is used to conditianlly show "View all hosts" link in table cells.
+ const windowsFeatureFlagEnabled = config?.mdm_enabled ?? false;
+ const tableHeaders = generateTableHeaders(windowsFeatureFlagEnabled);
+ const tableData = generateTableData(
+ windowsFeatureFlagEnabled,
+ diskEncryptionStatusData,
+ currentTeamId
+ );
if (diskEncryptionStatusError) {
return ;
@@ -53,8 +59,7 @@ const DiskEncryptionTable = ({ currentTeamId }: IDiskEncryptionTableProps) => {
isLoading={false}
showMarkAllPages={false}
isAllPagesSelected={false}
- defaultSortHeader={DEFAULT_SORT_HEADER}
- defaultSortDirection={DEFAULT_SORT_DIRECTION}
+ manualSortBy
disableTableHeader
disablePagination
disableCount
diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/DiskEncryptionTableConfig.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/DiskEncryptionTableConfig.tsx
index 068459d69cfb..9a5b7baf5dbe 100644
--- a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/DiskEncryptionTableConfig.tsx
+++ b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/DiskEncryptionTableConfig.tsx
@@ -1,7 +1,11 @@
import React from "react";
-import { FileVaultProfileStatus } from "interfaces/mdm";
-import { IFileVaultSummaryResponse } from "services/entities/mdm";
+import { DiskEncryptionStatus } from "interfaces/mdm";
+import {
+ IDiskEncryptionStatusAggregate,
+ IDiskEncryptionSummaryResponse,
+} from "services/entities/mdm";
+import { DISK_ENCRYPTION_QUERY_PARAM_NAME } from "services/entities/hosts";
import TextCell from "components/TableContainer/DataTable/TextCell";
import HeaderCell from "components/TableContainer/DataTable/HeaderCell";
@@ -12,7 +16,7 @@ import { IndicatorStatus } from "components/StatusIndicatorWithIcon/StatusIndica
interface IStatusCellValue {
displayName: string;
statusName: IndicatorStatus;
- value: FileVaultProfileStatus;
+ value: DiskEncryptionStatus;
tooltip?: string | JSX.Element;
}
@@ -28,6 +32,7 @@ interface ICellProps {
};
row: {
original: {
+ includeWindows: boolean;
status: IStatusCellValue;
teamId: number;
};
@@ -72,15 +77,53 @@ const defaultTableHeaders: IDataColumn[] = [
},
},
{
- title: "Hosts",
+ title: "macOS hosts",
Header: (cellProps: IHeaderProps) => (
),
- accessor: "hosts",
+ disableSortBy: true,
+ accessor: "macosHosts",
+ Cell: ({
+ cell: { value: aggregateCount },
+ row: { original },
+ }: ICellProps) => {
+ return (
+
+ <>{val}>} />
+ {/* TODO: WINDOWS FEATURE FLAG: remove this conditional when windows mdm
+ is released. the view all UI will show in the windows column when we
+ release the feature. */}
+ {!original.includeWindows && (
+
+ )}
+
+ );
+ },
+ },
+];
+
+const windowsTableHeader: IDataColumn[] = [
+ {
+ title: "Windows hosts",
+ Header: (cellProps: IHeaderProps) => (
+
+ ),
+ disableSortBy: true,
+ accessor: "windowsHosts",
Cell: ({
cell: { value: aggregateCount },
row: { original },
@@ -91,7 +134,7 @@ const defaultTableHeaders: IDataColumn[] = [
@@ -101,15 +144,17 @@ const defaultTableHeaders: IDataColumn[] = [
},
];
-type StatusNames = keyof IFileVaultSummaryResponse;
-
-type StatusEntry = [StatusNames, number];
-
-export const generateTableHeaders = (): IDataColumn[] => {
+// TODO: WINDOWS FEATURE FLAG: return all headers when windows feature flag is removed.
+export const generateTableHeaders = (
+ includeWindows: boolean
+): IDataColumn[] => {
+ return includeWindows
+ ? [...defaultTableHeaders, ...windowsTableHeader]
+ : defaultTableHeaders;
return defaultTableHeaders;
};
-const STATUS_CELL_VALUES: Record = {
+const STATUS_CELL_VALUES: Record = {
verified: {
displayName: "Verified",
statusName: "success",
@@ -122,8 +167,8 @@ const STATUS_CELL_VALUES: Record = {
statusName: "successPartial",
value: "verifying",
tooltip:
- "These hosts acknowledged the MDM command to install disk encryption profile. " +
- "Fleet is verifying with osquery and retrieving the disk encryption key. This may take up to one hour.",
+ "These hosts acknowledged the MDM command to turn on disk encryption. Fleet is verifying with " +
+ "osquery and retrieving the disk encryption key. This may take up to one hour.",
},
action_required: {
displayName: "Action required (pending)",
@@ -141,7 +186,7 @@ const STATUS_CELL_VALUES: Record = {
statusName: "pendingPartial",
value: "enforcing",
tooltip:
- "These hosts will receive the MDM command to install the disk encryption profile when the hosts come online.",
+ "These hosts will receive the MDM command to turn on disk encryption when the hosts come online.",
},
failed: {
displayName: "Failed",
@@ -153,21 +198,41 @@ const STATUS_CELL_VALUES: Record = {
statusName: "pendingPartial",
value: "removing_enforcement",
tooltip:
- "These hosts will receive the MDM command to remove the disk encryption profile when the hosts come online.",
+ "These hosts will receive the MDM command to turn off disk encryption when the hosts come online.",
},
};
+type StatusEntry = [DiskEncryptionStatus, IDiskEncryptionStatusAggregate];
+
+// Order of the status column. We want the order to always be the same.
+const STATUS_ORDER = [
+ "verified",
+ "verifying",
+ "failed",
+ "action_required",
+ "enforcing",
+ "removing_enforcement",
+] as const;
+
export const generateTableData = (
- data?: IFileVaultSummaryResponse,
+ // TODO: WINDOWS FEATURE FLAG: remove includeWindows when windows feature flag is removed.
+ // This is used to conditionally show "View all hosts" link in table cells.
+ includeWindows: boolean,
+ data?: IDiskEncryptionSummaryResponse,
currentTeamId?: number
) => {
if (!data) return [];
- const entries = Object.entries(data) as StatusEntry[];
- return entries.map(([status, numHosts]) => ({
- // eslint-disable-next-line object-shorthand
+ const rowFromStatusEntry = (
+ status: DiskEncryptionStatus,
+ statusAggregate: IDiskEncryptionStatusAggregate
+ ) => ({
+ includeWindows,
status: STATUS_CELL_VALUES[status],
- hosts: numHosts,
+ macosHosts: statusAggregate.macos,
+ windowsHosts: statusAggregate.windows,
teamId: currentTeamId,
- }));
+ });
+
+ return STATUS_ORDER.map((status) => rowFromStatusEntry(status, data[status]));
};
diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss
index ee3e1c025ea8..c2e35efe6b8b 100644
--- a/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss
+++ b/frontend/pages/ManageControlsPage/OSSettings/cards/DiskEncryption/components/DiskEncryptionTable/_styles.scss
@@ -1,7 +1,4 @@
.disk-encryption-table {
- padding: $pad-xxlarge;
- border: 1px solid $ui-fleet-black-10;
- border-radius: $border-radius;
margin-bottom: $pad-xxlarge;
.data-table-block .data-table tbody td .w250 {
diff --git a/frontend/pages/ManageControlsPage/components/TurnOnMdmMessage/TurnOnMdmMessage.tsx b/frontend/pages/ManageControlsPage/components/TurnOnMdmMessage/TurnOnMdmMessage.tsx
index 545887a8f5d2..ce052c31e180 100644
--- a/frontend/pages/ManageControlsPage/components/TurnOnMdmMessage/TurnOnMdmMessage.tsx
+++ b/frontend/pages/ManageControlsPage/components/TurnOnMdmMessage/TurnOnMdmMessage.tsx
@@ -30,7 +30,7 @@ const TurnOnMdmMessage = ({ router }: ITurnOnMdmMessageProps) => {
return (
diff --git a/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx b/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx
index 2fbaac795a75..b4102d321e83 100644
--- a/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/HostsPageConfig.tsx
@@ -1,6 +1,7 @@
import React from "react";
import Icon from "components/Icon";
+import { DISK_ENCRYPTION_QUERY_PARAM_NAME } from "services/entities/hosts";
export const MANAGE_HOSTS_PAGE_FILTER_KEYS = [
"query",
@@ -17,7 +18,7 @@ export const MANAGE_HOSTS_PAGE_FILTER_KEYS = [
"os_version",
"munki_issue_id",
"low_disk_space",
- "macos_settings_disk_encryption",
+ DISK_ENCRYPTION_QUERY_PARAM_NAME,
"bootstrap_package",
] as const;
diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
index ab6a3b4debcd..6eedf30627c1 100644
--- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
@@ -18,6 +18,7 @@ import labelsAPI, { ILabelsResponse } from "services/entities/labels";
import teamsAPI, { ILoadTeamsResponse } from "services/entities/teams";
import globalPoliciesAPI from "services/entities/global_policies";
import hostsAPI, {
+ DISK_ENCRYPTION_QUERY_PARAM_NAME,
ILoadHostsQueryKey,
ILoadHostsResponse,
ISortOption,
@@ -49,7 +50,7 @@ import { IOperatingSystemVersion } from "interfaces/operating_system";
import { IPolicy, IStoredPolicyResponse } from "interfaces/policy";
import { ITeam } from "interfaces/team";
import { IEmptyTableProps } from "interfaces/empty_table";
-import { FileVaultProfileStatus, BootstrapPackageStatus } from "interfaces/mdm";
+import { DiskEncryptionStatus, BootstrapPackageStatus } from "interfaces/mdm";
import sortUtils from "utilities/sort";
import {
@@ -232,8 +233,8 @@ const ManageHostsPage = ({
? parseInt(queryParams.low_disk_space, 10)
: undefined;
const missingHosts = queryParams?.status === "missing";
- const diskEncryptionStatus: FileVaultProfileStatus | undefined =
- queryParams?.macos_settings_disk_encryption;
+ const diskEncryptionStatus: DiskEncryptionStatus | undefined =
+ queryParams?.[DISK_ENCRYPTION_QUERY_PARAM_NAME];
const bootstrapPackageStatus: BootstrapPackageStatus | undefined =
queryParams?.bootstrap_package;
@@ -558,7 +559,7 @@ const ManageHostsPage = ({
};
const handleChangeDiskEncryptionStatusFilter = (
- newStatus: FileVaultProfileStatus
+ newStatus: DiskEncryptionStatus
) => {
handleResetPageIndex();
@@ -569,7 +570,7 @@ const ManageHostsPage = ({
routeParams,
queryParams: {
...queryParams,
- macos_settings_disk_encryption: newStatus,
+ [DISK_ENCRYPTION_QUERY_PARAM_NAME]: newStatus,
page: 0, // resets page index
},
})
@@ -768,7 +769,7 @@ const ManageHostsPage = ({
newQueryParams.os_version = osVersion;
} else if (diskEncryptionStatus && isPremiumTier) {
// Premium feature only
- newQueryParams.macos_settings_disk_encryption = diskEncryptionStatus;
+ newQueryParams[DISK_ENCRYPTION_QUERY_PARAM_NAME] = diskEncryptionStatus;
} else if (bootstrapPackageStatus && isPremiumTier) {
newQueryParams.bootstrap_package = bootstrapPackageStatus;
}
diff --git a/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss
index 38a15997083d..d4cb6bed093e 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss
+++ b/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss
@@ -33,7 +33,7 @@
line-height: 1.5;
background-color: $ui-light-grey;
border: solid 1px $ui-fleet-black-10;
- border-radius: 4px;
+ border-radius: $border-radius;
font-size: $small;
padding: 9.5px 12px 9.5px 36px;
color: $core-fleet-blue;
@@ -70,7 +70,7 @@
color: $core-vibrant-red;
border: 1px solid $core-vibrant-red;
box-sizing: border-box;
- border-radius: 4px;
+ border-radius: $border-radius;
&:focus {
border-color: $ui-error;
diff --git a/frontend/pages/hosts/ManageHostsPage/components/DiskEncryptionStatusFilter/DiskEncryptionStatusFilter.tsx b/frontend/pages/hosts/ManageHostsPage/components/DiskEncryptionStatusFilter/DiskEncryptionStatusFilter.tsx
index 2405fd6d151b..4e49123919f1 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/DiskEncryptionStatusFilter/DiskEncryptionStatusFilter.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/components/DiskEncryptionStatusFilter/DiskEncryptionStatusFilter.tsx
@@ -4,7 +4,7 @@ import { IDropdownOption } from "interfaces/dropdownOption";
// @ts-ignore
import Dropdown from "components/forms/fields/Dropdown";
-import { FileVaultProfileStatus } from "interfaces/mdm";
+import { DiskEncryptionStatus } from "interfaces/mdm";
const baseClass = "disk-encryption-status-filter";
@@ -42,8 +42,8 @@ const DISK_ENCRYPTION_STATUS_OPTIONS: IDropdownOption[] = [
];
interface IDiskEncryptionStatusFilterProps {
- diskEncryptionStatus: FileVaultProfileStatus;
- onChange: (value: FileVaultProfileStatus) => void;
+ diskEncryptionStatus: DiskEncryptionStatus;
+ onChange: (value: DiskEncryptionStatus) => void;
}
const DiskEncryptionStatusFilter = ({
diff --git a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss
index a7badf53a1f1..8f4a9c76a377 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss
+++ b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss
@@ -4,7 +4,7 @@
align-items: center;
padding: 6px 12px;
border: 1px solid $ui-fleet-black-25;
- border-radius: 4px;
+ border-radius: $border-radius;
box-shadow: none;
color: $core-fleet-black;
font-size: $xx-small;
diff --git a/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx b/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx
index 0e64c52c744f..1ff7287cb3c8 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx
@@ -7,7 +7,7 @@ import {
IOperatingSystemVersion,
} from "interfaces/operating_system";
import {
- FileVaultProfileStatus,
+ DiskEncryptionStatus,
BootstrapPackageStatus,
IMdmSolution,
MDM_ENROLLMENT_STATUS,
@@ -15,7 +15,10 @@ import {
import { IMunkiIssuesAggregate } from "interfaces/macadmins";
import { ISoftware } from "interfaces/software";
import { IPolicy } from "interfaces/policy";
-import { MacSettingsStatusQueryParam } from "services/entities/hosts";
+import {
+ DISK_ENCRYPTION_QUERY_PARAM_NAME,
+ MacSettingsStatusQueryParam,
+} from "services/entities/hosts";
import {
PLATFORM_LABEL_DISPLAY_NAMES,
@@ -60,7 +63,7 @@ interface IHostsFilterBlockProps {
osVersions?: IOperatingSystemVersion[];
softwareDetails: ISoftware | null;
mdmSolutionDetails: IMdmSolution | null;
- diskEncryptionStatus?: FileVaultProfileStatus;
+ diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
};
selectedLabel?: ILabel;
@@ -68,9 +71,7 @@ interface IHostsFilterBlockProps {
handleClearRouteParam: () => void;
handleClearFilter: (omitParams: string[]) => void;
onChangePoliciesFilter: (response: PolicyResponse) => void;
- onChangeDiskEncryptionStatusFilter: (
- response: FileVaultProfileStatus
- ) => void;
+ onChangeDiskEncryptionStatusFilter: (response: DiskEncryptionStatus) => void;
onChangeBootstrapPackageStatusFilter: (
response: BootstrapPackageStatus
) => void;
@@ -376,8 +377,8 @@ const HostsFilterBlock = ({
onChange={onChangeDiskEncryptionStatusFilter}
/>
handleClearFilter(["macos_settings_disk_encryption"])}
+ label="OS settings: Disk encryption"
+ onClear={() => handleClearFilter([DISK_ENCRYPTION_QUERY_PARAM_NAME])}
/>
>
);
diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx
index 285c0f8908ad..d5550026d577 100644
--- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx
+++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx
@@ -417,6 +417,7 @@ const DeviceUserPage = ({
showRefetchSpinner={showRefetchSpinner}
onRefetchHost={onRefetchHost}
renderActionButtons={renderActionButtons}
+ osSettings={host?.mdm.os_settings}
deviceUser
/>
@@ -489,6 +490,7 @@ const DeviceUserPage = ({
)}
{showMacSettingsModal && (
diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
index 0493579f5e11..48212d6a10f0 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
+++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
@@ -72,6 +72,7 @@ import HostActionDropdown from "./HostActionsDropdown/HostActionsDropdown";
import MacSettingsModal from "../MacSettingsModal";
import BootstrapPackageModal from "./modals/BootstrapPackageModal";
import SelectQueryModal from "./modals/SelectQueryModal";
+import { isSupportedPlatform } from "./modals/DiskEncryptionKeyModal/DiskEncryptionKeyModal";
const baseClass = "host-details";
@@ -725,6 +726,7 @@ const HostDetailsPage = ({
showRefetchSpinner={showRefetchSpinner}
onRefetchHost={onRefetchHost}
renderActionButtons={renderActionButtons}
+ osSettings={host?.mdm.os_settings}
/>
@@ -857,12 +860,15 @@ const HostDetailsPage = ({
{showUnenrollMdmModal && !!host && (
)}
- {showDiskEncryptionModal && host && (
- setShowDiskEncryptionModal(false)}
- />
- )}
+ {showDiskEncryptionModal &&
+ host &&
+ isSupportedPlatform(host.platform) && (
+ setShowDiskEncryptionModal(false)}
+ />
+ )}
{showBootstrapPackageModal &&
bootstrapPackageData.details &&
bootstrapPackageData.name && (
diff --git a/frontend/pages/hosts/details/HostDetailsPage/modals/DiskEncryptionKeyModal/DiskEncryptionKeyModal.tsx b/frontend/pages/hosts/details/HostDetailsPage/modals/DiskEncryptionKeyModal/DiskEncryptionKeyModal.tsx
index 8acdc6622ebd..1046822673b2 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/modals/DiskEncryptionKeyModal/DiskEncryptionKeyModal.tsx
+++ b/frontend/pages/hosts/details/HostDetailsPage/modals/DiskEncryptionKeyModal/DiskEncryptionKeyModal.tsx
@@ -9,15 +9,32 @@ import CustomLink from "components/CustomLink";
import Button from "components/buttons/Button";
import InputFieldHiddenContent from "components/forms/fields/InputFieldHiddenContent";
import DataError from "components/DataError";
+import { SupportedPlatform } from "interfaces/platform";
const baseClass = "disk-encryption-key-modal";
+// currently these are the only supported platforms for the disk encryption
+// key modal.
+export type ModalSupportedPlatform = Extract<
+ SupportedPlatform,
+ "darwin" | "windows"
+>;
+
+// Checks to see if the platform is supported by the modal.
+export const isSupportedPlatform = (
+ platform: string
+): platform is ModalSupportedPlatform => {
+ return ["darwin", "windows"].includes(platform);
+};
+
interface IDiskEncryptionKeyModal {
+ platform: ModalSupportedPlatform;
hostId: number;
onCancel: () => void;
}
const DiskEncryptionKeyModal = ({
+ platform,
hostId,
onCancel,
}: IDiskEncryptionKeyModal) => {
@@ -33,6 +50,18 @@ const DiskEncryptionKeyModal = ({
select: (data) => data.encryption_key.key,
});
+ const isMacOS = platform === "darwin";
+ const descriptionText = isMacOS
+ ? "The disk encryption key refers to the FileVault recovery key for macOS."
+ : "The disk encryption key refers to the BitLocker recovery key for Windows.";
+
+ const recoveryText = isMacOS
+ ? "Use this key to log in to the host if you forgot the password."
+ : "Use this key to unlock the encrypted drive.";
+ const recoveryUrl = isMacOS
+ ? "https://fleetdm.com/docs/using-fleet/mdm-disk-encryption#reset-a-macos-hosts-password-using-the-disk-encryption-key"
+ : "https://fleetdm.com/docs/using-fleet/mdm-disk-encryption#unlock-a-windows-hosts-drive-using-the-disk-encryption-key";
+
return (
{encryptionKeyError ? (
@@ -40,15 +69,12 @@ const DiskEncryptionKeyModal = ({
) : (
<>
+
{descriptionText}
- The disk encryption key refers to the FileVault recovery key for
- macOS.
-
-
- Use this key to log in to the host if you forgot the password.{" "}
+ {recoveryText}{" "}
diff --git a/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/_styles.scss b/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/_styles.scss
index 7f2f5f1ff1b7..c0b6053f3043 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/_styles.scss
+++ b/frontend/pages/hosts/details/HostDetailsPage/modals/OSPolicyModal/_styles.scss
@@ -42,7 +42,7 @@
&__copy-message {
background-color: $ui-light-grey;
border: solid 1px #e2e4ea;
- border-radius: 10px;
+ border-radius: $border-radius-xlarge;
padding: 2px 6px;
}
}
diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/index.ts b/frontend/pages/hosts/details/MacSettingsIndicator/index.ts
deleted file mode 100644
index 47e97520648e..000000000000
--- a/frontend/pages/hosts/details/MacSettingsIndicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./MacSettingsIndicator";
diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx
index a055bae71536..eab9e92bbbe0 100644
--- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx
+++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx
@@ -7,20 +7,28 @@ import MacSettingsTable from "./MacSettingsTable";
import { generateTableData } from "./MacSettingsTable/MacSettingsTableConfig";
interface IMacSettingsModalProps {
- hostMDMData?: Pick;
+ platform?: string;
+ hostMDMData?: IHostMdmData;
onClose: () => void;
}
const baseClass = "mac-settings-modal";
-const MacSettingsModal = ({ hostMDMData, onClose }: IMacSettingsModalProps) => {
- const memoizedTableData = useMemo(() => generateTableData(hostMDMData), [
- hostMDMData,
- ]);
+const MacSettingsModal = ({
+ platform,
+ hostMDMData,
+ onClose,
+}: IMacSettingsModalProps) => {
+ const memoizedTableData = useMemo(
+ () => generateTableData(hostMDMData, platform),
+ [hostMDMData, platform]
+ );
+
+ if (!platform) return null;
return (
innerProps.isDiskEncryptionProfile
- ? "The host will receive the MDM command to install the disk encryption profile when the " +
- "host comes online."
+ ? "The hosts will receive the MDM command to turn on disk encryption " +
+ "when the hosts come online."
: "The host will receive the MDM command to install the configuration profile when the " +
"host comes online.",
},
@@ -56,8 +59,8 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
iconName: "success",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
- ? "The host turned disk encryption on and " +
- "sent their key to Fleet. Fleet verified with osquery."
+ ? "The host turned disk encryption on and sent the key to Fleet. " +
+ "Fleet verified with osquery."
: "The host installed the configuration profile. Fleet verified with osquery.",
},
verifying: {
@@ -65,8 +68,9 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
iconName: "success-partial",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
- ? "The host acknowledged the MDM command to install disk encryption profile. Fleet is " +
- "verifying with osquery and retrieving the disk encryption key. This may take up to one hour."
+ ? "The host acknowledged the MDM command to turn on disk encryption. " +
+ "Fleet is verifying with osquery and retrieving the disk encryption key. " +
+ "This may take up to one hour."
: "The host acknowledged the MDM command to install the configuration profile. Fleet is " +
"verifying with osquery.",
},
@@ -98,9 +102,41 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
},
};
+type WindowsDiskEncryptionDisplayConfig = Omit<
+ OperationTypeOption,
+ "action_required"
+>;
+
+const WINDOWS_DISK_ENCRYPTION_DISPLAY_CONFIG: WindowsDiskEncryptionDisplayConfig = {
+ verified: {
+ statusText: "Verified",
+ iconName: "success",
+ tooltip: () =>
+ "The host turned disk encryption on and sent the key to Fleet. Fleet verified with osquery.",
+ },
+ verifying: {
+ statusText: "Verifying",
+ iconName: "success-partial",
+ tooltip: () =>
+ "The host acknowledged the MDM command to turn on disk encryption. Fleet is verifying with osquery and retrieving " +
+ "the disk encryption key. This may take up to one hour.",
+ },
+ pending: {
+ statusText: "Enforcing (pending)",
+ iconName: "pending-partial",
+ tooltip: () =>
+ "The host will receive the MDM command to turn on disk encryption when the host comes online.",
+ },
+ failed: {
+ statusText: "Failed",
+ iconName: "error",
+ tooltip: null,
+ },
+};
+
interface IMacSettingStatusCellProps {
status: MacSettingsTableStatusValue;
- operationType: MacMdmProfileOperationType;
+ operationType: MacMdmProfileOperationType | null;
profileName: string;
}
@@ -108,8 +144,18 @@ const MacSettingStatusCell = ({
status,
operationType,
profileName = "",
-}: IMacSettingStatusCellProps): JSX.Element => {
- const diplayOption = PROFILE_DISPLAY_CONFIG[operationType]?.[status];
+}: IMacSettingStatusCellProps) => {
+ let displayOption: ProfileDisplayOption = null;
+
+ // windows hosts do not have an operation type at the moment and their display options are
+ // different than mac hosts.
+ if (!operationType && isMdmProfileStatus(status)) {
+ displayOption = WINDOWS_DISK_ENCRYPTION_DISPLAY_CONFIG[status];
+ }
+
+ if (operationType) {
+ displayOption = PROFILE_DISPLAY_CONFIG[operationType]?.[status];
+ }
const isDeviceUser = window.location.pathname
.toLowerCase()
@@ -118,8 +164,8 @@ const MacSettingStatusCell = ({
const isDiskEncryptionProfile =
profileName === FLEET_FILEVAULT_PROFILE_DISPLAY_NAME;
- if (diplayOption) {
- const { statusText, iconName, tooltip } = diplayOption;
+ if (displayOption) {
+ const { statusText, iconName, tooltip } = displayOption;
const tooltipId = uniqueId();
return (
diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx
index 39bd021222b4..7b2364af255c 100644
--- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx
+++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx
@@ -5,20 +5,27 @@ import { IHostMdmData } from "interfaces/host";
import {
FLEET_FILEVAULT_PROFILE_DISPLAY_NAME,
// FLEET_FILEVAULT_PROFILE_IDENTIFIER,
- IHostMacMdmProfile,
+ IHostMdmProfile,
MdmProfileStatus,
+ isWindowsDiskEncryptionStatus,
} from "interfaces/mdm";
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
import TruncatedTextCell from "components/TableContainer/DataTable/TruncatedTextCell";
import MacSettingStatusCell from "./MacSettingStatusCell";
+import { generateWinDiskEncryptionProfile } from "../../helpers";
-export interface IMacSettingsTableRow
- extends Omit {
+export interface IMacSettingsTableRow extends Omit {
status: MacSettingsTableStatusValue;
}
export type MacSettingsTableStatusValue = MdmProfileStatus | "action_required";
+export const isMdmProfileStatus = (
+ status: string
+): status is MdmProfileStatus => {
+ return status !== "action_required";
+};
+
interface IHeaderProps {
column: {
title: string;
@@ -92,20 +99,41 @@ const tableHeaders: IDataColumn[] = [
];
export const generateTableData = (
- hostMDMData?: Pick
+ hostMDMData?: IHostMdmData,
+ platform?: string
) => {
+ if (!platform) return [];
+
let rows: IMacSettingsTableRow[] = [];
if (!hostMDMData) {
return rows;
}
+ if (
+ platform === "windows" &&
+ hostMDMData.os_settings?.disk_encryption.status &&
+ isWindowsDiskEncryptionStatus(
+ hostMDMData.os_settings.disk_encryption.status
+ )
+ ) {
+ rows.push(
+ generateWinDiskEncryptionProfile(
+ hostMDMData.os_settings.disk_encryption.status
+ )
+ );
+ return rows;
+ }
+
const { profiles, macos_settings } = hostMDMData;
+
if (!profiles) {
return rows;
}
- rows = profiles;
- if (macos_settings?.disk_encryption === "action_required") {
+ if (
+ platform === "darwin" &&
+ macos_settings?.disk_encryption === "action_required"
+ ) {
rows = profiles.map((p) => {
// TODO: this is a brittle check for the filevault profile
// it would be better to match on the identifier but it is not
diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx b/frontend/pages/hosts/details/ProfileStatusIndicator/ProfileStatusIndicator.tests.tsx
similarity index 87%
rename from frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx
rename to frontend/pages/hosts/details/ProfileStatusIndicator/ProfileStatusIndicator.tests.tsx
index a71467903cec..73044dd21805 100644
--- a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx
+++ b/frontend/pages/hosts/details/ProfileStatusIndicator/ProfileStatusIndicator.tests.tsx
@@ -1,12 +1,15 @@
import React from "react";
import { fireEvent, render, screen } from "@testing-library/react";
-import MacSettingsIndicator from "./MacSettingsIndicator";
+import ProfileStatusIndicator from "./ProfileStatusIndicator";
-describe("MacSettingsIndicator", () => {
+describe("ProfileStatusIndicator component", () => {
it("Renders the text and icon", () => {
const indicatorText = "test text";
render(
-
+
);
const renderedIndicatorText = screen.getByText(indicatorText);
const renderedIcon = screen.getByTestId("success-icon");
@@ -19,7 +22,7 @@ describe("MacSettingsIndicator", () => {
const indicatorText = "test text";
const tooltipText = "test tooltip text";
render(
- {
document.body.appendChild(newDiv);
};
render(
- {
diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx b/frontend/pages/hosts/details/ProfileStatusIndicator/ProfileStatusIndicator.tsx
similarity index 92%
rename from frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx
rename to frontend/pages/hosts/details/ProfileStatusIndicator/ProfileStatusIndicator.tsx
index 473745ee3344..f3bbe6cd024c 100644
--- a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx
+++ b/frontend/pages/hosts/details/ProfileStatusIndicator/ProfileStatusIndicator.tsx
@@ -4,9 +4,9 @@ import { IconNames } from "components/icons";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
-const baseClass = "settings-indicator";
+const baseClass = "profile-status-indicator";
-export interface IMacSettingsIndicator {
+export interface IProfileStatusIndicatorProps {
indicatorText: string;
iconName: IconNames;
onClick?: () => void;
@@ -16,12 +16,12 @@ export interface IMacSettingsIndicator {
};
}
-const MacSettingsIndicator = ({
+const ProfileStatusIndicator = ({
indicatorText,
iconName,
onClick,
tooltip,
-}: IMacSettingsIndicator): JSX.Element => {
+}: IProfileStatusIndicatorProps) => {
const getIndicatorTextWrapped = () => {
if (onClick && tooltip?.tooltipText) {
return (
@@ -103,4 +103,4 @@ const MacSettingsIndicator = ({
);
};
-export default MacSettingsIndicator;
+export default ProfileStatusIndicator;
diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss b/frontend/pages/hosts/details/ProfileStatusIndicator/_styles.scss
similarity index 88%
rename from frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss
rename to frontend/pages/hosts/details/ProfileStatusIndicator/_styles.scss
index fce8265c95eb..a7ed40ad9155 100644
--- a/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss
+++ b/frontend/pages/hosts/details/ProfileStatusIndicator/_styles.scss
@@ -1,4 +1,4 @@
-.settings-indicator {
+.profile-status-indicator {
display: flex;
gap: 4px;
diff --git a/frontend/pages/hosts/details/ProfileStatusIndicator/index.ts b/frontend/pages/hosts/details/ProfileStatusIndicator/index.ts
new file mode 100644
index 000000000000..99de4100ca68
--- /dev/null
+++ b/frontend/pages/hosts/details/ProfileStatusIndicator/index.ts
@@ -0,0 +1 @@
+export { default } from "./ProfileStatusIndicator";
diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx
index f18194844c59..45be0eaba57b 100644
--- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx
+++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx
@@ -1,7 +1,12 @@
import React from "react";
-
import ReactTooltip from "react-tooltip";
-import { IHostMacMdmProfile, BootstrapPackageStatus } from "interfaces/mdm";
+
+import {
+ IHostMdmProfile,
+ BootstrapPackageStatus,
+ isWindowsDiskEncryptionStatus,
+} from "interfaces/mdm";
+import { IOSSettings } from "interfaces/host";
import getHostStatusTooltipText from "pages/hosts/helpers";
import TooltipWrapper from "components/TooltipWrapper";
@@ -9,6 +14,7 @@ import Button from "components/buttons/Button";
import Icon from "components/Icon/Icon";
import DiskSpaceGraph from "components/DiskSpaceGraph";
import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip";
+import PremiumFeatureIconWithTooltip from "components/PremiumFeatureIconWithTooltip";
import {
getHostDiskEncryptionTooltipMessage,
humanHostMemory,
@@ -16,10 +22,11 @@ import {
} from "utilities/helpers";
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
import StatusIndicator from "components/StatusIndicator";
-import PremiumFeatureIconWithTooltip from "components/PremiumFeatureIconWithTooltip";
+
import MacSettingsIndicator from "./MacSettingsIndicator";
import HostSummaryIndicator from "./HostSummaryIndicator";
import BootstrapPackageIndicator from "./BootstrapPackageIndicator/BootstrapPackageIndicator";
+import { generateWinDiskEncryptionProfile } from "../../helpers";
const baseClass = "host-summary";
@@ -38,7 +45,7 @@ interface IHostSummaryProps {
toggleOSPolicyModal?: () => void;
toggleMacSettingsModal?: () => void;
toggleBootstrapPackageModal?: () => void;
- hostMdmProfiles?: IHostMacMdmProfile[];
+ hostMdmProfiles?: IHostMdmProfile[];
mdmName?: string;
showRefetchSpinner: boolean;
onRefetchHost: (
@@ -46,6 +53,7 @@ interface IHostSummaryProps {
) => void;
renderActionButtons: () => JSX.Element | null;
deviceUser?: boolean;
+ osSettings?: IOSSettings;
}
const HostSummary = ({
@@ -64,8 +72,9 @@ const HostSummary = ({
onRefetchHost,
renderActionButtons,
deviceUser,
+ osSettings,
}: IHostSummaryProps): JSX.Element => {
- const { status, id, platform } = titleData;
+ const { status, platform } = titleData;
const renderRefetch = () => {
const isOnline = titleData.status === "online";
@@ -179,6 +188,22 @@ const HostSummary = ({
};
const renderSummary = () => {
+ // for windows hosts we have to manually add a profile for disk encryption
+ // as this is not currently included in the `profiles` value from the API
+ // response for windows hosts.
+ if (
+ platform === "windows" &&
+ osSettings?.disk_encryption?.status &&
+ isWindowsDiskEncryptionStatus(osSettings.disk_encryption.status)
+ ) {
+ const winDiskEncryptionProfile: IHostMdmProfile = generateWinDiskEncryptionProfile(
+ osSettings.disk_encryption.status
+ );
+ hostMdmProfiles = hostMdmProfiles
+ ? [...hostMdmProfiles, winDiskEncryptionProfile]
+ : [winDiskEncryptionProfile];
+ }
+
return (
@@ -198,12 +223,15 @@ const HostSummary = ({
{isPremiumTier && renderHostTeam()}
- {platform === "darwin" &&
+ {/* Rendering of OS Settings data */}
+ {(platform === "darwin" || platform === "windows") &&
isPremiumTier &&
- mdmName === "Fleet" && // show if 1 - host is enrolled in Fleet MDM, and
+ // TODO: API INTEGRATION: change this when we figure out why the API is
+ // returning "Fleet" or "FleetDM" for the MDM name.
+ mdmName?.includes("Fleet") && // show if 1 - host is enrolled in Fleet MDM, and
hostMdmProfiles &&
hostMdmProfiles.length > 0 && ( // 2 - host has at least one setting (profile) enforced
-
+ {
const statuses = hostMacSettings.map((setting) => setting.status);
if (statuses.includes("failed")) {
@@ -68,7 +68,7 @@ const getMacProfileStatus = (
};
interface IMacSettingsIndicatorProps {
- profiles: IHostMacMdmProfile[];
+ profiles: IHostMdmProfile[];
onClick?: () => void;
}
const MacSettingsIndicator = ({
diff --git a/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyFailingCount/PolicyFailingCount.tsx b/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyFailingCount/PolicyFailingCount.tsx
index ecb1f1b7c5f1..24a184a0d12b 100644
--- a/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyFailingCount/PolicyFailingCount.tsx
+++ b/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyFailingCount/PolicyFailingCount.tsx
@@ -2,6 +2,7 @@ import { IHostPolicy } from "interfaces/policy";
import React from "react";
import Icon from "components/Icon/Icon";
+import InfoBanner from "components/InfoBanner";
const baseClass = "policy-failing-count";
@@ -18,7 +19,7 @@ const PolicyFailingCount = ({
}, 0);
return failCount ? (
-
+
This device is failing
@@ -27,10 +28,10 @@ const PolicyFailingCount = ({
Click a policy below to see if there are steps you can take to resolve
the issue
- {failCount > 1 ? "s" : ""}.{" "}
+ {failCount > 1 ? "s" : ""}.
{deviceUser && " Once resolved, click “Refetch” above to confirm."}