agent production logging

This commit is contained in:
Oliver Kieselbach
2026-03-09 23:58:30 +01:00
parent ba72e08c9b
commit a84f8e6165
2 changed files with 89 additions and 13 deletions
@@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
@@ -19,11 +21,6 @@ namespace AutopilotMonitor.Agent.Core.Security
/// <summary>
/// Polls the certificate store until a valid MDM certificate is found or the timeout expires.
/// </summary>
/// <param name="thumbprint">Optional specific certificate thumbprint to wait for</param>
/// <param name="timeoutMinutes">Maximum wait time in minutes (0 = wait indefinitely)</param>
/// <param name="logger">Logger for status output</param>
/// <param name="cancellationToken">Cancellation token for clean shutdown</param>
/// <returns>The MDM certificate, or null if the timeout expired or was cancelled</returns>
public static async Task<X509Certificate2> WaitForMdmCertificateAsync(
string thumbprint = null,
int timeoutMinutes = 480,
@@ -39,30 +36,36 @@ namespace AutopilotMonitor.Agent.Core.Security
while (!cancellationToken.IsCancellationRequested)
{
// Lightweight check: opens cert store, scans by issuer+EKU, closes — takes milliseconds
var cert = CertificateHelper.FindMdmCertificate(thumbprint);
var cert = CertificateHelper.FindMdmCertificate(thumbprint, logger);
if (cert != null && CertificateHelper.IsCertificateValid(cert))
if (cert != null)
{
// No IsCertificateValid check here: freshly provisioned SCEP certs can have
// a NotBefore slightly in the future due to clock skew between device and CA.
// The cert existing in the store with correct issuer+EKU is sufficient.
var elapsed = DateTime.UtcNow - startTime;
logger?.Info($"Await-enrollment: MDM certificate found after {FormatElapsed(elapsed)} — Issuer={cert.Issuer}, Thumbprint={cert.Thumbprint}");
logger?.Info($"Await-enrollment: MDM certificate found after {FormatElapsed(elapsed)} — " +
$"Issuer={cert.Issuer}, Thumbprint={cert.Thumbprint}, " +
$"Valid={cert.NotBefore:yyyy-MM-dd HH:mm:ss}..{cert.NotAfter:yyyy-MM-dd HH:mm:ss}");
return cert;
}
var totalElapsed = DateTime.UtcNow - startTime;
// Check timeout
if (totalElapsed >= timeout)
{
logger?.Warning($"Await-enrollment: Timeout after {FormatElapsed(totalElapsed)} — no MDM certificate found");
LogCertificateStoreDetails(logger);
return null;
}
// Periodic status log (every 1 minute)
// Periodic status with cert counts (every 1 minute)
if (DateTime.UtcNow - lastLogTime >= LogInterval)
{
var remaining = timeout - totalElapsed;
logger?.Info($"Await-enrollment: Waiting for MDM certificate... (elapsed: {FormatElapsed(totalElapsed)}, remaining: {FormatElapsed(remaining)})");
var storeSummary = GetCertificateStoreSummary();
logger?.Info($"Await-enrollment: Waiting for MDM certificate... " +
$"(elapsed: {FormatElapsed(totalElapsed)}, remaining: {FormatElapsed(remaining)}, {storeSummary})");
lastLogTime = DateTime.UtcNow;
}
@@ -80,6 +83,79 @@ namespace AutopilotMonitor.Agent.Core.Security
return null;
}
/// <summary>
/// Returns a short summary of cert counts per store, e.g. "LocalMachine=2, CurrentUser=0".
/// </summary>
private static string GetCertificateStoreSummary()
{
try
{
int lmCount = 0, cuCount = 0;
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadOnly);
lmCount = store.Certificates.Count;
}
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadOnly);
cuCount = store.Certificates.Count;
}
return $"certs in store: LM={lmCount}, CU={cuCount}";
}
catch
{
return "certs in store: unknown";
}
}
/// <summary>
/// Full cert store dump — only on timeout to help diagnose why no MDM cert was matched.
/// </summary>
private static void LogCertificateStoreDetails(AgentLogger logger)
{
if (logger == null) return;
try
{
var stores = new[]
{
new { Location = StoreLocation.LocalMachine, Name = StoreName.My },
new { Location = StoreLocation.CurrentUser, Name = StoreName.My }
};
foreach (var storeInfo in stores)
{
using (var store = new X509Store(storeInfo.Name, storeInfo.Location))
{
store.Open(OpenFlags.ReadOnly);
var certs = store.Certificates.OfType<X509Certificate2>().ToList();
logger.Info($"Await-enrollment: {storeInfo.Location}\\{storeInfo.Name} — {certs.Count} certificate(s):");
foreach (var cert in certs)
{
var hasClientAuth = cert.Extensions
.OfType<X509EnhancedKeyUsageExtension>()
.Any(ext => ext.EnhancedKeyUsages
.OfType<Oid>()
.Any(oid => oid.Value == "1.3.6.1.5.5.7.3.2"));
logger.Info($" - Issuer={cert.Issuer}, Thumbprint={cert.Thumbprint}, " +
$"ClientAuth={hasClientAuth}, Valid={cert.NotBefore:yyyy-MM-dd}..{cert.NotAfter:yyyy-MM-dd}");
}
}
}
}
catch (Exception ex)
{
logger.Warning($"Await-enrollment: Could not read certificate store: {ex.Message}");
}
}
private static string FormatElapsed(TimeSpan elapsed)
{
if (elapsed.TotalHours >= 1)
@@ -1 +1 @@
391
397