Monitor Certificate Expiration in Windows on NetXMS

Recently, we faced the task of monitoring the validity of certificates on servers running Windows. Well, how I got up, after the certificates turned into a pumpkin several times, at the very time when the bearded colleague responsible for their renewal was on vacation. After that, we suspected something and decided to think about it. Since we are slowly implementing the NetXMS monitoring system, it has become the main and, in principle, the only candidate for this task.

The result ended up looking like this:

Monitor Certificate Expiration in Windows on NetXMS

And the process goes on.

Go. There is no built-in certificate expiration counter in NetXMS, so you need to create your own and use scripts to provide it with data. Of course, on Powershell, it's Windows. The script must read all the certificates in the operating system, take their expiration date in days from there and pass this number to NetXMS. Through his agent. That's where we'll start.

Option One, simplest. Just get the number of days until the certificate expires with the nearest date.

In order for the NetXMS server to know about the existence of our custom parameter, it must receive it from the agent. Otherwise, this parameter cannot be added, due to its absence. Therefore, in the agent configuration file nxagentd.conf we add an external parameter string named HTTPS.CertificateExpireDateSimple, in which we register the launch of the script:

ExternalParameter = HTTPS.CertificateExpireDateSimple: powershell.exe -File "servershareNetXMS_CertExpireDateSimple.ps1"

Given that the script is run over the network, you need to remember about Execution policy, and don't forget the other "-NoLogo -NoProfile -NonInteractive", which I omitted for better readability of the code.

As a result, the agent config looks something like this:

#
# 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"

After that, you need to save the config and restart the agent. You can do this from the NetXMS console: open the config (Edit agent's confuguration file), edit it, execute Save&Apply, as a result of which, in fact, the same thing will happen. Then re-read the configuration (Poll > Configuration), if there is absolutely no strength to wait. After these steps, it should be possible to add our custom parameter.

In the NetXMS console, go to Data Collection Configuration experimental server on which we are going to monitor certificates and create a new parameter there (later, after configuration, it makes sense to transfer it to templates). Select HTTPS.CertificateExpireDateSimple from the list, enter Description with a friendly name, set the type to Integer, and set the polling interval. For debugging time, it makes sense to make it shorter, 30 seconds, for example. Everything is ready, enough for now.

You can check ... no, it's still early. Now, of course, we won't get anything. Simply because the script has not been written yet. We correct this omission. The script will simply return a number, the number of days left until the certificate expires. The smallest of all available. Script example:

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
}

It turns out like this:

Monitor Certificate Expiration in Windows on NetXMS

723 days, with almost two more years until the certificate expires. It is logical, because I reissued certificates for the Exchange of the test bench quite recently.

It was an easy option. Probably, someone will be satisfied with this, but we wanted more. We set ourselves the task of getting a list of all certificates on the server, by name, and for each one to see the number of days left until the certificate expires.

The second option, is somewhat more complicated.

Again we edit the agent config and there, instead of a line with ExternalParameter, we write two others:

ExternalList = HTTPS.CertificateNames: powershell.exe -File "serversharenetxms_CertExternalNames.ps1"
ExternalParameter = HTTPS.CertificateExpireDate(*): powershell.exe -File "serversharenetxms_CertExternalParameter.ps1" -CertificateId "$1"

Π’ ExternalList we get just a list of strings. In our case, a list of strings with certificate names. We will receive the list of these lines by a script. List name - 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)"
    }
}

And already in ExternalParameter we feed rows from the ExternalList list as input, and at the output we get the same number of days for each. The identifier is the Thumbprint of the certificate. Note that HTTPS.CertificateExpireDate contains an asterisk (*) in this variation. This is necessary so that it accepts external variables, just our 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 the Data Collection Configuration of the server, we create a new parameter. In Parameter we choose our HTTPS.CertificateExpireDate(*) from the list, and, (attention!) change the asterisk to {instance}. This important point will allow you to create a separate counter for each instance (certificate). The rest is filled in as in the previous version:

Monitor Certificate Expiration in Windows on NetXMS

In order for the counters to be created from, on the Instance Discovery tab, select Agent List from the list and in the List Name field enter the name of our ExternalList from the script - HTTPS.CertificateNames.

Almost done, wait a bit or force Poll > Configuration and Poll > Instance Discovery if it's impossible to wait at all. As a result, we get all our certificates with validity periods:

Monitor Certificate Expiration in Windows on NetXMS

What do you need? Well, yes, only the worm of perfectionism looks at this unnecessary Thumbprint in the name of the counter with sad eyes and does not allow to finish the article. To feed it, open the properties of the counter again and on the Instance Discovery tab in the field "Instance discovery filter script" add the script written in NXSL (NetXMS internal language) script:

instance = $1;
 if (instance ~= "^(.*)s-s[T:[a-zA-Z0-9]+]$")
 {
 return %(true, instance, $1);
 }
 return true;

which will filter out Thumbprint:

Monitor Certificate Expiration in Windows on NetXMS

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

Monitor Certificate Expiration in Windows on NetXMS

That's it, finally the finish from KDPV:

Monitor Certificate Expiration in Windows on NetXMS

Is it beauty?

It remains to configure alerts so that they come to the mail when the certificate comes to its logical end.

1. First you need to create an event template (Event Template) to activate it when the counter value decreases to some threshold we set. IN Event Configuration create two new templates named, say CertificateExpireDate_Threshold_Activate with Warning status:

Monitor Certificate Expiration in Windows on NetXMS

and similar CertificateExpireDate_Threshold_Deactivate with Normal status.

2. Next, go to the properties of the counter and set the threshold on the Tresholds tab:

Monitor Certificate Expiration in Windows on NetXMS

where we select our created events CertificateExpireDate_Threshold_Activate and CertificateExpireDate_Threshold_Deactivate, set the number of samples (Samples) 1 (specifically for this counter, it makes no sense to set more), a value of 30 (days), for example, and, importantly, set the event repetition time. For certificates in production, I set them once a day (86400 seconds), otherwise you can drown in notifications (which, by the way, happened once, and in such a way that the mailbox overflowed over the weekend). At the time of debugging, it makes sense to set it smaller, 60 seconds, for example.

3. In Action Configuration create a notification email template like this:

Monitor Certificate Expiration in Windows on NetXMS

All those %m, %S, etc. β€” macros into which values ​​from our parameter will be substituted. They are described in more detail in manual NetXMS.

4. And, finally, combining the previous points, in Event Processing Policy create a rule by which an Alarm will be created and a letter will be sent:

Monitor Certificate Expiration in Windows on NetXMS

We save the policy, everything can be tested. Let's set the threshold higher to check. My nearest certificate expires in 723 days, I set 724 for verification. As a result, we get the following alarm:

Monitor Certificate Expiration in Windows on NetXMS

and this email notification:

Monitor Certificate Expiration in Windows on NetXMS

Now that's all for sure. It would be possible, of course, to set up a dashboard, build graphs, but for certificates these will be somewhat meaningless and boring straight lines, unlike CPU or memory load graphs, for example. But, more about that some other time.

Source: habr.com

Add a comment