Fix bug where Fleet cannot start with expired ABM cert (#21929)

This commit is contained in:
Sarah Gillespie
2024-09-10 15:55:22 -05:00
committed by GitHub
parent ff9cb68385
commit 8d651b477c
3 changed files with 95 additions and 72 deletions
+86 -61
View File
@@ -499,7 +499,18 @@ the way that the Fleet server works.
mdmPushService = nanomdm_pushsvc.New(mdmStorage, mdmStorage, pushProviderFactory, nanoMDMLogger)
}
// validate Apple APNs/SCEP config
checkMDMAssets := func(names []fleet.MDMAssetName) (bool, error) {
_, err = ds.GetAllMDMConfigAssetsByName(context.Background(), names)
if err != nil {
if fleet.IsNotFound(err) || errors.Is(err, mysql.ErrPartialResult) {
return false, nil
}
return false, err
}
return true, nil
}
// reconcile Apple Business Manager configuration environment variables with the database
if config.MDM.IsAppleAPNsSet() || config.MDM.IsAppleSCEPSet() {
if !config.MDM.IsAppleAPNsSet() {
initFatal(errors.New("Apple APNs MDM configuration must be provided when Apple SCEP is provided"), "validate Apple MDM")
@@ -508,40 +519,63 @@ the way that the Fleet server works.
}
if len(config.Server.PrivateKey) == 0 {
initFatal(errors.New("inserting APNs and SCEP assets"), "missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
initFatal(errors.New("inserting MDM APNs and SCEP assets"), "missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}
// parse the APNs and SCEP assets from the config
_, apnsCertPEM, apnsKeyPEM, err := config.MDM.AppleAPNs()
if err != nil {
initFatal(err, "validate Apple APNs certificate and key")
initFatal(err, "parse Apple APNs certificate and key from config")
}
_, appleSCEPCertPEM, appleSCEPKeyPEM, err := config.MDM.AppleSCEP()
if err != nil {
initFatal(err, "validate Apple SCEP certificate and key")
initFatal(err, "load Apple SCEP certificate and key from config")
}
err = ds.InsertMDMConfigAssets(context.Background(), []fleet.MDMConfigAsset{
{Name: fleet.MDMAssetAPNSCert, Value: apnsCertPEM},
{Name: fleet.MDMAssetAPNSKey, Value: apnsKeyPEM},
{Name: fleet.MDMAssetCACert, Value: appleSCEPCertPEM},
{Name: fleet.MDMAssetCAKey, Value: appleSCEPKeyPEM},
})
if err != nil {
// duplicate key errors mean that we already
// have a value for those keys in the
// database, fail to initalize on other
// cases.
if !mysql.IsDuplicate(err) {
initFatal(err, "inserting MDM APNs and SCEP assets")
}
// first we'll check if the APNs and SCEP assets are already in the database and
// only insert config values if they're not already present in the database
toInsert := make([]fleet.MDMConfigAsset, 0, 4)
level.Warn(logger).Log("msg", "Your server already has stored SCEP and APNs certificates. Fleet will ignore any certificates provided via environment variables when this happens.")
// check DB for APNs assets
found, err := checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetAPNSCert, fleet.MDMAssetAPNSKey})
switch {
case err != nil:
initFatal(err, "reading APNs assets from database")
case !found:
toInsert = append(toInsert, fleet.MDMConfigAsset{Name: fleet.MDMAssetAPNSCert, Value: apnsCertPEM}, fleet.MDMConfigAsset{Name: fleet.MDMAssetAPNSKey, Value: apnsKeyPEM})
default:
level.Warn(logger).Log("msg", "Your server already has stored APNs certificates. Fleet will ignore any certificates provided via environment variables when this happens.")
}
// check DB for SCEP assets
found, err = checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetCACert, fleet.MDMAssetCAKey})
switch {
case err != nil:
initFatal(err, "reading SCEP assets from database")
case !found:
toInsert = append(toInsert, fleet.MDMConfigAsset{Name: fleet.MDMAssetCACert, Value: appleSCEPCertPEM}, fleet.MDMConfigAsset{Name: fleet.MDMAssetCAKey, Value: appleSCEPKeyPEM})
default:
level.Warn(logger).Log("msg", "Your server already has stored SCEP certificates. Fleet will ignore any certificates provided via environment variables when this happens.")
}
if len(toInsert) > 0 {
if len(config.Server.PrivateKey) == 0 {
initFatal(errors.New("inserting APNs and SCEP assets"), "missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}
if err := ds.InsertMDMConfigAssets(context.Background(), toInsert); err != nil {
if mysql.IsDuplicate(err) {
// we already checked for existing assets so we should never have a duplicate key error here; we'll add a debug log just in case
level.Debug(logger).Log("msg", "unexpected duplicate key error inserting MDM APNs and SCEP assets")
} else {
initFatal(err, "inserting MDM APNs and SCEP assets")
}
}
}
}
// validate Apple BM config
// reconcile Apple Business Manager configuration environment variables with the database
if config.MDM.IsAppleBMSet() {
// TODO: Confirm whether we should have any fatal license errors
if !license.IsPremium() {
initFatal(errors.New("Apple Business Manager configuration is only available in Fleet Premium"), "validate Apple BM")
}
@@ -552,36 +586,38 @@ the way that the Fleet server works.
appleBM, err := config.MDM.AppleBM()
if err != nil {
initFatal(err, "validate Apple BM token, certificate and key")
initFatal(err, "parse Apple BM token, certificate and key from config")
}
err = ds.InsertMDMConfigAssets(context.Background(), []fleet.MDMConfigAsset{
{Name: fleet.MDMAssetABMKey, Value: appleBM.KeyPEM},
{Name: fleet.MDMAssetABMCert, Value: appleBM.CertPEM},
})
if err != nil {
// duplicate key errors mean that we already
// have a value for those keys in the
// database, fail to initalize on other
// cases.
if !mysql.IsDuplicate(err) {
initFatal(err, "inserting MDM ABM assets")
}
toInsert := make([]fleet.MDMConfigAsset, 0, 4)
found, err := checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetABMKey, fleet.MDMAssetABMCert})
switch {
case err != nil:
initFatal(err, "reading ABM assets from database")
case !found:
toInsert = append(toInsert, fleet.MDMConfigAsset{Name: fleet.MDMAssetABMKey, Value: appleBM.KeyPEM}, fleet.MDMConfigAsset{Name: fleet.MDMAssetABMCert, Value: appleBM.CertPEM})
default:
level.Warn(logger).Log("msg", "Your server already has stored ABM certificates and token. Fleet will ignore any certificates provided via environment variables when this happens.")
} else {
// insert the ABM token without any metdata,
// it'll be picked by the
// apple_mdm_dep_profile_assigner cron and
// backfilled
tok := &fleet.ABMToken{
EncryptedToken: appleBM.EncryptedToken,
// 2000-01-01 is our "zero value" for time
RenewAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
}
_, err = ds.InsertABMToken(context.Background(), tok)
if err != nil {
initFatal(err, "save ABM token")
}
if len(toInsert) > 0 {
err := ds.InsertMDMConfigAssets(context.Background(), toInsert)
switch {
case err != nil && mysql.IsDuplicate(err):
// we already checked for existing assets so we should never have a duplicate key error here; we'll add a debug log just in case
level.Debug(logger).Log("msg", "unexpected duplicate key error inserting ABM assets")
case err != nil:
initFatal(err, "inserting ABM assets")
default:
// insert the ABM token without any metdata; it'll be picked by the
// apple_mdm_dep_profile_assigner cron and backfilled
if _, err := ds.InsertABMToken(context.Background(), &fleet.ABMToken{
EncryptedToken: appleBM.EncryptedToken,
RenewAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC), // 2000-01-01 is our "zero value" for time
}); err != nil {
initFatal(err, "save ABM token")
}
}
}
}
@@ -591,17 +627,6 @@ the way that the Fleet server works.
initFatal(err, "loading app config")
}
checkMDMAssets := func(names []fleet.MDMAssetName) (bool, error) {
_, err = ds.GetAllMDMConfigAssetsByName(context.Background(), names)
if err != nil {
if fleet.IsNotFound(err) || errors.Is(err, mysql.ErrPartialResult) {
return false, nil
}
return false, err
}
return true, nil
}
appCfg.MDM.EnabledAndConfigured = false
appCfg.MDM.AppleBMEnabledAndConfigured = false
if len(config.Server.PrivateKey) > 0 {
@@ -612,7 +637,7 @@ the way that the Fleet server works.
fleet.MDMAssetAPNSCert,
})
if err != nil {
initFatal(err, "validating MDM assets from database")
initFatal(err, "loading MDM assets from database")
}
var appleBMCerts bool
@@ -621,14 +646,14 @@ the way that the Fleet server works.
fleet.MDMAssetABMKey,
})
if err != nil {
initFatal(err, "validating MDM ABM assets from database")
initFatal(err, "loading MDM ABM assets from database")
}
if appleBMCerts {
// the ABM certs are there, check if a token exists and if so, apple
// BM is enabled and configured.
count, err := ds.GetABMTokenCount(context.Background())
if err != nil {
initFatal(err, "validating MDM ABM token from database")
initFatal(err, "loading MDM ABM token from database")
}
appCfg.MDM.AppleBMEnabledAndConfigured = count > 0
}