Add host mdm disk encryption detail to host details API response (#14623)

This commit is contained in:
gillespi314
2023-10-18 15:39:23 -05:00
committed by GitHub
parent 8efac8b648
commit 484550a620
8 changed files with 63 additions and 33 deletions
@@ -0,0 +1,2 @@
- Updated `GET hosts/:id` API response to include additional detail for disk encryption in case of
device client errors.
+24 -17
View File
@@ -254,31 +254,32 @@ WHERE
return &res, nil
}
func (ds *Datastore) GetMDMWindowsBitLockerStatus(ctx context.Context, host *fleet.Host) (*fleet.DiskEncryptionStatus, error) {
func (ds *Datastore) GetMDMWindowsBitLockerStatus(ctx context.Context, host *fleet.Host) (*fleet.HostMDMDiskEncryption, error) {
hde := &fleet.HostMDMDiskEncryption{}
if host == nil {
return nil, errors.New("host cannot be nil")
return hde, errors.New("host cannot be nil")
}
if host.Platform != "windows" {
// Generally, the caller should have already checked this, but just in case we log and
// return nil
level.Debug(ds.logger).Log("msg", "cannot get bitlocker status for non-windows host", "host_id", host.ID)
return nil, nil
return hde, nil
}
if host.MDMInfo != nil && host.MDMInfo.IsServer {
// It is currently expected that server hosts do not have a bitlocker status so we can skip
// the query and return nil. We log for potential debugging in case this changes in the future.
level.Debug(ds.logger).Log("msg", "no bitlocker status for server host", "host_id", host.ID)
return nil, nil
return hde, nil
}
enabled, err := ds.getConfigEnableDiskEncryption(ctx, host.TeamID)
if err != nil {
return nil, err
return hde, err
}
if !enabled {
return nil, nil
return hde, nil
}
// Note action_required and removing_enforcement are not applicable to Windows hosts
@@ -289,7 +290,8 @@ SELECT
WHEN (%s) THEN '%s'
WHEN (%s) THEN '%s'
WHEN (%s) THEN '%s'
END AS status
END AS status,
COALESCE(client_error, '') as detail
FROM
host_mdm hmdm
LEFT JOIN host_disk_encryption_keys hdek ON hmdm.host_id = hdek.host_id
@@ -306,17 +308,22 @@ WHERE
fleet.DiskEncryptionFailed,
)
var des fleet.DiskEncryptionStatus
if err := sqlx.GetContext(ctx, ds.reader(ctx), &des, stmt, host.ID); err != nil {
if err == sql.ErrNoRows {
// At this point we know disk encryption is enabled so if we don't have a record for the
// host then we treat it as enforcing and log for potential debugging
level.Debug(ds.logger).Log("msg", "no bitlocker status found for host", "host_id", host.ID)
des = fleet.DiskEncryptionEnforcing
return &des, nil
var dest struct {
Status fleet.DiskEncryptionStatus `db:"status"`
Detail string `db:"detail"`
}
if err := sqlx.GetContext(ctx, ds.reader(ctx), &dest, stmt, host.ID); err != nil {
if err != sql.ErrNoRows {
return &fleet.HostMDMDiskEncryption{}, err
}
return nil, err
// At this point we know disk encryption is enabled so if there are no rows for the
// host then we treat it as enforcing and log for potential debugging
level.Debug(ds.logger).Log("msg", "no bitlocker status found for host", "host_id", host.ID)
dest.Status = fleet.DiskEncryptionEnforcing
}
return &des, nil
return &fleet.HostMDMDiskEncryption{
Status: &dest.Status,
Detail: dest.Detail,
}, nil
}
+2 -1
View File
@@ -133,7 +133,8 @@ func TestMDMWindowsDiskEncryption(t *testing.T) {
bls, err := ds.GetMDMWindowsBitLockerStatus(ctx, h)
require.NoError(t, err)
require.NotNil(t, bls)
require.Equal(t, expected, *bls)
require.NotNil(t, bls.Status)
require.Equal(t, expected, *bls.Status)
}
}
+1 -1
View File
@@ -1053,7 +1053,7 @@ type Datastore interface {
//
// Note that the returned status will be nil if the host is reported to be a Windows
// server or if disk encryption is disabled for the host's team (or no team, as applicable).
GetMDMWindowsBitLockerStatus(ctx context.Context, host *Host) (*DiskEncryptionStatus, error)
GetMDMWindowsBitLockerStatus(ctx context.Context, host *Host) (*HostMDMDiskEncryption, error)
///////////////////////////////////////////////////////////////////////////////
// Host Script Results
+19 -4
View File
@@ -376,6 +376,7 @@ type HostMDMOSSettings struct {
type HostMDMDiskEncryption struct {
Status *DiskEncryptionStatus `json:"status" db:"-" csv:"-"`
Detail string `json:"detail" db:"-" csv:"-"`
}
type DiskEncryptionStatus string
@@ -431,11 +432,14 @@ type HostMDMMacOSSetup struct {
BootstrapPackageName string `db:"bootstrap_package_name" json:"bootstrap_package_name" csv:"-"`
}
// DetermineMacOSDiskEncryptionStatus determines the disk encryption status for the
// DetermineHostMDMDiskEncryptionMacOS determines the disk encryption status for the
// host based on the file-vault profile in its list of profiles and whether its
// disk encryption key is available and decryptable. The file-vault profile
// identifier is received as argument to avoid a circular dependency.
func (d *MDMHostData) DetermineMacOSDiskEncryptionStatus(profiles []HostMDMAppleProfile, fileVaultIdentifier string) {
// disk encryption key is available and decryptable. It sets the status value in MacOSSettings on
// the HostMDMData struct. It also returns a pointer to a newly populated HostMDMDiskEncryption
// struct intended for use in the host details response.
//
// The file-vault profile identifier is received as argument to avoid a circular dependency.
func (d *MDMHostData) DetermineHostMDMDiskEncryptionMacOS(profiles []HostMDMAppleProfile, fileVaultIdentifier string) *HostMDMDiskEncryption {
var settings MDMHostMacOSSettings
var fvprof *HostMDMAppleProfile
@@ -503,6 +507,17 @@ func (d *MDMHostData) DetermineMacOSDiskEncryptionStatus(profiles []HostMDMApple
}
}
d.MacOSSettings = &settings
var status *DiskEncryptionStatus
if settings.DiskEncryption != nil {
status = settings.DiskEncryption
}
var detail string
if fvprof != nil {
detail = fvprof.Detail
}
return &HostMDMDiskEncryption{Status: status, Detail: detail}
}
func (d *MDMHostData) ProfileStatusFromDiskEncryptionState(currStatus *MDMAppleDeliveryStatus) *MDMAppleDeliveryStatus {
+2 -2
View File
@@ -690,7 +690,7 @@ type MDMWindowsDeleteEnrolledDeviceWithDeviceIDFunc func(ctx context.Context, md
type GetMDMWindowsBitLockerSummaryFunc func(ctx context.Context, teamID *uint) (*fleet.MDMWindowsBitLockerSummary, error)
type GetMDMWindowsBitLockerStatusFunc func(ctx context.Context, host *fleet.Host) (*fleet.DiskEncryptionStatus, error)
type GetMDMWindowsBitLockerStatusFunc func(ctx context.Context, host *fleet.Host) (*fleet.HostMDMDiskEncryption, error)
type NewHostScriptExecutionRequestFunc func(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult, error)
@@ -4114,7 +4114,7 @@ func (s *DataStore) GetMDMWindowsBitLockerSummary(ctx context.Context, teamID *u
return s.GetMDMWindowsBitLockerSummaryFunc(ctx, teamID)
}
func (s *DataStore) GetMDMWindowsBitLockerStatus(ctx context.Context, host *fleet.Host) (*fleet.DiskEncryptionStatus, error) {
func (s *DataStore) GetMDMWindowsBitLockerStatus(ctx context.Context, host *fleet.Host) (*fleet.HostMDMDiskEncryption, error) {
s.mu.Lock()
s.GetMDMWindowsBitLockerStatusFuncInvoked = true
s.mu.Unlock()
+4 -4
View File
@@ -924,11 +924,11 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f
switch host.Platform {
case "windows":
if ac.MDM.WindowsEnabledAndConfigured && license.IsPremium(ctx) {
bls, err := svc.ds.GetMDMWindowsBitLockerStatus(ctx, host)
hde, err := svc.ds.GetMDMWindowsBitLockerStatus(ctx, host)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "get host mdm bitlocker status")
}
host.MDM.OSSettings.DiskEncryption.Status = bls
host.MDM.OSSettings.DiskEncryption = *hde
}
case "darwin":
if ac.MDM.EnabledAndConfigured {
@@ -939,8 +939,8 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f
// determine disk encryption and action required here based on profiles and
// raw decryptable key status.
host.MDM.DetermineMacOSDiskEncryptionStatus(profs, mobileconfig.FleetFileVaultPayloadIdentifier)
host.MDM.OSSettings.DiskEncryption.Status = host.MDM.MacOSSettings.DiskEncryption
hde := host.MDM.DetermineHostMDMDiskEncryptionMacOS(profs, mobileconfig.FleetFileVaultPayloadIdentifier)
host.MDM.OSSettings.DiskEncryption = *hde
for _, p := range profs {
if p.Identifier == mobileconfig.FleetFileVaultPayloadIdentifier {
+9 -4
View File
@@ -228,6 +228,7 @@ func TestHostDetailsMDMAppleDiskEncryption(t *testing.T) {
Identifier: mobileconfig.FleetFileVaultPayloadIdentifier,
Status: &fleet.MDMAppleDeliveryFailed,
OperationType: fleet.MDMAppleOperationTypeInstall,
Detail: "some mdm profile install error",
},
fleet.DiskEncryptionFailed,
"",
@@ -280,6 +281,7 @@ func TestHostDetailsMDMAppleDiskEncryption(t *testing.T) {
Identifier: mobileconfig.FleetFileVaultPayloadIdentifier,
Status: &fleet.MDMAppleDeliveryFailed,
OperationType: fleet.MDMAppleOperationTypeRemove,
Detail: "some mdm profile removal error",
},
fleet.DiskEncryptionFailed,
"",
@@ -327,11 +329,13 @@ func TestHostDetailsMDMAppleDiskEncryption(t *testing.T) {
if c.wantState == "" {
require.Nil(t, hostDetail.MDM.MacOSSettings.DiskEncryption)
require.Nil(t, hostDetail.MDM.OSSettings.DiskEncryption.Status)
require.Empty(t, hostDetail.MDM.OSSettings.DiskEncryption.Detail)
} else {
require.NotNil(t, hostDetail.MDM.MacOSSettings.DiskEncryption)
require.Equal(t, c.wantState, *hostDetail.MDM.MacOSSettings.DiskEncryption)
require.NotNil(t, hostDetail.MDM.OSSettings.DiskEncryption.Status)
require.Equal(t, c.wantState, *hostDetail.MDM.OSSettings.DiskEncryption.Status)
require.Equal(t, c.fvProf.Detail, hostDetail.MDM.OSSettings.DiskEncryption.Detail)
}
if c.wantAction == "" {
require.Nil(t, hostDetail.MDM.MacOSSettings.ActionRequired)
@@ -343,6 +347,7 @@ func TestHostDetailsMDMAppleDiskEncryption(t *testing.T) {
require.NotNil(t, hostDetail.MDM.Profiles)
profs := *hostDetail.MDM.Profiles
require.Equal(t, c.wantStatus, profs[0].Status)
require.Equal(t, c.fvProf.Detail, profs[0].Detail)
} else {
require.Nil(t, *hostDetail.MDM.Profiles)
}
@@ -396,11 +401,11 @@ func TestHostDetailsOSSettings(t *testing.T) {
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{MDM: fleet.MDM{EnabledAndConfigured: true, WindowsEnabledAndConfigured: true}}, nil
}
ds.GetMDMWindowsBitLockerStatusFunc = func(ctx context.Context, host *fleet.Host) (*fleet.DiskEncryptionStatus, error) {
ds.GetMDMWindowsBitLockerStatusFunc = func(ctx context.Context, host *fleet.Host) (*fleet.HostMDMDiskEncryption, error) {
if c.wantStatus == "" {
return nil, nil
}
return &c.wantStatus, nil
return &fleet.HostMDMDiskEncryption{Status: &c.wantStatus, Detail: ""}, nil
}
ds.GetHostMDMProfilesFunc = func(ctx context.Context, uuid string) ([]fleet.HostMDMAppleProfile, error) {
return nil, nil
@@ -469,9 +474,9 @@ func TestHostDetailsOSSettingsWindowsOnly(t *testing.T) {
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{MDM: fleet.MDM{WindowsEnabledAndConfigured: true}}, nil
}
ds.GetMDMWindowsBitLockerStatusFunc = func(ctx context.Context, host *fleet.Host) (*fleet.DiskEncryptionStatus, error) {
ds.GetMDMWindowsBitLockerStatusFunc = func(ctx context.Context, host *fleet.Host) (*fleet.HostMDMDiskEncryption, error) {
verified := fleet.DiskEncryptionVerified
return &verified, nil
return &fleet.HostMDMDiskEncryption{Status: &verified, Detail: ""}, nil
}
ds.GetHostMDMProfilesFunc = func(ctx context.Context, uuid string) ([]fleet.HostMDMAppleProfile, error) {
return nil, nil