Validate that WSTEP is configured before enabling Windows MDM (#14858)

#14446 

~~Note that the fix requires a frontend change too, so this should not
be merged before the frontend is also ready.~~ Frontend
[PR](https://github.com/fleetdm/fleet/pull/14971) is ready.
This commit is contained in:
Martin Angers 2023-11-09 08:08:54 -05:00 committed by GitHub
parent 588555ef63
commit b2ab4553cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 11 deletions

View File

@ -0,0 +1 @@
* Added a validation that the WSTEP certificate and key pair is configured before allowing the user to enable Windows MDM.

View File

@ -1040,7 +1040,7 @@ func TestVerifyDiskEncryptionKeysJob(t *testing.T) {
base64EncryptedKey := base64.StdEncoding.EncodeToString(encryptedKey)
fleetCfg := config.TestConfig()
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, testBMToken)
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, testBMToken, "../../server/service/testdata")
now := time.Now()

View File

@ -14,17 +14,21 @@ import (
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"testing"
"time"
"github.com/fleetdm/fleet/v4/pkg/optjson"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/fleet"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
"github.com/fleetdm/fleet/v4/server/mock"
nanomdm_mock "github.com/fleetdm/fleet/v4/server/mock/nanomdm"
"github.com/fleetdm/fleet/v4/server/ptr"
"github.com/fleetdm/fleet/v4/server/service"
"github.com/google/uuid"
"github.com/micromdm/nanodep/tokenpki"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -820,10 +824,20 @@ func TestApplyAsGitOps(t *testing.T) {
enqueuer := new(nanomdm_mock.Storage)
license := &fleet.LicenseInfo{Tier: fleet.TierPremium, Expiration: time.Now().Add(24 * time.Hour)}
// mdm test configuration must be set so that activating windows MDM works.
testCert, testKey, err := apple_mdm.NewSCEPCACertKey()
require.NoError(t, err)
testCertPEM := tokenpki.PEMCertificate(testCert.Raw)
testKeyPEM := tokenpki.PEMRSAPrivateKey(testKey)
fleetCfg := config.TestConfig()
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, nil, "../../server/service/testdata")
_, ds := runServerWithMockedDS(t, &service.TestServerOpts{
License: license,
MDMStorage: enqueuer,
MDMPusher: mockPusher{},
License: license,
MDMStorage: enqueuer,
MDMPusher: mockPusher{},
FleetConfig: &fleetCfg,
})
gitOps := &fleet.User{
@ -832,7 +846,7 @@ func TestApplyAsGitOps(t *testing.T) {
Email: "gitops1@example.com",
GlobalRole: ptr.String(fleet.RoleGitOps),
}
gitOps, err := ds.NewUser(context.Background(), gitOps)
gitOps, err = ds.NewUser(context.Background(), gitOps)
require.NoError(t, err)
ds.SessionByKeyFunc = func(ctx context.Context, key string) (*fleet.Session, error) {
return &fleet.Session{
@ -2984,6 +2998,28 @@ spec:
`, macSetupFile),
wantErr: `macOS MDM isn't turned on.`,
},
{
desc: "app config enable windows mdm without feature flag",
spec: `
apiVersion: v1
kind: config
spec:
mdm:
windows_enabled_and_configured: true
`,
wantErr: `422 Validation Failed: cannot enable Windows MDM without the feature flag explicitly enabled`,
},
{
desc: "app config enable windows mdm without WSTEP",
spec: `
apiVersion: v1
kind: config
spec:
mdm:
windows_enabled_and_configured: true
`,
wantErr: `422 Validation Failed: Couldn't turn on Windows MDM. Please configure Fleet with a certificate and key pair first.`,
},
}
// NOTE: Integrations required fields are not tested (Jira/Zendesk) because
// they require a complex setup to mock the client that would communicate
@ -2994,6 +3030,12 @@ spec:
license := &fleet.LicenseInfo{Tier: fleet.TierPremium, Expiration: time.Now().Add(24 * time.Hour)}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
// bit hacky, but since the env var is temporary while Windows MDM is in beta,
// didn't want to add a field to the test cases just for this.
if strings.Contains(c.desc, "WSTEP") {
t.Setenv("FLEET_DEV_MDM_ENABLED", "1")
}
_, ds := runServerWithMockedDS(t, &service.TestServerOpts{License: license})
setupDS(ds)
filename := writeTmpYml(t, c.spec)

View File

@ -1699,7 +1699,7 @@ func TestConfig() FleetConfig {
// all required pairs and the Apple BM token is used as-is, instead of
// decrypting the encrypted value that is usually provided via the fleet
// server's flags.
func SetTestMDMConfig(t testing.TB, cfg *FleetConfig, cert, key []byte, appleBMToken *nanodep_client.OAuth1Tokens) {
func SetTestMDMConfig(t testing.TB, cfg *FleetConfig, cert, key []byte, appleBMToken *nanodep_client.OAuth1Tokens, wstepCertAndKeyDir string) {
tlsCert, err := tls.X509KeyPair(cert, key)
if err != nil {
t.Fatal(err)
@ -1729,11 +1729,17 @@ func SetTestMDMConfig(t testing.TB, cfg *FleetConfig, cert, key []byte, appleBMT
cfg.MDM.AppleSCEPSignerValidityDays = 365
cfg.MDM.AppleSCEPChallenge = "testchallenge"
certPath := "../service/testdata/server.pem"
keyPath := "../service/testdata/server.key"
if wstepCertAndKeyDir == "" {
wstepCertAndKeyDir = "testdata"
}
certPath := filepath.Join(wstepCertAndKeyDir, "server.pem")
keyPath := filepath.Join(wstepCertAndKeyDir, "server.key")
cfg.MDM.WindowsWSTEPIdentityCert = certPath
cfg.MDM.WindowsWSTEPIdentityKey = keyPath
if _, _, _, err := cfg.MDM.MicrosoftWSTEP(); err != nil {
t.Fatal(err)
}
}
// Undocumented feature flag for Windows MDM, used to determine if the Windows

View File

@ -728,6 +728,12 @@ func (svc *Service) validateMDM(
return
}
}
if !svc.config.MDM.IsMicrosoftWSTEPSet() {
if mdm.WindowsEnabledAndConfigured {
invalid.Append("mdm.windows_enabled_and_configured", "Couldn't turn on Windows MDM. Please configure Fleet with a certificate and key pair first.")
return
}
}
// if either macOS or Windows MDM is enabled, this setting can be set.
if !mdm.AtLeastOnePlatformEnabledAndConfigured() {

View File

@ -1045,7 +1045,7 @@ func TestHostEncryptionKey(t *testing.T) {
testKeyPEM := tokenpki.PEMRSAPrivateKey(testKey)
fleetCfg := config.TestConfig()
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, testBMToken)
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, testBMToken, "")
recoveryKey := "AAA-BBB-CCC"
encryptedKey, err := pkcs7.Encrypt([]byte(recoveryKey), []*x509.Certificate{testCert})
@ -1210,7 +1210,7 @@ func TestHostMDMProfileDetail(t *testing.T) {
testKeyPEM := tokenpki.PEMRSAPrivateKey(testKey)
fleetCfg := config.TestConfig()
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, testBMToken)
config.SetTestMDMConfig(t, &fleetCfg, testCertPEM, testKeyPEM, testBMToken, "")
svc, ctx := newTestServiceWithConfig(t, ds, fleetCfg, nil, nil)
ctx = test.UserContext(ctx, test.UserAdmin)

View File

@ -100,7 +100,7 @@ func (s *integrationMDMTestSuite) SetupSuite() {
testKeyPEM := tokenpki.PEMRSAPrivateKey(testKey)
fleetCfg := config.TestConfig()
config.SetTestMDMConfig(s.T(), &fleetCfg, testCertPEM, testKeyPEM, testBMToken)
config.SetTestMDMConfig(s.T(), &fleetCfg, testCertPEM, testKeyPEM, testBMToken, "")
fleetCfg.Osquery.EnrollCooldown = 0
mdmStorage, err := s.ds.NewMDMAppleMDMStorage(testCertPEM, testKeyPEM)