Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Récemment, nous avons eu la tâche de surveiller la durée de vie des certificats sur des serveurs Windows. Cela a été déclenché après que les certificats se soient transformés en citrouille plusieurs fois, au moment où le collègue responsable de leur renouvellement, barbu, était en vacances. Après cela, nous avons commencé à nous méfier et avons décidé d’y réfléchir. Comme nous implémentons lentement le système de surveillance NetXMS, il est devenu le principal et unique candidat pour cette mission.

Le résultat final a été obtenu sous la forme suivante :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Et le processus qui suit.

Allons-y. Il n'y a pas de compteur intégré pour la date d'expiration des certificats dans NetXMS, donc il faut créer le sien et utiliser des scripts pour alimenter ce compteur en données. Bien sûr, en Powershell, c'est Windows. Le script doit lire tous les certificats présents dans le système d'exploitation, obtenir leur date d'expiration en jours et transmettre ce nombre à NetXMS. Via son agent. C'est par là que nous allons commencer.

Première option, la plus simple. Il suffit d'obtenir le nombre de jours restants avant l'expiration du certificat avec la date la plus proche.

Pour que le serveur NetXMS soit informé de notre paramètre personnalisé, il doit le recevoir de l'agent. Sinon, il sera impossible d'ajouter ce paramètre en raison de son absence. Ainsi, dans le fichier de configuration de l'agent nxagentd.conf nous ajoutons la ligne du paramètre externe nommé HTTPS.CertificateExpireDateSimple, dans laquelle nous spécifions le lancement du script :

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

Étant donné que le script est exécuté sur le réseau, n'oubliez pas la Execution Policy, ainsi que d'autres options comme « -NoLogo -NoProfile -NonInteractive », que j'ai omises pour une meilleure lisibilité du code.

Ce qui fait que la configuration de l'agent ressemble à peu près à ceci :

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

Après cela, il faut sauvegarder la configuration et redémarrer l'agent. Cela peut être fait depuis la console NetXMS : ouvrir la configuration (Edit agent’s configuration file), modifier, faire Save&Apply, ce qui réalisera finalement la même chose. Ensuite, relisez la configuration (Poll > Configuration), si vous ne pouvez vraiment pas attendre. Après ces actions, la possibilité d'ajouter notre paramètre personnalisé devrait apparaître.

Dans la console NetXMS, dirigez-vous vers Configuration de la collecte de données du serveur cible où nous allons surveiller les certificats et créons un nouveau paramètre (ultérieurement, après la configuration, il serait judicieux de le transférer dans les modèles). Sélectionnons HTTPS.CertificateExpireDateSimple dans la liste, entrons une Description avec un nom explicite, mettons le type sur Integer et configurons l'intervalle de sondage. Pour le débogage, il est logiquement judicieux de le rendre plus court, par exemple 30 secondes. Voilà, c'est prêt, c'est suffisant pour le moment.

On peut vérifier... non, c'est encore trop tôt. Actuellement, naturellement, nous n'obtiendrons rien. Simplement parce que le script n'est pas encore écrit. Corrigeons cet oubli. Le script va simplement renvoyer un chiffre, le nombre de jours restants avant l'expiration du certificat. Le plus minimal de tous ceux qui sont disponibles. Exemple de script :

try {
    # Obtenons tous les certificats du magasin de certificats
    $lmCertificates = @( Get-ChildItem -Recurse -path 'Cert:LocalMachineMy' -ErrorAction Stop )
     
    # S'il n'y a pas de certificats, retourne "10 ans"
    if ($lmCertificates.Count -eq 0) { return 3650 }
 
    # Obtenons la date d'expiration de tous les certificats
    $expirationDates = @( $lmCertificates | ForEach-Object { return $_.NotAfter } )
 
    # Obtenons la date d'expiration la plus proche de toutes
    $minExpirationDate = ($expirationDates | Measure-Object -Minimum -ErrorAction Stop ).Minimum
 
    # Convertissons la date d'expiration la plus proche en nombre de jours restants, en arrondissant vers le bas
    $daysLeft = [Math]::Floor( ($minExpirationDate - [DateTime]::Now).TotalDays )
 
    # Renvoie la valeur
    return $daysLeft
}
catch {
    return -1
}

Il en ressort ceci :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

723 jours, presque deux ans avant l'expiration du certificat. Logique, car j'ai récemment renouvelé les certificats sur l'Exchange du banc d'essai.

C'était l'option simple. Peut-être que cela conviendra à certains, mais nous voulions plus. Notre objectif était d'obtenir une liste de tous les certificats sur le serveur, nommés un par un, et de voir pour chacun le nombre de jours restants avant l'expiration du certificat.

Deuxième option, un peu plus complexe.

