Onlangs werden we geconfronteerd met de taak om de geldigheidsduur van certificaten op Windows-servers te controleren. Hoe is dat toch gekomen, nadat de certificaten meerdere keren in pompoenen waren veranderd, en dat terwijl de bebaarde collega die verantwoordelijk was voor de verlenging ervan op vakantie was? Daarna kregen we een vermoeden en besloten we erover na te denken. Omdat we het NetXMS-monitoringsysteem langzaam implementeren, is dit de belangrijkste en in principe enige kandidaat voor deze taak geworden.
Het resultaat werd uiteindelijk in de volgende vorm verkregen:

En het proces zelf gaat door.
Laten we gaan. NetXMS beschikt niet over een ingebouwde teller voor het verlopen van certificaten. U moet dus uw eigen teller maken en scripts gebruiken om de teller van gegevens te voorzien. Op Powershell is het natuurlijk Windows. Het script moet alle certificaten in het besturingssysteem lezen, de vervaldatum ervan in dagen noteren en dit nummer doorgeven aan NetXMS. Via zijn agent. Laten we met hem beginnen.
Optie een, de eenvoudigste. Zoek eenvoudigweg het aantal dagen op totdat het certificaat verloopt, met de dichtstbijzijnde datum.
Om ervoor te zorgen dat de NetXMS-server op de hoogte is van het bestaan van onze aangepaste parameter, moet deze deze van de agent ontvangen. Anders kan deze parameter niet worden toegevoegd vanwege het ontbreken ervan. Daarom staat in het agentconfiguratiebestand nxagentd.conf we voegen een regel externe parameters toe met de naam HTTPS.CertificaatVervaldatumEenvoudig, waarin we het script voor de lancering schrijven:
ExternalParameter = HTTPS.CertificateExpireDateSimple: powershell.exe -File "servershareNetXMS_CertExpireDateSimple.ps1"Aangezien het script via het netwerk wordt gestart, moet u rekening houden met het volgende: en vergeet ook de andere "-NoLogo -NoProfile -NonInteractive" niet. Ik heb deze weggelaten omdat de code daardoor beter leesbaar is.
De agentconfiguratie ziet er dan 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"Hierna moet u de configuratie opslaan en de agent opnieuw opstarten. U kunt dit doen via de NetXMS-console: open de configuratie (bewerk het configuratiebestand van de agent), bewerk deze en voer Save&Apply uit. Dit heeft hetzelfde resultaat. Lees dan de configuratie opnieuw (Poll > Configuratie), als u echt niet de kracht hebt om te wachten. Na deze stappen zou u onze aangepaste parameter moeten kunnen toevoegen.
Ga in de NetXMS-console naar Configuratie van gegevensverzameling de experimentele server waarop we de certificaten gaan bewaken en daar een nieuwe parameter gaan aanmaken (later, na de configuratie, is het zinvol om deze over te brengen naar sjablonen). Selecteer HTTPS.CertificateExpireDateSimple uit de lijst, voer een Beschrijving in met een duidelijke naam, stel het type in op Integer en configureer het polling-interval. Voor foutopsporingsdoeleinden is het zinvol om de duur in te korten, bijvoorbeeld 30 seconden. Alles is klaar, dat is voor nu voldoende.
Je kunt het controleren... nee, het is te vroeg. Nu krijgen we natuurlijk niets. Simpelweg omdat het script nog niet geschreven is. Wij corrigeren deze omissie. Het script geeft simpelweg een getal weer: het aantal dagen dat nog resteert totdat het certificaat verloopt. Het meest minimale van allemaal. Voorbeeld script:
try {
# Получаем все сертификаты из хранилища сертификатов
$lmCertificates = @( Get-ChildItem -Recurse -path 'Cert:LocalMachineMy' -ErrorAction Stop )
# Если сертификатов нет, вернуть "10 лет"
if ($lmCertificates.Count -eq 0) { return 3650 }
# Получаем Expiration Date всех сертификатов
$expirationDates = @( $lmCertificates | ForEach-Object { return $_.NotAfter } )
# Получаем наиболее близкий Expiration Date из всех
$minExpirationDate = ($expirationDates | Measure-Object -Minimum -ErrorAction Stop ).Minimum
# Конвертируем наиболее близкий Expiration Date в количество оставшихся дней с округлением в меньшую сторону
$daysLeft = [Math]::Floor( ($minExpirationDate - [DateTime]::Now).TotalDays )
# Возвращаем значение
return $daysLeft
}
catch {
return -1
}Het ziet er als volgt uit:

Nog 723 dagen, bijna twee jaar voordat het certificaat verloopt. Dat is logisch, want ik heb onlangs de certificaten voor de Exchange-teststand opnieuw uitgegeven.
Het was een simpele keuze. Voor sommigen zou dit misschien voldoende zijn, maar wij wilden meer. We hebben onszelf de taak gesteld om een lijst te maken van alle certificaten op de server, gesorteerd op naam, en te kijken hoeveel dagen er nog resteren tot de vervaldatum van elk certificaat.
De tweede optie, een beetje ingewikkelder.
We bewerken opnieuw de agentconfiguratie en in plaats van de regel met ExternalParameter schrijven we er twee andere:
ExternalList = HTTPS.CertificateNames: powershell.exe -File "serversharenetxms_CertExternalNames.ps1"
ExternalParameter = HTTPS.CertificateExpireDate(*): powershell.exe -File "serversharenetxms_CertExternalParameter.ps1" -CertificateId "$1"В Externe lijst We krijgen alleen een lijst met strings. In ons geval is dat een lijst met strings met certificaatnamen. Met behulp van een script verkrijgen we een lijst van deze regels. Lijstnaam - HTTPS.Certificaatnamen.
NetXMS_CertNames.ps1-script:
#Список возможных имен сертификатов
$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 Externe parameter We voeren de regels uit de ExternalList-lijst in de invoer in, en bij de uitvoer krijgen we voor elk hetzelfde aantal dagen. De identificatie is de vingerafdruk van het certificaat. Houd er rekening mee dat HTTPS.CertificateExpireDate in deze variant een asterisk (*) bevat. Dit is nodig om externe variabelen te accepteren, met name onze 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)"
}Maak een nieuwe parameter in de gegevensverzamelingsconfiguratie van de server. In Parameter selecteren we de onze HTTPS.CertificaatVervaldatum(*) uit de lijst, en (let op!) verander de asterisk in {aanleg}. Dankzij deze belangrijke stap kunt u voor elk exemplaar (certificaat) een aparte teller aanmaken. De rest wordt ingevuld zoals in de vorige versie:

Om iets te hebben waarvan u tellers kunt maken, moet u op het tabblad Instance Discovery de Agent List selecteren en in het veld List Name de naam van onze ExternalList uit het script invoeren: HTTPS.CertificateNames.
Bijna klaar. Wacht nog even of forceer Poll > Configuratie en Poll > Instantiedetectie als u helemaal niet kunt wachten. Als gevolg hiervan ontvangen wij al onze certificaten met geldigheidsperiodes:
Wat heb je nodig? Nou ja, alleen de worm van perfectionisme kijkt met droevige ogen naar deze onnodige Duimafdruk in de tegennaam en staat mij niet toe het artikel af te maken. Om het te voeden, opent u de eigenschappen van de teller opnieuw en voegt u op het tabblad 'Instance Discovery' in het veld 'Instance Discovery filter script' het script toe dat is geschreven in (interne NetXMS-taal) script:
instance = $1;
if (instance ~= "^(.*)s-s[T:[a-zA-Z0-9]+]$")
{
return %(true, instance, $1);
}
return true;die Thumbprint zal filteren:

En om het gefilterd weer te geven, wijzigt u op het tabblad Algemeen in het veld Beschrijving CertificateExpireDate: {instance} in Certificaat vervaldatum: {instance-name}:

Dat is het dan, eindelijk het eindresultaat van KDPV:
Is het niet prachtig?
Het enige wat u nu nog hoeft te doen, is het instellen van meldingen, zodat deze naar uw e-mailadres worden verzonden wanneer de geldigheidsduur van het certificaat nadert.
1. Eerst moet u een gebeurtenissjabloon maken om deze te activeren wanneer de tellerwaarde daalt tot een door ons ingestelde drempelwaarde. IN Evenement configuratie we maken twee nieuwe sjablonen met namen, laten we zeggen Certificaatvervaldatum_Drempel_Activeren met waarschuwingsstatus:

en vergelijkbaar Certificaatvervaldatum_drempel_deactiveren met de status Normaal.
2. Ga vervolgens naar de eigenschappen van de teller en stel op het tabblad Drempelwaarden de drempelwaarde in:

waarbij we de door ons aangemaakte gebeurtenissen CertificateExpireDate_Threshold_Activate en CertificateExpireDate_Threshold_Deactivate selecteren, het aantal metingen (Samples) instellen op 1 (het heeft geen zin om deze teller specifieker in te stellen), een waarde van 30 (dagen) bijvoorbeeld, en, wat belangrijk is, de herhalingstijd van de gebeurtenis instellen. Voor certificaten in productie stel ik het eenmaal per dag in (86400 seconden), anders word je overspoeld met meldingen (wat overigens maar één keer is gebeurd, en wel zo vaak dat mijn mailbox afgelopen weekend vol zat). Voor debugtijd is het zinvol om een kortere waarde in te stellen, bijvoorbeeld 60 seconden.
3. in Actie Configuratie Maak een sjabloon voor een kennisgevingsbrief, zoals deze:

Al deze %m, %S, enz. zijn macro's waarin de waarden van onze parameters worden gesubstitueerd. Ze worden in meer detail beschreven in NetXMS.
4. En ten slotte, door de voorgaande punten te combineren, Beleid voor gebeurtenisverwerking we maken een regel aan op basis waarvan een alarm wordt aangemaakt en een brief wordt verzonden:
We slaan het beleid op, dat is alles, we kunnen het testen. Laten we de drempel hoger leggen om het te controleren. Mijn dichtstbijzijnde certificaat verloopt over 723 dagen, dus ik heb het op 724 ingesteld om het te controleren. Als gevolg hiervan krijgen we het volgende alarm:

en een dergelijke kennisgeving per post:

Dat is nu wel zeker. Je zou natuurlijk een dashboard kunnen opzetten en grafieken kunnen maken, maar voor certificaten zouden dat saaie, nietszeggende rechte lijnen zijn, in tegenstelling tot grafieken over de processor- of geheugenbelasting bijvoorbeeld. Maar daarover praten we een andere keer.
Bron: www.habr.com
