Retifff's Blog

Мой ИТ блог — пошаговые мануалы

Мониторинг срока действия внешних сертификатов в NetXMS

Posted by Retifff на 05.02.2024

Вообще, я хотел не эту статью писать, а другую, но в ней будет использоваться как раз мониторинг срока действия внешних сертификатов, поэтому придётся сначала эту написать.

Вообще про мониторинг сертификатов, которые находятся на серверах с Windows , я уже писал: Мониторинг срока действия сертификатов в Windows на NetXMS. Но мониторить сертификаты бывает нужно не только на Windows-машинах, но и на Linux, на каких-то балансировщиках, апплаинсах, внутренних сайтах и на каких-то внешних ресурсах (сайтах в Интернете, к примеру). Именно поэтому в этой статье разберём подробно, как этот мониторинг настроить.

  1. Использование встроенных счетчиков NetXMS
  2. Использование скрипта для автоматического создания счетчиков под каждый сертификат

1 Использование встроенных счетчиков NetXMS

Они появились примерно с 4-й версии, раньше не было. Очень удобно стало.

Давайте создадим два счётчика. Выбираем в качестве жертвы какую-то ноду с Windows, у меня это контроллер домена dc01 в тестовой среде. Естественно, сначала нужно поставить на него агента.

1.1 Открываем Data Collection Configuration ноды, создаем первый счётчик (подробно, как это сделать, можно прочитать в моей первой статье на эту тему Настройка счётчиков в NetXMS), выбираем метрику и в фильтре вводим «certificate». Нам выдается список имеющихся метрик для мониторинга сертификатов:

Выбираем там «Days until expiration of X.509 certificate of remote TLS service». Заполняем поля, в поле «Metric», в скобках надо будет заменить звездочку (*) на имя хоста и порт, через запятую. Для примера я взял сайт https://netxms.com/. В поле «Display name» можно написать что-то более понятное для нас, чем то, что туда автоматически подставляется:

Интервал в продакшене я использую 1200 секунд, здесь слишком часто делать опрос необходимости нет.

1.2 Второй счетчик создаём аналогично, с метрикой «Expiration date (YYYY-MM-DD) of X.509 certificate of remote TLS service»:

В общем-то всё. В тонкости я вникать не буду, порог на первом счетчике настроить труда не составит. Получится примерно так:

По второму счетчику, обратите внимание, что там тип строка, следовательно, какого-то вменяемого порога срабатывания настроить мы не сможем. А с первым без проблем, ставим 30 дней, к примеру, всё как в прошлой статье Настройка оповещений при приближении конца срока действия сертификата.

Всё довольно просто и понятно. Сложнее становится, когда сертификатов много и под каждый создавать отдельный счетчик откровенно лень. Тем более, что получается, нужно на один сертификат два счетчика, один с датой истечения срока сертификата (просто на него смотреть удобней), второй с количеством дней, оставшихся до этой даты.

Тогда на помощь приходит второй вариант. Он, в общем-то, основан на первой моей статье про мониторинг сертификатов, только с адаптацией под внешние сертификаты.

2 Использование скрипта для автоматического создания счетчиков под каждый сертификат

2.1 В конфиге агента пишем такие две строчки (не забудьте перезапустить агента, после редактирования конфига, это можно сделать прямо из консоли NetXMS, как и редактировать конфиг агента):

ExternalList = CertExpDaysLeftList: powershell.exe -NoLogo -STA -NoProfile -NonInteractive -File "\\test-company.mooo.com\SYSVOL\test-company.mooo.com\scripts\NetXMS_CheckExternalCertificateExpiration.ps1" -List
ExternalMetricProvider = powershell.exe -NoLogo -STA -NoProfile -NonInteractive -File "\\test-company.mooo.com\SYSVOL\test-company.mooo.com\scripts\NetXMS_CheckExternalCertificateExpiration.ps1":600

Обратите внимание, что в конфиге агента используется ExternalMetric вместо ExternalParameter в прошлой статье. Параметры ExternalParameter и ExternalParameterProvider стали уже Deprecated, вместо них теперь ExternalMetric и ExternalMetricProvider с 4-й версии NetXMS.

С ExternalParameter я столкнулся с тем, что скрипт может работать не очень быстро, особенно, если мониторится много сертификатов. Также могут быть какие-то сетевые проблемы в это время. В результате получается, что в сервер NetXMS приходит битая информация. А с ExternalMetricProvider скрипт возвращает ряд метрик и их значений, они кэшируется агентом, а агент возвращает их серверу по запросу (раз в 600 секунд в моем случае, интервал задаётся через двоеточие).

Таким образом, ExternalMetric есть смысл использовать при быстрых скриптах, а ExternalMetricProvider — при долгих.

Ещё один тонкий момент, пишите эти параметры в основной секции. Я один раз написал их в секции [FILEMGR] и очень долго не мог понять, почему у меня не создаются инстансы, была ошибка:

Failed to get instance list

при выполнении при Poll > Instance Discovery.

Т.е. выглядеть конфиг должен примерно так:

2.2 Теперь сам скрипт. В отличие от прошлой статьи, скрипт у меня используется один, но может выполнять обе задачи (в зависимости от того, подавать ему на вход параметр «List» или нет), и формировать список строк с именами и датами сертификатов и получать количество дней для каждого.

#Список внешних хостов для мониторинга
param(
    [Parameter(Mandatory = $false)]
    [Switch]$List,
    [Parameter(Mandatory = $false)]
    [String[]]$Hosts = @(
        'netxms.com',
        'netxms.org',
		'ya.ru',
		'google.com')
)

