Autodiscovery de Serviços no Linux com Zabbix

Com o zabbix é possível monitorar serviços que estão sendo executados em servidores linux através de uma chave especial net.tcp.service[nomedoservice] onde em nome do serviço o zabbix aceita alguns serviços padrões como ftp, http, ssh, ntp etc. 

O problema em monitorar utilizando este método é que ele não suporta todos os tipos de serviço, como por exemplo não é possível passar como parâmetro para essa chave serviços como mongodb, redis etc. Outro ponto negativo é que você não sabe qual serviço exatamente está sendo utilizado como por exemplo o serviço http está rodando Apache ou Nginx ? e se ou roda-los em uma porta não padrão ou seja não na porta 80?

Por esses motivos prefiro utilizar a capacidade do zabbix de autodiscovery para descobrir exatamente qual serviço está sendo executado e em qual porta.

Um modo de se obter as informações referente ao serviço e em que porta o mesmo está em execução é utilizar o comando netstat, formatar a saída do comando e mandar para o zabbix.
 Eu pessoalmente já utilizei esse método através de um script em python que executava o netstat e formatava seu output, porém eu particularmente não o utilizo mais por alguns motivos que são:

- Para obter as informações de processo é necessário ter acesso root logo é necessário executar o netstat com sudo.

- Independente da linguagem de script que se use, sempre teremos a dependência do pacote net-tools para poder rodar o netstat.

Por esses motivos eu prefiro criar um binário que infelizmente ainda será necessário ser executado com sudo, porém não terá nenhuma dependência para funcionar e em teoria é mais seguro pois sua função é restrita a apenas obter as informações necessárias sem mais nem menos.

 O binário é originado de código em golang, que basicamente utiliza uma implementação do netstat que eu criei para poder obter informações de processos e facilitar a formatação desses dados.

Segue o código para obter os processos tcp e formatar de acordo com os macros do zabbix.


 

package main

import(
    "fmt"
    "encoding/json"
    "log"
    "github.com/drael/GOnetstat"
)

type Process struct {
    Name    string   `json:"{#PROCNAME}"`
    Port    int64     `json:"{#PORT}"`
}

type ZabbixData struct {
    Data []Process  `json:"data"`
}

func main() {
    data := GOnetstat.Tcp()
    var zd = new(ZabbixData)
    
    for _, p := range(data) {
        if p.State == "LISTEN" {
            zd.Data = append(zd.Data, Process{p.Name, p.Port})
        }
    }
    
    output, err := json.MarshalIndent(zd, "", "    ")
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println(string(output))
}


O código é simples e direto, irá obter os processos tcp com o status de LISTEN e irá formatar para json o nome e porta do processo em um array data, logo a permissão de sudo que daremos para o binário gerado desse código será limitado a apenas isso obter o nome e porta de processos tcp com status listen.

Basta criar o binário com um simples go build, porém se desejar baixe aqui o binário em 32 bits ou 64 que está dentro da pasta bin, nesse link você também vai obter os arquivos necessários para configurar o autodiscovery no zabbix, como os templates, e arquivos de configuração.

Configurando o Autodiscovery de Serviços.

Primeiramente copie o arquivo binário para o servidor que será monitorado os serviços, lembrando que o servidor precisa ter o zabbix-agent instalado!
No tar.gz que você baixou dentro da pasta bin terá duas pastas para cada arquitetura, 32 bits e 64 bits escolha a arquitetura correta do seu servidor e copie o arquivo binário dos tipos de serviço que deseja monitorar, tcp_services ou udp_services.

Eu prefiro colocar os binários em /etc/zabbix/bin porém você pode colocar no diretório que preferir, porém será necessário alterar o arquivo de configuração corretamente em /etc/zabbix/zabbix_agentd.d.

No dentro da pasta zabbix_agentd.d está o arquivo de configuração do zabbix-agent para que o servidor do zabbix consiga executar o binário e obter suas informações, copie os arquivos desta pasta para /etc/zabbix/zabbix_agentd.d.

Se preferir crie os arquivos na mão com o seguinte conteúdo.

/etc/zabbix/zabbix_agentd.d/tcp_services.conf:

UserParameter=tcp_services, sudo /etc/zabbix/bin/tcp_services



/etc/zabbix/zabbix_agentd.d/udp_services.conf:

UserParameter=udp_services, sudo /etc/zabbix/bin/udp_services

Reinicie o agent para carregar as novas configurações


# service zabbix-agent restart

Agora precisamos dar permissão de execução com sudo dos arquivos binários para o usuário zabbix.
Para isso copie o arquivo zabbix da pasta sudoers.d para a pasta /etc/sudoers.d do servidor que deseja monitorar.

Ou crie o arquivo manualmente

/etc/sudoers.d/zabbix

 
Defaults:zabbix !requiretty
zabbix ALL=NOPASSWD: /etc/zabbix/bin/tcp_services, /etc/zabbix/bin/udp_services

Perceba que permitimos que apenas os binários sejam executados usando sudo com o usuário do zabbix, permitimos também que o usuário do zabbix possa executar sudo sem um terminal (tty), o que é necessário pois o usuário do zabbix é criado sem permissão para isso, e quando servidor do zabbix executar o binário através do script ele não carrega um tty.

Agora basta importar os templates que foram baixados junto com os binários para o zabbix.
Não baixou o tar.gz antes ? sem problema aqui o link .
Importe os arquivos template_tcp_services.xml e template_udp_services.xml

Vá em Configuration/Templates e clique em import para carregar o arquivo xml dos templates, conforme imagem abaixo.


Após importar os templates, basta "linka-los" ao host que deseja realizar o autodiscovery, você vai localizar no grupo de templates os templates que foram importados como:

Template Linux TCP Services
Template Linux UDP Services

Uma vez que o template for linkado ao host, o autodiscovery será executado de uma em uma hora para verificar se novos serviços estão em execução no servidor ou se algum serviço não está mais sendo executado.

Veja abaixo que os serviços foram descobertos e já estão sendo monitorados




O zabbix irá monitorar entre um período de 90 segundos se o serviço está sendo executado na porta que foi identificada através do autodiscovery e caso o serviço pare de executar irá alarmar conforme a imagem abaixo


O auto discovery é executado de uma em uma hora, você pode alterar esse tempo nas configurações do template pela interface web do zabbix, você também pode filtrar os serviços que deseja que sejam descoberto pela porta em que eles rodam, veja o exemplo na imagem abaixo


Em update interval você define o tempo de execução do autodiscovery em segundos, e em Regexp você filtra os serviços que serão descobertos pela porta.


Problemas ao executar os binários.

É possível que mesmo com toda a configuração correta e com as devidas permissões de sudo o autodiscovery não funcionar e o motivo provavelmente será o SELinux no CentOS/Redhat.

Se você estiver tentando monitorar nesse ambiente, verifique os logs em /var/log/audit/audit.log 

Verifique nesse arquivo por alguma ocorrência do zabbix, algo parecido com isso:


 
type=CRED_DISP msg=audit(1404896208.502:4427): user pid=3870 uid=0 auid=0 ses=9 subj=unconfined_u:system_r:zabbix_agent_t:s0 msg='op=PAM:setcred acct="root" exe="/usr/bin/sudo" hostname=? addr=? terminal=? res=success'

No audit acima é possível ver que o selinux não está permitindo o uso do sudo pelo zabbix.
Nesse caso tente criar uma regra que irá autorizar o zabbix a executar essa ação.

Instale o pacote policycoreutils-python



yum install policycoreutils-python

Agora execute o comando abaixo para gerar a regra para o selinux

 
audit2allow -a -M zabbixrule

Instale a regra

 
semodule -i zabbixrule.pp

Agora teste para ver se o binário será executado pelo zabbix, você pode alterar o tempo em que o autodiscovery irá executar no template ou através do servidor do zabbix execute o seguinte comando

 
zabbix_get -s IP_DO_SERVIDOR_MONITORADO -k "tcp_services"

Se o comando funcionar você receberá um output em json com os serviços descobertos parecido com esse


{
    "data": [
        {
            "{#PROCNAME}": "Nginx",
            "{#PORT}": 80
        },
        {
            "{#PROCNAME}": "Sshd",
            "{#PORT}": 22
        },
        {
            "{#PROCNAME}": "Redis-Server",
            "{#PORT}": 6379
        },
        {
            "{#PROCNAME}": "Master",
            "{#PORT}": 25
        },
        {
            "{#PROCNAME}": "Zabbix_agentd",
            "{#PORT}": 10050
        },
        {
            "{#PROCNAME}": "Mongod",
            "{#PORT}": 27017
        }
    ]
}

Se não apareceu nada na tela ao executar esse comando no servidor do zabbix, só temos uma alternativa que não é desabilitar o selinux, mas sim dar permissão de acesso para a tag zabbix_agent_t .

Essa não é a melhor solução porém na data em que estou escrevendo esse post 20/07/2014, o zabbix possuí bugs com o selinux na versão 6 e 7 do CentOS.

Dê permissão ao zabbix com o seguinte comando


semanage permissive -a zabbix_agent_t

Deste modo o zabbix-agent será capaz de executar os binários através do sudo normalmente e o SELinux ainda estará ativo no seu sistema garantindo uma maior segurança para o mesmo.

Após essa permissão pode testar novamente a execução através do servidor do zabbix que irá funcionar sem problema.
Se continuar não funcionando depois de dar permissão no selinux então é bem provável que é algum erro de configuração, portanto verifique se fez a configuração exatamente como eu expliquei.

Qualquer dúvida ou sugestão deixe um comentário.

2 Comentário(s) em “Autodiscovery de Serviços no Linux com Zabbix”

  1. Olá Rafael, excelente tutorial!!!!! Segui os passos e está tudo funcionando... Só que tenho uma dúvida com relação às Macros. Mandei filtrar usando a expressão regular ^(2121|8080|3306) só que no meu servidor monitorado, que é um servidor web, o servidor ftp está em modo passivo. Então, quando os usuários logam no ftp eles acabam abrindo uma conexão tcp usando uma portal qualquer do range 21000 a 211000. Nessa hora, o Zabbix acaba descobrindo essas novas conexões tcp que usam essas portas 21000 a 21100 ignorando o filtro da expressão regular. É pra ser assim ou eu entendi errado a parte de poder filtrar os serviços por expressões regulares?

    [Responder comentário]
  2. Olá Daniel,

    Estranho isso não deveria ocorrer, apenas as portas definidas na expressão deveriam ser registradas como descobertas.

    Tenho algumas suspeitas do que pode estar acontecendo:

    - Nas versões mais recentes do zabbix o campo de filtro foi transferido para uma aba ao lado do discovery rule, verifique se colocou a regex no campo correto.

    - Você pode ter colocado o filtro depois de um tempo que o autodiscovery já estava rodando o que pode ter descoberto serviços nas portas 21000-21100 e esses serviços estão em processo de remoção mas ainda são exibidos, como você pode verificar no autodiscovery o campo "Keep lost resources period" está definido para 1 dia, você pode forçar a remoção desses serviços mudando para 0 e aguardar o tempo do autodiscovery executar novamente, mas lembre-se de voltar para o valor para de 1 dia novamente pois desse modo caso um serviço que esteja sendo monitorado pare o mesmo irá ser removido na próxima vez que o zabbix realizar o autodiscovery e você não receberá um alerta sobre o serviço parado.

    - O zabbix internamente pode tratar a regex de alguma forma diferente, coloque o cifrão "$" no final da regex ^(2121|8080|3306)$

    [Responder comentário]

Deixe um comentário