add additional logging for SCEP proxy and SCEP profiles (#39501)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #36361 

This PR adds some additional debug logging to log hostUUID:profileUUID
when renewing MDM managed certificates.
Also adds log statements when processing a profile, when hitting NDES or
Smallstep (not SCEP as it's a static challenge, that is fetched and
replaced, no external calls).

NDES: If we get a successful call (which is the standard, with errors on
the HTML page), we debug log, the entire HTML response, and the request
duration.
Smallstep: Normal API errors, non OK we log: status code, the status
text, the request duration, and spit out the entire body (max 2mb), if
more than 2mb we don't log the response body.

I tried looking for more relevant places, but couldn't really find any
that would make sense to log for this ticket.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.


## Testing

- [ ] Added/updated automated tests
- [x] QA'd all new/changed functionality manually -> Did a quick test
for some of the logs, but the NDES one is not really easy to verify.
This commit is contained in:
Magnus Jensen
2026-02-09 14:46:30 -05:00
committed by GitHub
parent a187842260
commit f987d6d042
4 changed files with 22 additions and 0 deletions
@@ -0,0 +1 @@
- Added additional logging for SCEP proxy requests and SCEP profile renewals.
+15
View File
@@ -15,12 +15,14 @@ import (
"time"
"github.com/Azure/go-ntlmssp"
"github.com/docker/go-units"
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
scepclient "github.com/fleetdm/fleet/v4/server/mdm/scep/client"
scepserver "github.com/fleetdm/fleet/v4/server/mdm/scep/server"
"github.com/fleetdm/fleet/v4/server/ptr"
"github.com/go-kit/kit/log/level"
"github.com/go-kit/log"
"github.com/google/uuid"
"golang.org/x/net/html/charset"
@@ -518,7 +520,9 @@ func (s *SCEPConfigService) GetNDESSCEPChallenge(ctx context.Context, proxy flee
return "", ctxerr.Wrap(ctx, err, "creating request")
}
req.SetBasicAuth(username, password)
startRequestTime := time.Now()
resp, err := client.Do(req)
endRequestTime := time.Now()
if err != nil {
return "", ctxerr.Wrap(ctx, err, "sending request")
}
@@ -551,6 +555,9 @@ func (s *SCEPConfigService) GetNDESSCEPChallenge(ctx context.Context, proxy flee
return "", ctxerr.Wrap(ctx,
NewNDESInsufficientPermissionsError("this account does not have sufficient permissions to enroll with SCEP. Please use a different account with NDES SCEP enroll permissions."))
}
// If we can't find a specific error, we log more context in terms of the request to further diagnose
level.Debug(s.logger).Log("msg", "failed to parse NDES challenge from admin URL response", "ca_type", fleet.CATypeNDESSCEPProxy, "raw_response", htmlString, "request_duration", endRequestTime.Sub(startRequestTime).Seconds())
return "", ctxerr.Wrap(ctx,
NewNDESInvalidError("could not retrieve the enrollment challenge password; invalid admin URL or credentials; please correct and try again"))
}
@@ -602,11 +609,19 @@ func (s *SCEPConfigService) GetSmallstepSCEPChallenge(ctx context.Context, ca fl
return "", ctxerr.Wrap(ctx, err, "creating request")
}
req.SetBasicAuth(ca.Username, ca.Password)
startRequestTime := time.Now()
resp, err := client.Do(req)
endRequestTime := time.Now()
if err != nil {
return "", ctxerr.Wrap(ctx, err, "sending request")
}
if resp.StatusCode != http.StatusOK {
reader := io.LimitReader(resp.Body, units.MiB*2)
if b, err := io.ReadAll(reader); err == nil {
level.Debug(s.logger).Log("msg", "failed to get Smallstep SCEP challenge", "status_code", resp.StatusCode, "status", resp.Status, "ca_type", fleet.CATypeSmallstep, "raw_response", string(b), "request_duration", endRequestTime.Sub(startRequestTime).Seconds())
} else {
level.Debug(s.logger).Log("msg", "failed to get Smallstep SCEP challenge and failed to read response body", "status_code", resp.StatusCode, "status", resp.Status, "ca_type", fleet.CATypeSmallstep, "read_error", err.Error(), "request_duration", endRequestTime.Sub(startRequestTime).Seconds())
}
return "", ctxerr.Wrap(ctx, fmt.Errorf("status code %d", resp.StatusCode), "getting Smallstep SCEP challenge")
}
defer resp.Body.Close()
+4
View File
@@ -2851,13 +2851,17 @@ func (ds *Datastore) RenewMDMManagedCertificates(ctx context.Context) error {
limit -= len(hostCertsToRenew)
totalHostCertsToRenew += len(hostCertsToRenew)
allHostAndProfileIdsToRenew := make([]string, len(hostCertsToRenew))
for _, hostCertToRenew := range hostCertsToRenew {
hostProfileClause += `(host_uuid = ? AND profile_uuid = ?) OR `
values = append(values, hostCertToRenew.HostUUID, hostCertToRenew.ProfileUUID)
allHostAndProfileIdsToRenew = append(allHostAndProfileIdsToRenew, hostCertToRenew.HostUUID+":"+hostCertToRenew.ProfileUUID)
}
hostProfileClause = strings.TrimSuffix(hostProfileClause, " OR ")
level.Info(ds.logger).Log("msg", "Renewing MDM managed certificates", "len", len(hostCertsToRenew), "type", hostCertType, "platform", hostPlatform)
level.Debug(ds.logger).Log("msg", "Host and profile IDs for certificates to renew", "host_profile_ids", allHostAndProfileIdsToRenew)
err = ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
_, err := tx.ExecContext(ctx, updateQuery+hostProfileClause+")", values...)
if err != nil {
+2
View File
@@ -5573,6 +5573,7 @@ func preprocessProfileContents(
if ndesConfig == nil {
ndesConfig = groupedCAs.NDESSCEP
}
level.Debug(logger).Log("msg", "fetching NDES challenge", "host_uuid", hostUUID, "profile_uuid", profUUID)
// Insert the SCEP challenge into the profile contents
challenge, err := scepConfig.GetNDESSCEPChallenge(ctx, *ndesConfig)
if err != nil {
@@ -5661,6 +5662,7 @@ func preprocessProfileContents(
"This error should never happen since we validated/populated CAs earlier", "ca_name", caName)
continue
}
level.Debug(logger).Log("msg", "fetching Smallstep SCEP challenge", "host_uuid", hostUUID, "profile_uuid", profUUID)
challenge, err := scepConfig.GetSmallstepSCEPChallenge(ctx, *ca)
if err != nil {
detail := fmt.Sprintf("Fleet couldn't populate $FLEET_VAR_%s. %s", fleet.FleetVarSmallstepSCEPChallengePrefix, err.Error())