Recopilando los LOGs de VMware ESXi en Elasticsearch y visualizándolos en Grafana

Bueno pues hoy toca otro post sobre recopilación de logs, cómo tratarlos y sobre todo cómo visualizarlos; en este documento veremos cómo realizar todo el proceso con los Logs del hipervisor VMware ESXi, tratarlos con Elastic Stack y finalmente visualizar en Grafana lo que nos interese, como puedan ser logs de errores, de inicios de sesión incorrectos…

 

Todos los que trabajamos con infraestructuras de VMware conocemos que toda la base se sustenta en un fabuloso hipervisor, nuestros queridos los hosts ESXi. Un hipervisor basado en la seguridad y estabilidad, que pocos problemas suelen dar, pero que no viene nada mal recoger sus logs en un lugar centralizado para tener controlada su salud. Como sabemos, podremos almacenar sus logs en un syslog, así que aprovechándonos de eso, mandaremos los Logs a Logstash. Logstash se encargará de recibir y ordenar los logs, separando tediosas cadenas de texto en distintos campos con datos válidos, para finalmente enviar a Elasticsearch estos datos y sean almacenados en un índice. Luego ya mediante Kibana o Grafana podremos visualizar de una manera gráfica ese contenido, y ver los intentos de login al host (por SSH, GUI…), ver simplemente accesos, conocer los eventos con errores, comparar distintos hipervisores entre sí, conocer errores repetitivos… y todo esto como siempre en tiempo real o para realizar históricos con datos de las últimas 24h, semana, mes, año…

 

Primero obviamente tenemos que tener la parte de Elastic Stack instalada, lo que viene siendo LogstashElasticsearch y Kibana; luego ya sería indicarle a cada hipervisor que envíe los Logs a Logstash, al puerto que nos de la gana. Para eso, tenemos muchas maneras de hacerlo, host a host, desde GUI, CLI, desde vCenter…

Lo más cómo si tienes pocos hosts, desde vCenter vamos a cada host, en “Configurar” > Configuración avanzada del sistema” > y buscamos “syslog.global”, editamos ‘Syslog.global.logHost” indicando en formato tcp/udp://DIRECCION_IP:PUERTO el destino de nuestros Logs. O mejor aún con PowerShell:

Get-VMHostSysLogServer -VMHost NOMBRE_HOST_ESXi
Set-VMHostSysLogServer -VMHost NOMBRE_HOST_ESXi -SysLogServer 'udp://DIRECCION_IP:PUERTO
Set-VMHostSysLogServer -VMHost NOMBRE_HOST_ESXi -SysLogServer 'tcp://DIRECCION_IP:PUERTO
Get-VMHostSysLogServer -VMHost NOMBRE_HOST_ESXi

Get-VMhostFireWallException -VMhost NOMBRE_HOST_ESXi -Name syslog
Get-VMHostFireWallException -VMHost NOMBRE_HOST_ESXi -Name Syslog | Set-VMHostFirewallException -Enabled:$True.

 

 

input {
        tcp {
                type => "ESXi"
                port => "1514"
                tags => ["VMware","ESXi"]
        }
}