Nous modifions à nouveau la configuration de l'agent et là, au lieu de la ligne avec ExternalParameter, nous écrivons deux autres lignes :

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

Dans ExternalList nous obtenons simplement une liste de chaînes. Dans notre cas, une liste de chaînes avec les noms des certificats. Nous allons obtenir cette liste de chaînes avec un script. Le nom de la liste est 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)"
    }
}

Et déjà dans ExternalParameter Nous soumettons des chaînes de la liste ExternalList, et en retour, nous obtenons le même nombre de jours pour chaque élément. L'identifiant est le Thumbprint du certificat. Notez que HTTPS.CertificateExpireDate dans ce cas contient un astérisque (*). Cela est nécessaire pour accepter des variables externes, notamment notre 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)"
}

Dans la configuration de collecte de données du serveur, créons un nouveau paramètre. Dans Parameter, choisissons notre HTTPS.CertificateExpireDate(*) de la liste, et, (attention !) remplaçons l'astérisque par {instance}. Ce point important permettra de créer un compteur distinct pour chaque instance (certificat). Le reste est complété comme dans le cas précédent :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Pour que les compteurs puissent être créés, dans l'onglet Instance Discovery, il faut sélectionner Agent List dans la liste et dans le champ List Name, entrer le nom de notre ExternalList du script — HTTPS.CertificateNames.

C'est presque prêt, il suffit d'attendre un peu ou de forcer un Poll > Configuration et Poll > Instance Discovery, si l'attente est vraiment impossible. En résultat, nous obtenons tous nos certificats avec leurs dates d'expiration :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

C'est ce qu'il faut ? Oui, mais ce petit ver du perfectionnisme regarde ce Thumbprint inutile dans le nom du compteur avec des yeux tristes et ne me laisse pas finir l'article. Pour le rassasier, rouvre à nouveau les propriétés du compteur et dans l'onglet Instance Discovery, dans le champ « Instance discovery filter script », ajoute le script écrit en NXSL (le langage interne de NetXMS) :

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

qui filtrera le Thumbprint :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Et pour l'afficher filtré, dans l'onglet Général, dans le champ Description, remplaçons CertificateExpireDate: {instance} par CertificateExpireDate: {instance-name}:

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Voilà, enfin la fin du KDPV :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

C'est beau, non ?

Il reste à configurer des alertes pour recevoir des notifications par e-mail lorsque la date d'expiration du certificat approche de sa fin logique.

1. Tout d'abord, il faut créer un modèle d'événement (Event Template) pour l'activer lorsque la valeur du compteur diminue à un certain seuil que nous avons défini. Dans Event Configuration créons deux nouveaux modèles nommés, disons CertificateExpireDate_Threshold_Activate avec le statut Avertissement :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

et un modèle similaire CertificateExpireDate_Threshold_Deactivate avec le statut Normal.

2. Ensuite, allons dans les propriétés du compteur et dans l'onglet Tresholds, configurons le seuil :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

où nous choisissons nos événements créés CertificateExpireDate_Threshold_Activate et CertificateExpireDate_Threshold_Deactivate, nous mettons le nombre d'échantillons (Samples) à 1 (dans ce compteur, il n'est pas nécessaire de mettre plus), une valeur de 30 (jours), par exemple, et, ce qui est important, nous configurons le temps de répétition de l'événement. Pour les certificats en production, je le configure une fois par jour (86400 secondes), sinon on peut être submergé d'alertes (ce qui s'est d'ailleurs déjà produit une fois, au point que ma boîte mail a débordé durant le week-end). Pendant la phase de débogage, il est pertinent de mettre une valeur plus faible, 60 secondes, par exemple.

3. Dans Configuration de l'Action nous créons un modèle de mail d'alerte, comme celui-ci :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Tous ces %m, %S, etc. — ce sont des macros, qui seront remplacées par les valeurs de notre paramètre. Détails disponibles dans le manuel NetXMS.

4. Enfin, en combinant les points précédents, dans Politique de Traitement des Événements nous créons une règle, selon laquelle une alarme sera créée et un mail sera envoyé :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Nous sauvegardons la politique, c'est tout, nous pouvons tester. Mettons un seuil plus élevé pour la vérification. Mon certificat le plus proche expire dans 723 jours, j'ai mis 724 pour le test. En résultat, nous obtiendrons cette alarme :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

et cet e-mail d'alerte :

Surveillance de la durée de vie des certificats sous Windows avec NetXMS

Voilà, maintenant c'est tout. Bien sûr, il aurait été possible de configurer un tableau de bord, de créer des graphiques, mais pour les certificats, ce seront des lignes droites plutôt inutiles et ennuyeuses, contrairement aux graphiques de charge du processeur ou de la mémoire, par exemple. Mais, nous en parlerons une autre fois.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster