Onlangs kregen we de taak om de geldigheid van certificaten op Windows-servers te monitoren. Of liever, dat kwam aan de orde nadat certificaten verschillende keren in pumpkin waren veranderd op momenten dat de verantwoordelijke voor de verlenging, een baardige collega, met vakantie was. Hierna begonnen we iets te vermoeden en besloten we erover na te denken. Aangezien we gestaag het monitoring systeem NetXMS implementeren, werd dit de belangrijkste en eigenlijk de enige kandidaat voor deze taak.
Het resultaat werd uiteindelijk in de volgende vorm verkregen:

En het proces daarna.
Laten we beginnen. Er is geen ingebouwde teller voor de vervaldatum van certificaten in NetXMS, dus we moeten zelf een maken en scripts gebruiken om deze met gegevens te voorzien. Natuurlijk doen we dit met Powershell; immers, het is Windows. Het script moet alle certificaten in het besturingssysteem lezen, de vervaldatum in dagen ophalen en dit getal naar NetXMS doorgeven. Via zijn agent. Daarmee beginnen we.
Optie één, de eenvoudigste. Gewoon het aantal dagen tot de vervaldatum van het certificaat met de dichtstbijzijnde datum ophalen.
Om de NetXMS-server op de hoogte te stellen van ons aangepaste parameter, moet deze het ontvangen van de agent. Anders kan deze parameter niet worden toegevoegd vanwege het ontbreken ervan. Daarom voegen we in het configuratiebestand van de agent nxagentd.conf een regel van de externe parameter met de naam HTTPS.CertificateExpireDateSimple, waarin we de uitvoering van het script beschrijven:
ExternalParameter = HTTPS.CertificateExpireDateSimple: powershell.exe -File "servershareNetXMS_CertExpireDateSimple.ps1"Gezien het feit dat het script via het netwerk wordt uitgevoerd, moeten we niet vergeten over de , en ook niet vergeten andere '-NoLogo -NoProfile -NonInteractive' die ik heb weggelaten voor de leesbaarheid van de code.
Als gevolg hiervan ziet de agentconfiguratie er ongeveer zo uit:
#
# 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"Na dit moet de configuratie worden opgeslagen en de agent opnieuw worden opgestart. Dit kan vanuit de NetXMS-console: open de configuratie (Bewerk configuratiebestand van de agent), bewerkt het, voer Opslaan & Toepassen uit, waardoor hetzelfde gebeurt. Dan moet je de configuratie opnieuw lezen (Poll > Configuratie), als je echt niet kunt wachten. Na deze acties zou het mogelijk moeten zijn om onze aangepaste parameter toe te voegen.
In de NetXMS-console gaan we naar Configuratie van gegevensverzameling de proefserver waarop we de certificaten willen monitoren en waar we een nieuwe parameter aanmaken (later, na de configuratie, is het zinvol om deze naar de sjablonen te verplaatsen). We kiezen HTTPS.CertificateExpireDateSimple uit de lijst, geven een duidelijke naam op voor de Beschrijving, stellen het type in op Integer en configureren het pollinginterval. Voor de debugperiode is het zinvol om dit korter te maken, bijvoorbeeld 30 seconden. Alles is klaar, voorlopig is dit voldoende.
We kunnen controleren... nee, het is nog te vroeg. Op dit moment krijgen we natuurlijk niets. Gewoon omdat het script nog niet is geschreven. Laten we dat gebrek verhelpen. Het script zal gewoon een nummer geven, het aantal dagen dat nog over is tot de vervaldatum van het certificaat. De meest minimale van alle beschikbare. Voorbeeldscript:
try {
# Verkrijg alle certificaten uit de certificaatopslag
$lmCertificates = @( Get-ChildItem -Recurse -path 'Cert:LocalMachineMy' -ErrorAction Stop )
# Als er geen certificaten zijn, return "10 jaar"
if ($lmCertificates.Count -eq 0) { return 3650 }
# Verkrijg de vervaldatum van alle certificaten
$expirationDates = @( $lmCertificates | ForEach-Object { return $_.NotAfter } )
# Verkrijg de dichtstbijzijnde vervaldatum van allemaal
$minExpirationDate = ($expirationDates | Measure-Object -Minimum -ErrorAction Stop ).Minimum
# Converteer de dichtstbijzijnde vervaldatum naar het aantal resterende dagen met naar beneden afgerond
$daysLeft = [Math]::Floor( ($minExpirationDate - [DateTime]::Now).TotalDays )
# Return de waarde
return $daysLeft
}
catch {
return -1
}Een cliënt komt binnen

