# SSL certificates Zabix

<https://habr.com/ru/companies/first/articles/684136/>

![](/files/kkXGZbS40SwYoFIIDsYP)

*«Ничто не вечно под луной» Уильям Шекспир*

Если вы отвечаете за работоспособность сайтов, то эта статья поможет вам и вашим клиентам своевременно продлить срок регистрации доменов и вовремя обновить SSL-сертификаты.

Конечно, владельцы сайтов получат по электронной почте извещения о необходимости продления услуг, однако их легко не заметить или проигнорировать. И если просроченный сертификат можно заменить бесплатным Let’s Encrypt за несколько минут, то на восстановление работоспособности домена, у которого снято делегирование, может уйти больше суток. Все это время сайт не будет работать, что принесет вашим клиентам убытки.

Кроме того, после окончания срока регистрации и освобождения доменное имя может быть зарегистрировано кем угодно. В результате клиенту придется либо выкупать домен обратно, либо регистрировать и продвигать новый домен.

На сервисе SAAS интернет-магазинов нужно контролировать сотни доменов. Дополнительно задача контроля усложняется тем обстоятельством, что все время открываются новые сайты, а старые могут закрываться. Поэтому тут не обойтись без автоматизации, которую можно реализовать при помощи Zabbix.

Как и предыдущих статьях нашей серии про Zabbix, мы сначала рассмотрим ручные методы контроля, а затем перейдем к описанию шаблона и скриптов контроля для Zabbix.

## Ручной контроль срока действия сертификата SSL

Срок действия сертификата можно проверить в браузере, а также в командной строке ОС. Рассмотрим оба способа.

### Проверка срока действия сертификата SSL в браузере

Любой пользователь может узнать срок действия сертификата сайта, открытого в браузере. Для этого в Chrome, например, ему достаточно щелкнуть мышкой символ замка в адресной строке браузера, расположенный слева от URL сайта, выбрать строку **Безопасное подключение** и щелкнуть строку **Действительный сертификат**. После этого на экране появится окно с информацией о сертификате, подключенном к сайту (рис. 1).

![](/files/mY0Z8n2PWUcEhpDw4B6u)

Рис. 1. Информация о сертификате, подключенном к сайту

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

Аналогичный способ посмотреть срок действия сертификата есть и в других браузерах. В Firefox, например, нужно щелкнуть символ замка слева от URL сайта, выбрать строку **Защищенное соединение**, а затем выбрать строку **Подробнее**. Далее нужно щелкнуть кнопку **Посмотреть сертификат**. В блоке **Срок действия** вы найдете информацию о диапазоне дат, в пределах которого сертификат будет действительным.

Аналогичные способы проверки сертификатов есть и в браузерах смартфонов.

### Проверка срока действия сертификата SSL в командной строке

В интернете нетрудно найти способ проверки сроков действия сертификата, установленного на сайте, из командной строки с помощью программы openssl.

Например, следующая команда покажет в консоли диапазоны дат, в пределах которых будет действителен сертификат сайта [firstvds.ru](http://firstvds.ru/), использующего протокол https на порту 443:

```
$ echo | openssl s_client -servername firstvds.ru -connect firstvds.ru:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null
notBefore=Jun 29 00:00:00 2020 GMT
notAfter=Aug 28 12:00:00 2022 GMT
```

Сертификат действителен с даты **notBefore** и до даты **notAfter**.

Если вас интересует только дата, до которой будет работать сертификат, используйте такую команду:

```
$ echo | openssl s_client -servername firstvds.ru -connect firstvds.ru:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null | grep notAfter | cut -d'=' -f2
Aug 28 12:00:00 2022 GMT
```

Чтобы организовать несложную проверку сертификатов из командной строки, используйте скрипт get\_ssl\_info.sh, [доступный на Github](https://github.com/AlexandreFrolov/shop2you_zabbix_monitoring/blob/main/get_ssl_info.sh):

```
#!/bin/sh
SERVER=$1
PORT=$2;
EXPIRE_DATE=`echo | openssl s_client -servername $SERVER -connect $SERVER:$PORT 2>/dev/null | openssl x509 -noout -dates 2>/dev/null | grep notAfter | cut -d'=' -f2`
echo $EXPIRE_DATE
```

При запуске передайте ему доменное имя сайта и номер порта:

```
$ bash get_ssl_info.sh firstvds.ru 443
Aug 28 12:00:00 2022 GMT
```

## Ручной контроль срока окончания регистрации доменного имени

Узнать, до какой даты оплачена регистрация доменного имени, и когда доменное имя будет освобождено, можно с помощью команды whois. Просто передайте этой команде проверяемое доменное имя:

```
$ whois firstvds.ru
% By submitting a query to TCI's Whois Service
% you agree to abide by the following terms of use:
% https://www.tcinet.ru/documents/whois.pdf (in Russian)

domain:        FIRSTVDS.RU
nserver:       ns-1179.awsdns-19.org.
nserver:       ns-1806.awsdns-33.co.uk.
nserver:       ns-413.awsdns-51.com.
nserver:       ns-547.awsdns-04.net.
state:         REGISTERED, DELEGATED, VERIFIED
org:           CJSC "The First"
registrar:     REGTIME-RU
admin-contact: https://whois.webnames.ru
created:       2002-08-06T20:00:00Z
paid-till:     2023-08-07T21:00:00Z
free-date:     2023-09-08
source:        TCI
Last updated on 2022-07-29T07:46:32Z
```

Параметр **paid-till** содержит дату и время окончания регистрации доменного имени, а параметр **free-date** — дату его освобождения.

## Мониторинг с помощью Zabbix

Используя приведенные выше команды и программу zabbix\_sender, описанную в предыдущей статье серии, можно организовать мониторинг сроков окончания действия сертификатов и регистрации доменных имен. В случае SAAS-сервиса интернет-магазинов ситуация осложняется тем, что доменов, подлежащих мониторингу сотни, постоянно добавляются новые и иногда исчезают старые.

Для получения списка доменных имен активных интернет-магазинов мы используем вызов внутренней CRM сервиса SAAS. Далее, на основе этого списка с помощью программного интерфейса Zabbix API создается или редактируется список элементов данных Items, содержащих информацию для мониторинга, а также список соответствующих триггеров.

Мы не можем опубликовать API проприетарной системы CRM сервиса SAAS, но вам в любом случае при постановке аналогичной задачи придется выполнять собственную интеграцию со своей CRM. Мы подскажем, где это нужно сделать в опубликованном скрипте мониторинга.

Что же касается описания Zabbix API, то для версии 6.2 [вы найдете ее здесь](https://www.zabbix.com/documentation/6.2/en/manual/api). На русском языке описание API доступно для версии 6.0 [вот тут](https://www.zabbix.com/documentation/6.0/ru/manual/api).

## Программа domain\_monitor.pl

Программа domain\_monitor.pl выполняет все описанные выше функции по динамическому формированию списка элементов данных и триггеров в соответствии со списком работающих интернет-магазинов. Далее она получает информацию обо всех контролируемых доменах и сертификатах, а потом отправляет ее на сервер Zabbix.

Эту программу [можно скачать здесь](https://github.com/AlexandreFrolov/shop2you_zabbix_monitoring/blob/main/domain_monitor_free_version.pl).

### Загрузка файла конфигурации

Сразу после запуска программа загружает файл конфигурации, содержащий реквизиты доступа к Zabbix API:

```
use File::Slurp;
…
my $zbx = LoadFile('/home/frolov/zabbix_domain_monitoring/config/zabbix-server.yaml');
my $zabbix_server_ip = $zbx->{ zabbix_server_ip };
Здесь функции LoadFile нужно передать полный путь к файлу конфигурации в формате YAML следующего вида:
zabbix_server_url: http://zabbix.domain.ru/api_jsonrpc.php
zabbix_server_login: Admin
zabbix_server_password: *********
zabbix_server_ip: ***.***.***.***
```

В параметре zabbix\_server\_url укажите URL для доступа к вашему серверу Zabbix для отправки HTTP POST запросов к файлу api\_jsonrpc.php.

Через параметры zabbix\_server\_login и zabbix\_server\_password следует передать логин и пароль доступа к API. Вы можете использовать здесь реквизиты доступа администратора Zabbix или другого пользователя, обладающего необходимыми правами.

И, наконец, параметр zabbix\_server\_ip задает адрес IP вашего сервера Zabbix.

### Подключение к Zabbix API

Загрузив файл конфигурации, программа domain\_monitor.pl открывает соединение с сервером Zabbix через API с помощью функции zabbix\_open:

```
my $z = zabbix_open($zbx);
```

Функции для обращения к Zabbix API будут отписаны ниже в разделе «Функции для работы с API Zabbix» этой статьи.

### Получение информации о доменах работающих интернет-магазинов

На следующем шаге программа domain\_monitor.pl получает из встроенной CRM ссылку на хэш, содержащий информацию обо всех доменах интернет-магазинов, работающих на момент запуска программы на SAAS-сервисе (открытых сайтов):

```
$all_sites = get_opened_domains_from_billing();
```

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

### Получение информации о контролируемых доменах от Zabbix

Получив хэш доменов работающих интернет-магазинов, программа формирует хэш всех доменов, которые на момент запуска уже контролируются при помощи Zabbix. Для этого вызывается функция get\_all\_monitored\_domains:

```
my $domains_group_name = 'Shop2YOU Domains';
my $all_monitored_domains = get_all_monitored_domains($z, $domains_group_name);
```

Для работы с доменными именами сервиса на сервере Zabbix была создана группа «Shop2YOU Domains». Вам нужно будет создать группу, например, с названием вашего сервиса или компании.

Соединение с Zabbix API передается функции get\_all\_monitored\_domains в качестве первого параметра, а имя группы —в качестве второго параметра.

Таким образом, в переменной all\_sites хранится ссылка на хэш со всеми доменами, которые работают, а в переменной all\_monitored\_domains — с доменами, которые находятся на мониторинге. Эти данные загружены на момент запуска программы domain\_monitor.pl.

### Актуализация контролируемых доменов

Теперь нужно актуализировать в Zabbix список доменов, добавив туда отсутствующие с момента предыдущей проверки элементы Items и триггеры, а также удалив ненужные элементы для интернет-магазинов, которые прекратили свою работу.

Первая из этих задач решается функцией create\_missing\_domain\_in\_zabbix, а вторая — функцией delete\_closed\_domains\_from\_zabbix.

Функции create\_missing\_domain\_in\_zabbix нужно передать ссылку на Zabbix API, имя группы, имя шаблона, который применяется для мониторинга доменов, ссылку на хэш с работающими доменами all\_sites, а также ссылку на контролируемые домены all\_monitored\_domains:

```
my $domains_template_name = 'Shop2YOU Domains Monitor';

create_missing_domain_in_zabbix($z, $domains_group_name, $domains_template_name, $all_sites, $all_monitored_domains);
```

Функции delete\_closed\_domains\_from\_zabbix передаются те же самые параметры:

```
delete_closed_domains_from_zabbix($z, $domains_group_name, $domains_template_name, $all_sites, $all_monitored_domains);
```

### Отправка текущей информации о доменах на сервер zabbix

Теперь, когда список контролируемых при помощи Zabbix доменов приведен в соответствие списку работающих сайтов из CRM сервиса SAAS, можно отправлять данные с текущей информацией о доменах на сервер Zabbix.

Эта операция выполняется в цикле по хэшу со всеми работающими доменами all\_sites:

```
foreach my $key (keys %$all_sites)
{
  my $zkey;
  my $zvalue;
  my $trap_cmd;
  if($key)
  {
    my $host_name = $all_sites->{$key}->{domain_name};

    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'days_before_domain_expire', $all_sites->{$key}->{ 'days_before_domain_expire' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'days_before_ssl_expire', $all_sites->{$key}->{ 'days_before_ssl_expire' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'domain_ssl_matches', $all_sites->{$key}->{ 'domain_ssl_matches' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'domain_has_ssl', $all_sites->{$key}->{ 'domain_has_ssl' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'whois_ok', $all_sites->{$key}->{ 'whois_ok' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'a_found', $all_sites->{$key}->{ 'a_found' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'dns_a', $all_sites->{$key}->{ 'a' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'mx_found', $all_sites->{$key}->{ 'mx_found' });
    send_value_to_zabbix($zabbix_sender, $zabbix_server_ip, $host_name, 'dns_mx', $all_sites->{$key}->{ 'mx' });
  }
}

```

Отправка данных выполняется при помощи функции send\_value\_to\_zabbix. Как и в предыдущей статье нашей серии, для отправки запускается программа zabbix\_sender. Однако здесь каждый параметр отправляется отдельно:

```
sub send_value_to_zabbix($$$$$)
{
  my $zabbix_sender=shift @;
  my $zabbix_server_ip=shift @;
  my $host_name=shift @;
  my $zkey=shift @;
  my $zvalue=shift @;

  my $trap_cmd = $zabbix_sender.' -z '.$zabbix_server_ip.' -s '.$host_name.' -k '.$zkey.' -o "'.$zvalue.'"';
  my @trapout = (); @trapout = split /\n/, `$trap_cmd`;
}
```

Через параметр -z программе zabbix\_sender передается адрес IP сервера Zabbix, через параметр -s передается имя хоста, которое в нашем случае соответствует проверяемому домену. Параметры -k и -o используются, соответственно, для передачи имени ключа и значения.

Изучив приведенный выше цикл по хэшу, вы узнаете, какая информация о доменах попадает на сервер:

* days\_before\_domain\_expire — количество дней до завершения регистрации домена;
* days\_before\_ssl\_expire — количество дней до завершения периода действия сертификата;
* domain\_ssl\_matches — сертификат на сайте соответствует доменному имени сайта;
* domain\_has\_ssl — к сайту подключен сертификат SSL;
* whois\_ok — команда whois вернула правильную информацию о домене;
* a\_found — в DNS домена обнаружена запись A;
* a — содержимое записи A для домена;
* mx\_found — в DNS домена обнаружена запись MX;
* mx — содержимое записи MX для домена

## Функция get\_domain\_info

Для организации собственной системы мониторинга доменов вам пригодится функция get\_domain\_info, которая вызывается функцией get\_opened\_domains\_from\_billing при получении хэша с данными о доменах открытых интернет-магазинов.

Функции get\_domain\_info нужно передать в качестве первого параметра доменное имя, а в качестве второго — порт, на котором работает проверяемый сайт (обычно 443). Функция записывает полученные данные в хэш domain\_info и возвращает этот хэш вызывающей функции (в нашем случае это get\_opened\_domains\_from\_billing).

Полный код функции [вы найдете на Github](https://github.com/AlexandreFrolov/shop2you_zabbix_monitoring/blob/main/domain_monitor_free_version.pl).

Прежде всего, функция get\_domain\_info записывает в хэш доменное имя, для которого она будет определять текущие параметры:

```
$domain_info->{ domain_name } = $domain_name;
```

### Получение данных о сертификате SSL

На следующем шаге функция определяет, подключен ли к сайту с этим доменным именем сертификат SSL. Для этого анализируются результаты выполнения следующей команды:

```
my $cmd = 'openssl s_client -servername '.$domain_name.' -connect '.$domain_name.':'.$ssl_port.' </dev/null 2>/dev/null';
my @rqout = ();
@rqout = split /\n/, `$cmd`;
if(scalar(@rqout) == 0)
{
  $domain_info->{ domain_has_ssl }=0;
}
else
{
  $domain_info->{ domain_has_ssl }=1;
  …
}
```

Если на сервере нет сертификата для домена, в хэше по ключу domain\_has\_ssl записывается нулевое значение, в противном случае — значение единицы. Однако само по себе наличие выдачи результатов использованной здесь команды еще не говорит о валидности сертификата. Может быть такая ситуация, когда на сервере размещено несколько сайтов, и для сайта, у которого нет сертификата, будет получен сертификат другого сайта с этого же сервера.

Чтобы убедиться в соответствии доменного сертификата имени, на который выписан полученный сертификат, проверяем, упоминается ли проверяемое доменное имя в результатах выдачи следующей команды:

```
my $cmd_subj='echo | openssl s_client -servername '.$domain_name.' -connect '.$domain_name.':'.$ssl_port.' 2>/dev/null | openssl x509 -noout -subject';
my @subjout = ();
@subjout = split /\n/, `$cmd_subj`;
if(scalar(@subjout) != 0)
{
  my $cn=@subjout[0];
  if($cn=~/$domain_name/)
  {
    $domain_info->{ domain_ssl_matches }=1;
  }
  else
  {
    $domain_info->{ domain_ssl_matches }=0;
  }
}
```

Если сертификат соответствует доменному имени, записываем в хэш для ключа domain\_ssl\_matches значение 1, если нет — значение 0. Несоответствие доменного имени сертификату в данном случае является поводом проверить сертификат данного сайта и настройку Web-сервера.

Для валидного сертификата функция get\_domain\_info получает количество дней до завершения его срока действия:

```
$cmd = 'echo | openssl s_client -servername '.$domain_name.' -connect '.$domain_name.':'.$ssl_port." 2>/dev/null | openssl x509 -noout -dates 2>/dev/null | grep notAfter | cut -d'=' -f2";
my @rqout2 = ();
@rqout2 = split /\n/, `$cmd`;
my $expires_data = str2time(@rqout2[0]);
my $current_data = time();
my $days_before_expire = int(($expires_data - $current_data) / 86400);
if($days_before_expire <= 0) { $days_before_expire = 0;}
  $domain_info->{ days_before_ssl_expire }=$days_before_expire;
```

Полученное значение записывается в хэш по ключу days\_before\_ssl\_expire.

### Определение даты окончания регистрации доменного имени

Для того чтобы получить данные DNS для домена, мы используем функцию parse\_whois пакета Net::Whois::Parser:

```
my $info = parse_whois( domain => $domain_name );

my $domain_expiration_date='';
$domain_info->{ whois_ok } = 1;
if($info->{ paid_till })
{
  $domain_expiration_date = $info->{ paid_till };
}
elsif ( $info->{ expiration_date })
{
  $domain_expiration_date = $info->{ expiration_date };
}
elsif ( $info->{ registry_expiry_date })
{
  $domain_expiration_date = $info->{ registry_expiry_date };
}
elsif ( $info->{ 'Registry Expiry Date' })
{
  $domain_expiration_date = $info->{ 'Registry Expiry Date' };
}
else
{
  $domain_info->{ whois_ok } = 0;
}
```

Прежде всего, функция get\_domain\_info пытается отыскать в результатах выдачи parse\_whois дату завершения регистрации доменного имени. В зависимости от сервера DNS эта дата может обозначаться в выдаче whois по-разному: «paid\_till», «expiration\_date», «registry\_expiry\_date» и «Registry Expiry Date». Не исключено, что бывают и другие варианты.

Если ни один из этих способов поиска даты завершения регистрации домена не приводит к успеху, для ключа whois\_ok записывается нулевое значение. В этом случае нужно исследовать домен вручную, и, возможно, дополнить приведенный выше фрагмент кода.

Но если дата найдена, то она преобразуется в количество дней до окончания регистрации и записывается в хэш по ключу days\_before\_domain\_expire:

```
my $expires_data = str2time($domain_expiration_date);
my $current_data = time();
my $days_before_expire = int(($expires_data - $current_data) / 86400);
$domain_info->{ days_before_domain_expire } = $days_before_expire;
if($days_before_expire < 0)
{
  $domain_info->{ whois_ok } = 0;
}
```

### Получение записей A и MX из DNS

Следующий фрагмент функции get\_domain\_info используется для определения наличия в DNS записей A и MX для исследуемого домена с помощью функции get\_domain\_info\_from\_dns:

```
my $dns_info=get_domain_info_from_dns($domain_name);
if($dns_info->{ a_found })
{
  my $a_str="";
  my $a_counter=0;
  my $dns_a_ref = $dns_info->{ address };
  foreach my $dns_a (@$dns_a_ref)
  {
    if($a_counter > 0)
    {
      $a_str = $a_str.', '.$dns_a;
    }
    else
    {
      $a_str = $a_str.$dns_a;
    }
    $a_counter++;
  }
  $domain_info->{ a_found } = 1;
  $domain_info->{ a } = $a_str;
}
else
{
  $domain_info->{ a_found } = 0;
}
if($dns_info->{ mx_found })
{
  my $mx_str="";
  my $mx_counter=0;
  my $mx_ref = $dns_info->{ mx };
  foreach my $record (@$mx_ref)
  {
    my $pr = $record->preference;
    my $ex = $record->exchange;
    if($mx_counter > 0)
    {
      $mx_str = $mx_str.', '.$pr.' '.$ex;
    }
    else
    {
      $mx_str = $mx_str.$pr.' '.$ex;
    }
    $mx_counter++;
  }
  $domain_info->{ mx_found } = 1;
  $domain_info->{ mx } = $mx_str;
}
else
{
  $domain_info->{ mx_found } = 0;
}
```

Действия, выполняемые этим фрагментом кода, понятны и без дополнительных объяснений. Что же касается функции get\_domain\_info\_from\_dns, то она получает данные домена из DSN с помощью модуля Net::DNS::Resolver:

```
sub get_domain_info_from_dns($)
{
  my $domain = shift @_;
  my $res   = Net::DNS::Resolver->new;
  my $dinfo = {};
  my @mx = mx($res, $domain);
  if(@mx != 0)
  {
    $dinfo->{ mx_found } = 1;
    $dinfo->{ mx } = \@mx;
  }
  else
  {
    $dinfo->{ mx_found } = 0;
    $dinfo->{ mx_error } = $res->errorstring;
  }
  my $addr=();
  my $rr = {};
  my $query = {};
  $dinfo->{ a_found } = 0;
  $query = $res->search($domain);
  if ($query)
  {
    foreach $rr ($query->answer)
    {
       next unless ($rr->type eq "A");
       push @$addr, $rr->address;
       $dinfo->{ a_found } = 1;
    }
  }
  $dinfo->{ address } = $addr;
  return($dinfo);
}
```

## Функции для работы с Zabbix API

Для работы с Zabbix API наша программа использует модуль Zabbix::Tiny: <https://metacpan.org/pod/Zabbix::Tiny> или <https://github.com/whosgonna/Zabbix-Tiny.pm>.

По адресу <https://www.zabbix.com/ru/integrations?cat=api> есть решения для интеграции на разных языках программирования.

### zabbix\_open

Функция zabbix\_open вызывает конструктор модуля Zabbix::Tiny:

```
sub zabbix_open($)
{
  my $z = shift @_;
  my $zabbix = Zabbix::Tiny->new(
     server   => $z->{ zabbix_server_url },
     password => $z->{ zabbix_server_password },
     user     => $z->{ zabbix_server_login },
     ip     => $z->{ zabbix_server_ip },
 );
  return $zabbix;
}
```

### get\_group\_id

Функция get\_group\_id получает от Zabbix API идентификатор группы по ее имени:

```
sub get_group_id($$)
{
  my $z = shift @_;
  my $group_name = shift @_;
  my $params = {
    output => [qw(groupid name)],
    filter => { name => [$group_name]  }
  };
  my $result = $z->do(
   'hostgroup.get',
   $params
  );
  return $result->[0]->{ groupid };
}
```

### get\_group\_hosts

Функция get\_group\_hosts возвращает хосты для группы с заданным именем и вызывается функцией get\_all\_monitored\_domains:

```
sub get_group_hosts($$)
{
  my $z = shift @_;
  my $group_name = shift @_;

  my $gid = get_group_id($z, $group_name);
  my $params = {
    output => [qw(hostid name host)],
    groupids => [$gid],
  };
  my $result = $z->do(
   'host.get',
   $params
  );
  return $result;
}
```

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

### get\_template\_id

Чтобы по имени шаблона получить его идентификатор, используется функция get\_template\_id:

```
sub get_template_id($$)
{
  my $z = shift @_;
  my $template_name = shift @_;
  my $params = {
    output => [qw(templateid name)],
    filter => { name => [$template_name]  }
  };
  my $result = $z->do(
   'template.get',
   $params
  );
  return $result->[0]->{ templateid };
}
```

### create\_host

Для мониторинга каждого доменного имени программа domain\_monitor.pl создает отдельный хост, вызывая для этого функцию create\_host:

```
sub create_host($$$$$)
{
  my $z = shift @_;
  my $host_name = shift @_;
  my $name = shift @_;
  my $group_name = shift @_;
  my $template_name = shift @_;

  my $gid = get_group_id($z, $group_name);
  my $template_id = get_template_id($z, $template_name);

  my $params = {
    host => $host_name,
    name => $name,
    interfaces => [{type => 1, main => 1, useip => 1, ip => '127.0.0.1', dns => "", port => '443'}],
    groups => [{ groupid => $gid }],
    templates => [{ templateid => $template_id }],
  };
  my $result = $z->do(
   'host.create',
   $params
  );
  return $result;
}
```

В качестве параметров этой функции передаются соединение с сервером Zabbix, имя хоста (то есть имя контролируемого домена), имя группы и шаблона.

### get\_host\_id

Функция get\_host\_id возвращает идентификатор хоста, заданного своим именем:

```
sub get_host_id($$)
{
  my $z = shift @_;
  my $host_name = shift @_;
  my $params = {
    output => [qw(hostid name)],
    filter => { name => [$host_name]  }
  };
  my $result = $z->do(
   'host.get',
   $params
  );
  return $result->[0]->{ hostid };
}
```

### delete\_host

Если интернет-магазин закрылся, то его сайт нужно удалить из мониторинга. Функция delete\_host удаляет хост по его идентификатору:

```
sub delete_host($$)
{
  my $z = shift @_;
  my $hostid = shift @_;
  my $params = [ $hostid ];
  my $result = $z->do(
   'host.delete',
   $params
  );
  return $result;
}
```

### get\_all\_monitored\_domains

Чтобы получить все домены, которые находятся на мониторинге, программа domain\_monitor.pl вызывает функцию get\_all\_monitored\_domains. Она возвращает все хосты для группы с заданным именем:

```
sub get_all_monitored_domains($$)
{
  my $z = shift @_;
  my $group_name = shift @_;
  return get_group_hosts($z, $group_name);
}
```

### create\_missing\_domain\_in\_zabbix

Функция create\_missing\_domain\_in\_zabbix добавляет хосты в мониторинг, пользуясь для этого ссылкой на хэш hosts и функцией create\_host:

```
sub create_missing_domain_in_zabbix($$$$$)
{
  my $z=shift @_;
  my $domains_group_name=shift @_;
  my $domains_template_name=shift @_;
  my $domains_from_billing=shift @_; # from Billing
  my $domains_from_zabbix=shift @_; # from Zabbix
  foreach my $key (keys %$domains_from_billing)
  {
    my $host_name;
    my $name;
    if($key)
    {
      $host_name = $domains_from_billing->{$key}->{domain_name};
      my $pcode_used = $domains_from_billing->{$key}->{punycode_used};
      if($pcode_used)
      {
        $name = $domains_from_billing->{$key}->{domain_name_from_billing};
      }
      else
      {
        $name = $domains_from_billing->{$key}->{domain_name};
      }
      my ($found, $zbx_hostid) = find_in_monitored_domains($host_name, $domains_from_zabbix);
      if($found == 0)
      {
        print("$name to be CREATED \n");
        Encode::_utf8_on($name);
        my $hsts = create_host($z, $host_name, $name, $domains_group_name, $domains_template_name);
      }
    }
  }
}
```

При этом учитывается, что имена доменов могут быть в кодировке Punyсode.

### delete\_closed\_domains\_from\_zabbix

И, наконец, функция delete\_closed\_domains\_from\_zabbix удаляет из мониторинга хосты, которые соответствуют сайтам прекративших свою работу интернет-магазинов:

```
sub delete_closed_domains_from_zabbix($$$$$)
{
  my $z=shift @_;
  my $domains_group_name=shift @_;
  my $domains_template_name=shift @_;
  my $domains_from_billing=shift @_; # from Billing
  my $domains_from_zabbix=shift @_; # from Zabbix
  foreach my $arg (@$domains_from_zabbix)
  {
    my $cdomain = $arg->{host};
    my $zbx_hostid = $arg->{hostid};
    my $found_in_billing=find_domain_in_billing($cdomain, $domains_from_billing);
    if($found_in_billing == 0)
    {
      print("$cdomain NOT found in Billing, to be REMOVED. zbx_hostid = $zbx_hostid \n");
      my $rc = delete_host($z, $zbx_hostid);
    }
  }
}
```

Вам нужно будет самостоятельно реализовать функцию find\_domain\_in\_billing для поиска таких сайтов в вашей CRM.

## Шаблон мониторинга доменов

Шаблон мониторинга доменных имен и сертификатов вы можете загрузить [из Github](https://github.com/AlexandreFrolov/shop2you_zabbix_monitoring/blob/main/shop2you_domains_monitoring_template.xml).

В этом шаблоне определены ключи, о которых мы говорили в нашей статье (рис. 2).

![](/files/0nB59O89M1iaalYgBLvb)

Рис. 2. Ключи в шаблоне мониторинга доменных имен и сертификатов

Триггеры показаны на рис. 3.

![](/files/8WYMTxhKeRJqEIEblD31)

Рис. 3. Триггеры для мониторинга данных доменов и сертификатов

Здесь мы назначили среднюю серьезность только для триггеров **Domain registration expires in 30 days** (регистрация домена закончится через 30 дней) и **SSL expired in 7 days** (срок действия сертификата истекает через 7 дней). Остальные триггеры только для информации.

Вы, конечно, можете настроить эти триггеры по своему усмотрению.

## Запуск задания crontab

Для запуска программы проверки сроков регистрации доменных имен и срока действия сертификатов SSL подготовьте задание crontab, например, такое:

```
34 3 * * *      /usr/bin/perl /home/frolov/zabbix_domain_monitoring/domain_monitor.pl
```

Здесь проверка запускается каждый день ночью, в 3 часа 34 минуты.

*Автор: Александр Фролов.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.konstantinsecurity.com/readme/architect/monitoring/zabbix/ssl-certificates-zabix.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
