For nylig stod vi over for opgaven med at overvåge udløbsdatoen for certifikaterne på Windows-servere. Det kom dog til at ske, efter at certifikaterne flere gange blev til græskar, præcis når den ansvarlige for deres forlængelse, en skæg kollega, var på ferie. Derefter begyndte vi at mistænke, at vi skulle tænke over dette. Da vi langsomt implementerer overvågningssystemet NetXMS, blev det den primære og i princippet eneste kandidat til denne opgave.
Resultatet blev til sidst præsenteret som følger:

Og selve processen derefter.
Lad os komme i gang. Der findes ingen indbygget tæller for udløbne certifikater i NetXMS, så vi skal oprette vores egen og bruge scripts til at sikre dataene. Selvfølgelig på Powershell, da det er Windows. Scriptet skal læse alle certifikater i operativsystemet, tage udløbsdatoen i dage og sende det tal til NetXMS. Gennem dets agent. Lad os starte med det.
Første mulighed, den nemmeste. Bare få antallet af dage til udløbet af certifikatet med den nærmeste dato.
For at serveren NetXMS skal vide om vores brugerdefinerede parameter, skal den modtage den fra agenten. Ellers vil denne parameter ikke kunne tilføjes, på grund af dens fravær. Derfor tilføjer vi en linje for den eksterne parameter i agentens konfigurationsfil nxagentd.conf med navnet HTTPS.CertificateExpireDateSimple, hvor vi angiver kommandoen til at køre scriptet:
ExternalParameter = HTTPS.CertificateExpireDateSimple: powershell.exe -File "servershareNetXMS_CertExpireDateSimple.ps1"I betragtning af at scriptet køres over netværket, skal vi ikke glemme at tage højde for , samt ikke glemme andre "-NoLogo -NoProfile -NonInteractive" parametre, som jeg udelod for at forbedre læsbarheden af koden.
Som resultat ser agentkonfigurationen omtrent således ud:
#
# 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"Derefter skal du gemme konfigurationen og genstarte agenten. Dette kan gøres fra NetXMS-konsollen: åbne konfigurationen (Edit agent’s configuration file), redigere, udføre Save&Apply, hvorefter det faktisk vil ske det samme. Herefter skal konfigurationen genlæses (Poll > Configuration), hvis du ikke kan vente. Efter disse handlinger burde det være muligt at tilføje vores brugerdefinerede parameter.
I NetXMS-konsollen går vi til Data Collection Configuration Testserveren, som vi skal overvåge certifikater på, og vi opretter en ny parameter der (i fremtiden, efter opsætningen, giver det mening at flytte den til skabelonerne). Vælg HTTPS.CertificateExpireDateSimple fra listen, indtast en beskrivelse med et forståeligt navn, indstil typen til Integer, og konfigurer den nødvendige forespørgselsinterval. For debugging formål giver det mening at gøre den kortere, for eksempel 30 sekunder. Det er det, nu er vi klar.
Vi kan kontrollere ... nej, det er for tidligt. Lige nu får vi naturligvis ikke noget. Bare fordi, at scriptet ikke er skrevet endnu. Lad os rette dette udeladt. Scriptet vil blot returnere et tal, antallet af dage tilbage, indtil certifikatets udløbsdato. Den korteste af de eksisterende. Eksempel på script:
try {
# Hent alle certifikater fra certifikatlageret
$lmCertificates = @( Get-ChildItem -Recurse -path 'Cert:LocalMachineMy' -ErrorAction Stop )
# Hvis der ikke er certifikater, returner "10 år"
if ($lmCertificates.Count -eq 0) { return 3650 }
# Hent udløbsdatoer for alle certifikater
$expirationDates = @( $lmCertificates | ForEach-Object { return $_.NotAfter } )
# Hent den mest nærliggende udløbsdato af dem alle
$minExpirationDate = ($expirationDates | Measure-Object -Minimum -ErrorAction Stop ).Minimum
# Konverter den mest nærliggende udløbsdato til antal tilbageværende dage med nedrunding
$daysLeft = [Math]::Floor( ($minExpirationDate - [DateTime]::Now).TotalDays )
# Returner værdien
return $daysLeft
}
catch {
return -1
}Sådan:

723 dage, der er næsten to år tilbage, før certifikatet udløber. Det giver mening, for jeg har fornyet certifikaterne til Exchange testmiljøet for nylig.
Dette var den enkle løsning. Måske vil nogle være tilfredse med det, men vi ønskede mere. Vi satte os for at få en liste over alle certifikater på serveren, navn for navn, og se, hvor mange dage der er tilbage, inden hvert certifikat udløber.
Den anden mulighed, noget mere kompliceret.
Igen redigerer vi agentens konfiguration og skriver i stedet for linjen med ExternalParameter to andre:
ExternalList = HTTPS.CertificateNames: powershell.exe -File "serversharenetxms_CertExternalNames.ps1"
ExternalParameter = HTTPS.CertificateExpireDate(*): powershell.exe -File "serversharenetxms_CertExternalParameter.ps1" -CertificateId "$1"I ExternalList vi får blot en liste af strenge. I vores tilfælde, en liste af strenge med certifikatnavne. Denne liste får vi med et script. Navnet på listen er HTTPS.CertificateNames.
Scriptet 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)"
}
}Og så i ExternalParameter Vi indtaster strenge fra listen ExternalList, og i udgangen får vi det samme antal dage for hver enkelt. Identifikatoren er Thumbprint på certifikatet. Bemærk, at HTTPS.CertificateExpireDate i denne variant indeholder en stjerne (*). Dette er nødvendigt, så den kan modtage eksterne variable, netop vores CertificateId.
NetXMS_CertExpireDate.ps1 scriptet:
#Определяем входящий параметр $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)"
}I Data Collection Configuration på serveren opretter vi en ny parameter. I Parameter vælger vi vores HTTPS.CertificateExpireDate(*) fra listen og (vær opmærksom!) ændrer stjernen til {instance}. Dette vigtige punkt vil gøre det muligt at oprette en separat tæller for hver instans (certifikat). Resten udfyldes som i den tidligere version:

For at tællerne kan oprettes, skal vi på fanen Instance Discovery vælge Agent List fra listen og i feltet List Name skrive navnet på vores ExternalList fra scriptet — HTTPS.CertificateNames.
Næsten klar, vent lidt, eller tving Poll > Configuration og Poll > Instance Discovery, hvis det er umuligt at vente. Som resultat får vi alle vores certifikater med udløbsdatoer:
Er det hvad vi har brug for? Ja, men en lille perfektionisme-kamæleon ser på denne unødvendige Thumbprint i tællernavnet med tristhed og lader os ikke afslutte artiklen. For at tilfredsstille det åbner vi igen tællerens egenskaber og på fanen Instance Discovery tilføjer vi det skrevne script i feltet 'Instance discovery filter script' (NetXMS' interne sprog) script:
instance = $1;
if (instance ~= "^(.*)s-s[T:[a-zA-Z0-9]+]$")
{
return %(true, instance, $1);
}
return true;som vil filtrere Thumbprint:

For at vise det filtreret skal vi på fanen General ændre Description fra CertificateExpireDate: {instance} til CertificateExpireDate: {instance-name}:

Det er det, endelig mål i KDPV:
Skønt, ikke sandt?
Det er tilbage at tilpasse alarmer, så de sendes via e-mail, når certifikatets udløb nærmer sig sin logiske slutning.
1. Først skal vi oprette en hændelsesskabelon (Event Template) til aktivering, når tællerens værdi falder til en bestemt grænse, som vi angiver. I Event Configuration opretter vi to nye skabeloner med navne som CertificateExpireDate_Threshold_Activate med status Warning:

og en lignende CertificateExpireDate_Threshold_Deactivate med status Normal.
2. Dernæst går vi til tællerens egenskaber og på fanen Tresholds indstiller grænsen:

Her vælger vi vores oprettede events CertificateExpireDate_Threshold_Activate og CertificateExpireDate_Threshold_Deactivate, sætter antallet af målinger (Samples) til 1 (for denne tæller giver det ikke mening at sætte mere), værdien til 30 (dage), for eksempel, og det er vigtigt at indstille gentagelsesintervallet for eventen. For certificater i produktionen sætter jeg det til en gang om dagen (86400 sekunder), ellers kan man drukne i meddelelser (hvilket for øvrigt skete én gang, så meget, at mailboksen blev fyldt op i weekenden). Under fejlfinding er det værd at sætte det lavere, for eksempel 60 sekunder.
3. I Action Configuration opretter vi skabelonen til meddelelsen, næsten sådan her:

Alle disse %m, %S og lignende — er makroer, hvor værdierne fra vores parameter vil blive indsat. De er beskrevet nærmere i NetXMS.
4. Og til sidst, ved at samle de forrige punkter, i Event Processing Policy opretter vi en regel for, hvordan der skal oprettes en Alarm og sendes en mail:
Gem politikken, så er vi klar til at teste. Jeg sætter tærsklen højere for testens skyld. Jeg har et certifikat, der udløber om 723 dage, og for testen satte jeg det til 724. Som resultat får vi en alarm som denne:

og en sådan meddelelse via e-mail:

Nu er det helt sikkert, at vi er færdige. Vi kunne selvfølgelig have sat et dashboard op, bygge grafer, men for certificater vil det være nogle ret meningsløse og kedelige lige linjer, i modsætning til grafer for CPU- eller hukommelsesbelastning, for eksempel. Men det besvarer vi en anden gang.
Kilde: habr.com
