Vor kurzem standen wir vor der Aufgabe, die Gültigkeit von Zertifikaten auf Windows-Servern zu überwachen. Nun, es war nicht wirklich eine plötzliche Entscheidung, nachdem die Zertifikate mehrmals in Kürbisse verwandelt wurden, während unser kollegialer für die Verlängerung verantwortlicher Bartträger im Urlaub war. Nach diesem Vorfall haben wir etwas Verdacht geschöpft und beschlossen, darüber nachzudenken. Da wir schrittweise das Monitoring-System NetXMS einführen, wurde es der Haupt- und im Grunde der einzige Kandidat für diese Aufgabe.
Das Ergebnis wurde schließlich in folgender Form erzielt:

Und der Prozess selbst geht weiter.
Los geht's. Es gibt keinen integrierten Zähler für ablaufende Zertifikate in NetXMS, also müssen wir unseren eigenen erstellen und Skripte verwenden, um die Daten bereitzustellen. Natürlich mit Powershell, schließlich ist es Windows. Das Skript muss alle Zertifikate im Betriebssystem auslesen, ihr Ablaufdatum in Tagen erfassen und diese Zahl an NetXMS über dessen Agenten übermitteln. Damit beginnen wir.
Option eins, die einfachste. Einfach die Anzahl der Tage bis zum Ablauf des nächstgelegenen Zertifikats erhalten.
Damit der NetXMS-Server von der Existenz unseres benutzerdefinierten Parameters erfährt, muss er ihn vom Agenten erhalten. Andernfalls kann dieser Parameter aufgrund seiner Abwesenheit nicht hinzugefügt werden. Daher fügen wir in die Konfigurationsdatei des Agenten nxagentd.conf die Zeile des externen Parameters mit dem Namen HTTPS.CertificateExpireDateSimple, in der wir den Aufruf des Skripts eintragen:
ExternalParameter = HTTPS.CertificateExpireDateSimple: powershell.exe -File "servershareNetXMS_CertExpireDateSimple.ps1"Da das Skript über das Netzwerk gestartet wird, sollten wir die , sowie die anderen „-NoLogo -NoProfile -NonInteractive“ beachten, die ich zur besseren Lesbarkeit des Codes weggelassen habe.
Infolgedessen sieht die Agenten-Konfiguration ungefähr so aus:
#
# NetXMS agent configuration file
# Created by agent installer at Thu Jun 13 11:24:43 2019
#
MasterServers = netxms.corp.testcompany.ru
ConfigIncludeDir = C:NetXMSetcnxagentd.conf.d
LogFile = {syslog}
FileStore = C:NetXMSvar
SubAgent = ecs.nsm
SubAgent = filemgr.nsm
SubAgent = ping.nsm
SubAgent = logwatch.nsm
SubAgent = portcheck.nsm
SubAgent = winperf.nsm
SubAgent = wmi.nsm
ExternalParameter = HTTPS.CertificateExpireDateSimple: powershell.exe -File "servershareNetXMS_CertExpireDateSimple.ps1"Nachdem das Konfig gespeichert wurde, muss der Agent neu gestartet werden. Dies kann über die NetXMS-Konsole erfolgen: die Konfiguration öffnen (Edit agent’s configuration file), bearbeiten, Save&Apply ausführen, woraufhin im Grunde dasselbe passiert. Dann die Konfiguration neu auslesen (Poll > Configuration), falls man nicht länger warten kann. Nach diesen Schritten sollte es möglich sein, unseren benutzerdefinierten Parameter hinzuzufügen.
In der NetXMS-Konsole gehen wir zu Data Collection Configuration eines Testservers, auf dem wir die Zertifikate überwachen wollen, und erstellen dort einen neuen Parameter (später, nach der Konfiguration, macht es Sinn, ihn in die Vorlagen zu übertragen). Wir wählen HTTPS.CertificateExpireDateSimple aus der Liste, geben eine Beschreibung mit einem verständlichen Namen ein, setzen den Typ auf Integer und konfigurieren das Abfrageintervall. Für die Fehlersuche ist es sinnvoll, es kürzer zu machen, beispielsweise 30 Sekunden. Alles, fertig, das reicht vorerst.
Man kann prüfen... nein, noch ist es zu früh. Momentan werden wir natürlich nichts erhalten. Einfach weil das Skript noch nicht geschrieben wurde. Wir beheben diese Lücke. Das Skript gibt einfach eine Zahl aus, die Anzahl der Tage, die bis zum Ablauf des Zertifikats verbleiben. Die minimalste von allen verfügbaren. Beispielskript:
try {
# holt alle Zertifikate aus dem Zertifikatsspeicher
$lmCertificates = @( Get-ChildItem -Recurse -path 'Cert:LocalMachineMy' -ErrorAction Stop )
# wenn keine Zertifikate vorhanden sind, 10 Jahre zurückgeben
if ($lmCertificates.Count -eq 0) { return 3650 }
# bekommt das Ablaufdatum aller Zertifikate
$expirationDates = @( $lmCertificates | ForEach-Object { return $_.NotAfter } )
# bekommt das nächstgelegene Ablaufdatum von allen
$minExpirationDate = ($expirationDates | Measure-Object -Minimum -ErrorAction Stop ).Minimum
# konvertiert das nächstgelegene Ablaufdatum in die verbleibenden Tage, abrundet
$daysLeft = [Math]::Floor( ($minExpirationDate - [DateTime]::Now).TotalDays )
# gibt den Wert zurück
return $daysLeft
}
catch {
return -1
}Es ergibt sich Folgendes:

723 Tage verbleiben, bis das Zertifikat abläuft, es sind fast zwei Jahre. Logisch, denn ich habe die Zertifikate für die Exchange-Testumgebung erst kürzlich neu ausgestellt.
Das war eine einfache Variante. Vielleicht reicht das einigen, aber wir wollten mehr. Unsere Aufgabe war es, eine Liste aller Zertifikate auf dem Server, namentlich, zu erhalten und bei jedem die Anzahl der verbleibenden Tage bis zum Ablauf des Zertifikats zu sehen.
Die zweite Option, etwas komplizierter.
Wir bearbeiten erneut die Konfiguration des Agents und anstelle der Zeile mit ExternalParameter schreiben wir zwei andere:
ExternalList = HTTPS.CertificateNames: powershell.exe -File "serversharenetxms_CertExternalNames.ps1"
ExternalParameter = HTTPS.CertificateExpireDate(*): powershell.exe -File "serversharenetxms_CertExternalParameter.ps1" -CertificateId "$1"Im ExternalList wir erhalten einfach eine Liste von Zeichenfolgen. In unserem Fall eine Liste von Zeichenfolgen mit den Namen der Zertifikate. Diese Liste von Zeichenfolgen erhalten wir durch das Skript. Der Listenname ist HTTPS.CertificateNames.
Das Skript NetXMS_CertNames.ps1:
#Список возможных имен сертификатов
$nameTypeList = @(
[System.Security.Cryptography.X509Certificates.X509NameType]::SimpleName,
[System.Security.Cryptography.X509Certificates.X509NameType]::DnsName,
[System.Security.Cryptography.X509Certificates.X509NameType]::DnsFromAlternativeName,
[System.Security.Cryptography.X509Certificates.X509NameType]::UrlName,
[System.Security.Cryptography.X509Certificates.X509NameType]::EmailName,
[System.Security.Cryptography.X509Certificates.X509NameType]::UpnName
)
#Ищем все сертификаты, имеющие закрытый ключ
$certList = @( Get-ChildItem -Path 'Cert:LocalMachineMy' | Where-Object { $_.HasPrivateKey -eq $true } )
#Проходим по списку сертификатов, формируем строку "Имя сертификата - Дата - Thumbprint" и возвращаем её
foreach ($cert in $certList) {
$name = '(unknown name)'
try {
$thumbprint = $cert.Thumbprint
$dateExpire = $cert.NotAfter
foreach ($nameType in $nameTypeList) {
$name_temp = $cert.GetNameInfo( $nameType, $false)
if ($name_temp -ne $null -and $name_temp -ne '') {
$name = $name_temp;
break;
}
}
Write-Output "$($name) - $($dateExpire.ToString('dd.MM.yyyy')) - [T:$($thumbprint)]"
}
catch {
Write-Error -Message "Error processing certificate list: $($_.Exception.Message)"
}
}Und schon in ExternalParameter Wir geben Strings aus der Liste ExternalList ein und erhalten die gleiche Anzahl an Tagen für jede. Der Identifikator ist der Thumbprint des Zertifikats. Beachten Sie, dass HTTPS.CertificateExpireDate in dieser Variante ein Sternchen (*) enthält. Dies ist notwendig, damit er externe Variablen akzeptiert, genau unser CertificateId.
Script NetXMS_CertExpireDate.ps1:
#Определяем входящий параметр $CertificateId
param (
[Parameter(Mandatory=$false)]
[String]$CertificateId
)
#Проверка на существование
if ($CertificateId -eq $null) {
Write-Error -Message "CertificateID parameter is required!"
return
}
#По Thumbprint из строки в $CertificateId ищем сертификат и определяем его Expiration Date
$certId = $CertificateId;
try {
if ($certId -match '^.*[T:(?<Thumbprint>[A-Z0-9]+)]$') {
$thumbprint = $Matches['Thumbprint']
$certificatePath = "Cert:LocalMachineMy$($thumbprint)"
if (Test-Path -PathType Leaf -Path $certificatePath ) {
$certificate = Get-Item -Path $certificatePath;
$certificateExpirationDate = $certificate.NotAfter
$certificateDayToLive = [Math]::Floor( ($certificateExpirationDate - [DateTime]::Now).TotalDays )
Write-Output "$($certificateDayToLive)";
}
else {
Write-Error -Message "No certificate matching this thumbprint found on this server $($certId)"
}
}
else {
Write-Error -Message "CertificateID provided in wrong format. Must be FriendlyName [T:<thumbprint>]"
}
}
catch {
Write-Error -Message "Error while executing script: $($_.Exception.Message)"
}In der Data Collection Configuration des Servers erstellen wir einen neuen Parameter. Im Parameter wählen wir unseren HTTPS.CertificateExpireDate(*) aus der Liste und (Achtung!) ersetzen das Sternchen durch {instance}. Dieser wichtige Punkt ermöglicht es, einen separaten Zähler für jede Instanz (Zertifikat) zu erstellen. Der Rest wird wie in der vorherigen Variante ausgefüllt:

Damit es Zähler gibt, aus denen man erstellen kann, müssen wir auf der Registerkarte Instance Discovery die Agent List aus der Liste auswählen und im Feld List Name den Namen unserer ExternalList aus dem Skript eintragen — HTTPS.CertificateNames.
Fast fertig, etwas warten oder manuell Poll > Configuration und Poll > Instance Discovery durchführen, wenn man überhaupt nicht warten kann. Das Ergebnis sind all unsere Zertifikate mit Ablaufdaten:
Das, was wir brauchen? Ja, nur der Perfektionismus schaut auf diesen unnötigen Thumbprint im Namen des Zählers mit traurigen Augen und lässt mich den Artikel nicht beenden. Um ihn zu besänftigen, öffnen wir wieder die Zähler Eigenschaften und fügen auf der Registerkarte Instance Discovery im Feld „Instance discovery filter script“ folgendes hinzu: (die interne Sprache von NetXMS) Script:
instance = $1;
if (instance ~= "^(.*)s-s[T:[a-zA-Z0-9]+]$")
{
return %(true, instance, $1);
}
return true;das den Thumbprint filtriert:

Und um ihn gefiltert anzuzeigen, ändern wir auf der Registerkarte General im Feld Description CertificateExpireDate: {instance} in CertificateExpireDate: {instance-name}:

Alles, endlich das Ziel der KDPV:
Schön, oder?
Es bleibt nur noch, die Benachrichtigungen einzurichten, damit sie per E-Mail gesendet werden, wenn das Zertifikat dem logischen Ende näher kommt.
1. Zuerst muss ein Ereignisvorlage (Event Template) erstellt werden, um sie zu aktivieren, wenn der Zählerstand einen von uns festgelegten Schwellenwert erreicht. In Event Configuration erstellen wir zwei neue Vorlagen mit Namen, sagen wir mal CertificateExpireDate_Threshold_Activate mit dem Status Warning:

und analog CertificateExpireDate_Threshold_Deactivate mit dem Status Normal.
2. Dann gehen wir zu den Zähler Eigenschaften und konfigurieren auf der Registerkarte Tresholds den Schwellenwert:

Wir wählen unsere erstellten Events CertificateExpireDate_Threshold_Activate und CertificateExpireDate_Threshold_Deactivate aus, setzen die Anzahl der Messungen (Samples) auf 1 (für diesen Zähler macht es keinen Sinn, mehr einzustellen), den Wert auf 30 (Tage), zum Beispiel, und, was wichtig ist, wir konfigurieren die Wiederholfrequenz des Events. Für Zertifikate in der Produktion stelle ich es einmal täglich (86400 Sekunden) ein, andernfalls kann man in Benachrichtigungen untergehen (was übrigens einmal passiert ist, sodass das Postfach über das Wochenende überfüllt war). Für die Debugging-Zeit macht es Sinn, es geringer einzustellen, beispielsweise auf 60 Sekunden.
3. In Action Configuration erstellen wir eine Vorlage für die Benachrichtigungs-E-Mail, wie diese hier:

All diese %m, %S usw. sind Makros, in die die Werte aus unserem Parameter eingesetzt werden. Sie sind ausführlicher beschrieben in NetXMS.
4. Schließlich, indem wir die vorherigen Punkte zusammenführen, erstellen wir in Event Processing Policy eine Regel, nach der ein Alarm erstellt und eine E-Mail gesendet wird:
Wir speichern die Richtlinie, alles, jetzt können wir testen. Setzen wir den Schwellenwert höher zur Überprüfung. Mein nächstes Zertifikat läuft in 723 Tagen ab, zur Überprüfung habe ich 724 eingestellt. Infolgedessen erhalten wir so einen Alarm:

und so eine Benachrichtigung per E-Mail:

Jetzt ist wirklich alles. Natürlich könnte man das Dashboard einstellen, Grafiken erstellen, aber für Zertifikate wären das eher sinnlose und langweilige gerade Linien, im Gegensatz zu Grafiken zur CPU- oder Speicherauslastung, zum Beispiel. Aber dazu später mehr.
Quelle: habr.com