#Задаем префикс, который будет являться названием метрики и отражатся в начале Description cчетчика
$prefix = 'CertificateExpireDateExternal'

#Функция получения сертификата внешнего хоста
function Get-RemoteSslCertificate {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string]
        $ComputerName,
        [int]
        $Port = 443
    )

    $Certificate = $null
    $TcpClient = New-Object -TypeName System.Net.Sockets.TcpClient
    try {
        $TcpClient.Connect($ComputerName, $Port)
        $TcpStream = $TcpClient.GetStream()
        $Callback = { param($sender, $cert, $chain, $errors) return $true }
        [System.Security.Authentication.SslProtocols]$protocol = [System.Security.Authentication.SslProtocols]::Tls12
        $SslStream = New-Object -TypeName System.Net.Security.SslStream -ArgumentList @($TcpStream, $true, $Callback) -ErrorAction Stop
        try {
            $SslStream.AuthenticateAsClient($computername,$null,$protocol,$false)
            $Certificate = $SslStream.RemoteCertificate
        }
        finally {
            $SslStream.Dispose()
        }
    }
    finally {
        $TcpClient.Dispose()
    }

    if ($Certificate) {
        if ($Certificate -isnot [System.Security.Cryptography.X509Certificates.X509Certificate2]) {
            $Certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $Certificate -ErrorAction Stop
        }
    }
    return $Certificate
}

foreach($h in $Hosts) {
    $destAddress = $h
    $destPort = 443
    if ($destAddress.Contains(':')) {
        $destPort = [UInt32]::Parse($destAddress.SubString($destAddress.IndexOf(':') + 1))
        $destAddress = $destAddress.SubString(0, $destAddress.IndexOf(':'))
    }
    try {
        $cert = Get-RemoteSslCertificate -ComputerName $destAddress -Port $destPort -ErrorAction Stop
    }
    catch {
        if (-not $list.IsPresent) {
            Write-Output ([String]::Format("{0}({1} - {2})={3}", 
                $prefix,
                $destAddress,
                'connection failed',
                '1'))
        }
        else {
            write-output ([String]::Format("{0} - {1}", $destAddress, 'connection failed')) 
        }
        continue
    }
    if (-not $List.IsPresent) {
        $reportLine = [String]::Format("{0}({1} - {2})={3}", 
            $prefix,
            $destAddress,
            $cert.NotAfter.ToString('dd.MM.yyyy'),
            [Math]::Max(0, [Math]::Floor(($cert.NotAfter - [DateTime]::Now).TotalDays)).ToString()
            )
    }
    else {
        $reportLine = [String]::Format("{0} - {1}",
            $destAddress,
            $cert.NotAfter.ToString('dd.MM.yyyy'))
    }
    Write-Output $reportLine
}

В первой секции, «Список внешних хостов для мониторинга» мы задаём список хостов, сертификаты которых требуется мониторить. У меня для примера взяты четыре сайта:

netxms.com
netxms.org
ya.ru
google.com

Вы вместо них вводите свои значения. Обратите внимание, что в скрипте, после каждого нужна запятая, кроме последнего имени, самого нижнего. Скрипт можете разместить где угодно, хоть локально на выбранной ноде, хоть на файловой шаре. Я обычно кладу их в папку SYSVOL домена, так они везде доступны и близко к нодам. При расположении в SYSVOL и прочих сететевых шарах, учтите Execution Policy для Powershell и прочие моменты для удачного запуска скриптов. Не забудьте только в конфиге ноды прописать полный путь к скрипту.

2.3 Далее создаём счётчик, в котором в поле Metric вводим:

CertificateExpireDateExternal({instance})

А в поле Display name:

CertificateExpireDateExternal: {instance}

Обратите внимание, что название метрики (CertificateExpireDateExternal в данном случае) должно строго совпадать со значением переменной $prefix скрипта. В итоге счётчик будет выглядеть примерно так:

Кстати, если вы нажмете кнопку справа от поля Metric и попытаетесь там найти CertificateExpireDateExternal, то потерпите неудачу. Поэтому придётся вводить вручную.

2.4 Дальше, идём на вкладку Instance Discovery, там в поле Instance discovery method выбираем Agent List, а в поле List name пишем CertExpDaysLeftList. Это имя должно строго совпадать с именем параметра ExternalList в конфиге агента:

Нажимаем кнопку «Apply and Close» и в принципе счётчик готов.

2.5 Теперь нам нужно, чтобы создались инстансы для каждого сертификата, для чего для ноды выполняем Poll > Instance Discovery (вообще, по умолчанию это само происходит раз в 600 секунд, можно и подождать, но неохота). Это должно отработать как-то так:

Довольно часто здесь можно получить ошибку «Failed to get instance list», про которую я писал выше. К сожалению, причин её возникновения может быть довольно много и я не смогу их все здесь описать. Надо проверять работу скрипта на ноде просто из Powershell, по тому пути, который у вас в конфиге ноды, смотреть Execution Policy и т.п.

В Data Collection Configuration ноды должны создаться инстансы наших счетчиков, в количестве 4-х штук:

А в Last Values ноды, соответсвенно, должны появиться наши четыре счетчика:

Обратите внимание, что у нас в имени счетчика видно название сертификата и дата его срока действия, а в значении, соответственно, количество дней, оставшихся до этой даты. Получается три в одном 🙂 Естественно, в этом случае легко будет настроить порог срабатывания оповещения.

Т.е. всё, что нам надо, это заносить имена хостов в powershell-скрипт, дальше уже всё будет делаться автоматически.

Оставьте комментарий