filter {

        if [type] == "ESXi" {
                        grok {
                            match => { "message" => [
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{GREEDYDATA:Op_id} user=%{GREEDYDATA:Usuario}\] %{GREEDYDATA:Evento_tipo} %{GREEDYDATA:Evento_codigo} : %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{GREEDYDATA:Op_id} user=%{GREEDYDATA:Usuario}\] %{GREEDYDATA:Evento_codigo}: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{GREEDYDATA:Op_id} user=%{GREEDYDATA:Usuario}\] \(%{GREEDYDATA:Evento_codigo}\)",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{GREEDYDATA:Op_id}\] \[%{GREEDYDATA:Evento_codigo}\]: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{GREEDYDATA:Op_id}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Hostd: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Vpxa: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{GREEDYDATA:Op_id}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Vpxa: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Vpxa: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Rhttpproxy: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Rhttpproxy: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} apiForwarder: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} VSANMGMTSVC: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[opID=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vsansystem: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vsansystem: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vmkernel: %{WORD:CPU_core}:%{INT:Evento_id}\)%{GREEDYDATA:Titulo}: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vmkernel: %{WORD:CPU_core}:%{INT:Evento_id} opID=%{PROG:Op_id}\)%{GREEDYDATA:Titulo}: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vmkernel: %{WORD:CPU_core}:%{INT:Evento_id}\)%{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vmkwarning: %{WORD:CPU_core}:%{INT:Evento_id}\)%{GREEDYDATA:Titulo}: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Fdm: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{PROG:Op_id}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} Fdm: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} hostd-probe: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} %{PROG:Log_proceso}\[%{INT:Evento_id}\]: USER %{WORD:Usuario} pid %{INT:pid} %{WORD:Tipo_proceso} %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} %{PROG:Log_proceso}\[%{INT:Evento_id}\]: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} esxtokend: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{DATA:Op_id}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} kmxa: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo} opID=%{DATA:Op_id}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} kmxa: %{WORD:Log_nivel} %{PROG:Log_proceso}\[%{INT:Evento_id}\] \[Originator@6876 sub=%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} vobd:  \[%{WORD:Log_nivel}\] %{WORD:Log_id}: \[%{GREEDYDATA:Titulo}\] %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} configStoreBackup: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} ConfigStore\[%{INT:Evento_id}\]: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} heartbeat: %{WORD:Uptime_estado} %{WORD:Uptime_tiempo}, %{GREEDYDATA:MVs_encendidas}; %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} iscsid: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} smartd: \[%{WORD:Log_nivel}\] %{GREEDYDATA:Titulo}: %{GREEDYDATA:Mensaje}",
                               "<%{POSINT:syslog_pri}>%{TIMESTAMP_ISO8601:Fecha} %{HOSTNAME:Host_ESXi} %{PROG:Log_proceso}\[%{INT:Evento_id}\]: %{GREEDYDATA:Mensaje}"
                                       ]
                            }
                        }
        }
}


output {

        if ([type]=="ESXi"){

                elasticsearch {
                   index => "vmware_esxi-%{+YYYY.MM.dd}"
                   hosts => "DIRECCION_IP_ELASTICSEARCH:9200"
                }

        }
}

Ahora toca Logstash, así que una vez conectados a él, creamos por un fichero de configuración , por ejemplo: ‘/etc/logstash/conf.d/vmware-esxi.conf’. Y será ahí donde indiquemos el puerto de escucha, si escogimos tcp o udp y además vienen los filtros. Así como siempre pido que no me tiren piedras los gurús, pero estos groks son válidos para parsear Logs de VMware ESXi 7.0, eso sí, mejorables y mucho 😉 Bueno, tras separar los logs en trozos le indicaremos que lo vamos a almacenar en Elasticsearch, y ponemos un índice. Recordar no ser como yo y además añadir credenciales, esto es: username & password.

 

Una vez creado el fichero de configuración, recordar reiniciar el servicio de Logstash para recargar la nueva configuración. Después, iremos a Kibana y una vez los datos estén entrando ya podremos ir a “Management” > “Stack management” > “Kibana” > “Index Patterns” > “Create index pattern” para crear el patrón del índice, lo dicho, como habitualmente (en este caso y sin las comillas) ‘vmware_esxi-*’ y tendremos los datos ya en Elasticsearch almacenados de manera correcta. Ahora podríamos conectarnos desde “Discover” a nuestro índice de VMware ESXi y visualizar que está recogiendo datos, que todos los hosts envían…

 

Y para acabar, tras crear el índice en Kibana, ahora en Grafana deberíamos crear un “Data Source” que apunte contra nuestro Elasticsearch y el índice recién creado de VMware ESXi. Luego ya es dejar volar la imaginación, hacer un Dashboard con distintos Paneles, con distintos datos a visualizar, un panel de estilo Sankey para ver IPs origen/destino y el tráfico que se envían, en formato columnas, en tablas para ver datos concretos de por ejemplo los intentos de accesos, correctos, incorrectos, hacer un top con los logs de errores e intentar solucionarlos, comparar entre distintos hosts la ‘normalidad’ de la frecuencia de ciertos logs de info, warning, error….

Como siempre, todo esto para intentar inspiraros si necesitáis, para coger ideas y mejorarlas, así que con esto podréis ver qué pasa en vuestros ESXi’s en tiempo real, poniendo un refresco automático cada 10 segundos queda muy impresionante, también nos servirá para analizar el resumen del último día, o conocer cuando algo extraño sucede… Como siempre, gracias a todos y a tope con los que movéis este tipo de contenidos en redes sociales!!! 😉