723 dagen, tot de vervaldatum van het certificaat is er nog bijna twee jaar. Logisch, omdat ik de certificaten op de Exchange testomgeving pas recent opnieuw heb uitgegeven.
Dit was een eenvoudige optie. Misschien is dit voor sommigen al voldoende, maar wij wilden meer. We hebben onszelf als doel gesteld om een lijst te krijgen van alle certificaten op de server, met naam, en bij elk te zien hoeveel dagen er nog zijn tot de vervaldatum van het certificaat.
De tweede optie, iets ingewikkelder.
We bewerken weer de agentconfiguratie en vervangen de regel met ExternalParameter door twee andere:
ExternalList = HTTPS.CertificateNames: powershell.exe -File "serversharenetxms_CertExternalNames.ps1"
ExternalParameter = HTTPS.CertificateExpireDate(*): powershell.exe -File "serversharenetxms_CertExternalParameter.ps1" -CertificateId "$1"In ExternalList we krijgen gewoon een lijst van strings. In ons geval, een lijst van strings met de namen van certificaten. Deze lijst van strings krijgen we via het script. De naam van de lijst - HTTPS.CertificateNames.
Script 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)"
}
}En al in ExternalParameter We provide strings from the ExternalList as input, and as output we get the same number of days for each. The identifier is the Thumbprint of the certificate. Note that HTTPS.CertificateExpireDate in this variant contains an asterisk (*). This is necessary so that it accepts external variables, specifically our CertificateId.
NetXMS_CertExpireDate.ps1 script:
#Определяем входящий параметр $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 the server's Data Collection Configuration, we create a new parameter. In Parameter we select our HTTPS.CertificateExpireDate(*) from the list, and (attention!) change the asterisk to {instance}. This important step will allow us to create a separate counter for each instance (certificate). The rest is filled in as in the previous variant:

To have something to create counters from, in the Instance Discovery tab, we need to select Agent List from the list and type the name of our ExternalList from the script — HTTPS.CertificateNames.
Almost ready, just need to wait a bit or force Poll > Configuration and Poll > Instance Discovery if waiting is impossible. As a result, we get all our certificates with expiration dates:
Is this what we need? Well, yes, but the perfectionist inside looks at this unnecessary Thumbprint in the counter name with sad eyes and won't let the article be finished. To feed it, we open the counter properties again and in the Instance Discovery tab, in the 'Instance discovery filter script' field, we add the script written in (NetXMS internal language):
instance = $1;
if (instance ~= "^(.*)s-s[T:[a-zA-Z0-9]+]$")
{
return %(true, instance, $1);
}
return true;which will filter out the Thumbprint:

And to display it filtered, in the General tab in the Description field, we change CertificateExpireDate: {instance} to CertificateExpireDate: {instance-name}:

That's it, finally the finish line from KDPV:
Isn't it beautiful?
We just need to set up alerts so they come to our email when the certificate expiration date approaches.
1. First, we need to create an Event Template to activate it when the counter's value decreases to a threshold set by us. In the Event Configuration we create two new templates named, say, CertificateExpireDate_Threshold_Activate with a Warning status:

and a similar one CertificateExpireDate_Threshold_Deactivate with a Normal status.
2. Next, we go to the counter properties and in the Tresholds tab set the threshold:

waar we onze gemaakte evenementen CertificateExpireDate_Threshold_Activate en CertificateExpireDate_Threshold_Deactivate kiezen, stellen we het aantal metingen (Samples) in op 1 (voor deze teller heeft het geen zin om meer in te stellen), de waarde op 30 (dagen), bijvoorbeeld, en belangrijker nog, we stellen de herhalingsfrequentie van het evenement in. Voor certificaten in productie stel ik dit eenmaal per dag in (86400 seconden), anders kun je verdrinken in meldingen (wat trouwens één keer is gebeurd, en zo erg dat de mailbox in het weekend volraakte). Voor de testperiode is het zinvol om het lager in te stellen, bijvoorbeeld 60 seconden.
3. In Actieconfiguratie maken we een sjabloon voor de melding, zoals deze:

Al deze %m, %S enz. zijn macro's waarin waarden uit onze parameter zullen worden ingevoegd. Meer hierover is beschreven in NetXMS.
4. En tenslotte, door de vorige punten samen te voegen, in Evenement Verwerkingsbeleid maken we een regel volgens welke een Alarm zal worden aangemaakt en een e-mail zal worden verzonden:
We slaan het beleid op, dat is het, we kunnen test uitvoeren. Laten we de drempel hoger stellen voor de controle. Mijn dichtstbijzijnde certificaat verloopt over 723 dagen, voor de controle heb ik 724 ingesteld. Het resultaat is deze alarm:

en deze melding per e-mail:

Nu is alles zeker compleet. Natuurlijk zou je een dashboard kunnen instellen, grafieken kunnen maken, maar voor certificaten zullen dat enkele zinloze en saaie rechte lijnen zijn, in tegenstelling tot de grafieken van CPU- of geheugengebruik, bijvoorbeeld. Maar daarover later meer.
Bron: habr.com
