GuíasGuides · Nivel 3Level 3

Kibana y Elasticsearch: paneles de logs, reglas de alerta, ciclo de vida de índices con data streams y un clúster en solo lectura por disco llenoKibana and Elasticsearch: log dashboards, alerting rules, index lifecycle with data streams and a cluster gone read-only because the disk is full

Un panel de Kibana para los logs de Windows y Linux, una regla de tipo Elasticsearch query con su conector, una política ILM con rollover y borrado sobre un data stream propio, y el lunes en que Elasticsearch deja de aceptar logs porque el disco ha pasado la marca de flood-stage.A Kibana dashboard for Windows and Linux logs, an Elasticsearch query rule with its connector, an ILM policy with rollover and delete on your own data stream, and the Monday when Elasticsearch stops accepting logs because the disk passed the flood-stage watermark.

Qué vas a conseguir

Pasar de "los logs están en Elasticsearch" a que te avisen: un panel que el equipo abre cada mañana, una regla que manda un mensaje cuando hay demasiados inicios de sesión fallidos, los índices con fecha de caducidad automática gracias a ILM y los data streams, y la rutina para el día en que el disco se llena y Elasticsearch se pone en solo lectura.

Antes de empezar

  • Elasticsearch y Kibana 8.x funcionando, como en la guía de ELK para centralizar logs, con un usuario con permisos de administración.
  • Winlogbeat en los servidores Windows y Filebeat con el módulo system en los Linux. En 8.x escriben en los data streams winlogbeat-8.x.x y filebeat-8.x.x.
  • En kibana.yml, la clave xpack.encryptedSavedObjects.encryptionKey con al menos 32 caracteres. Sin ella, Kibana no deja crear reglas ni conectores.
  • Licencia: con Basic solo están los conectores Index y Server log. Email, Microsoft Teams o Webhook necesitan una suscripción de pago (Gold o superior) o la prueba de 30 días.

1. Un panel para los logs de Windows y Linux

Primero las vistas de datos (data views), que dicen a Kibana qué índices leer:

Kibana · Stack Management › Data Views › Create data view
NameWindows
Index patternwinlogbeat-*
Timestamp field@timestamp
Save data view to Kibana

Otra igual con filebeat-* para Linux. Después Analytics › Dashboards › Create dashboard › Create visualization y, con Lens, cuatro paneles:

PanelVistaFiltro (KQL)Gráfico
Inicios de sesión fallidosWindowsevent.code: 4625Barras por hora, top 10 de winlog.event_data.TargetUserName
Cuentas bloqueadasWindowsevent.code: 4740Tabla con hora, cuenta y host.name
SSH fallido en LinuxLinuxevent.dataset: "system.auth" and system.auth.ssh.event: "Failed"Top 10 de source.ip
Equipos que más registranAmbas(ninguno)Barras por host.name

Guarda el panel con una etiqueta (Tags: operaciones) y el intervalo Last 24 hours. El cuarto panel es el que avisa antes que nadie de un servidor con el log en modo depuración: lo vas a necesitar en el paso 6.

2. El conector

El conector es el canal por el que sale el aviso. Se crea una vez y lo usan todas las reglas:

Kibana · Stack Management › Alerts and Insights › Connectors › Create connector
Microsoft Teams
Connector nameTeams · Operaciones
Webhook URLhttps://contoso.webhook.office.com/webhookb2/...
Save & test
  • La URL del webhook la crea el propietario del canal en Teams. Trátala como una contraseña: quien la tenga puede escribir en el canal.
  • Save & test envía un mensaje de prueba. Si no llega, el servidor de Kibana no tiene salida a Internet o necesita proxy (xpack.actions.proxyUrl en kibana.yml).
  • Con licencia Basic, el conector Index escribe la alerta en un índice; útil para un panel de alertas, pero no avisa a nadie.

3. Una regla de tipo Elasticsearch query

Kibana · Stack Management › Alerts and Insights › Rules › Create rule › Elasticsearch query
NameWindows · más de 20 logons fallidos en 5 min
Query typeKQL or Lucene
Data viewWindows
Queryevent.code: 4625
Whencount() over top 5 host.name
ThresholdIS ABOVE 20
Time windowFor the last 5 minutes
Check every1 minute
Test query
ActionsTeams · Operaciones
Action frequencyOn status changes
Run whenQuery matched
Message{{rule.name}} · {{context.title}} · {{context.link}}
Create rule
  • Test query dice cuántos documentos encuentra ahora mismo. Si devuelve miles, el umbral está mal o falta un filtro.
  • On status changes manda un mensaje cuando salta y otro cuando se recupera (añade una segunda acción con Run when: Recovered), no uno cada minuto.
  • {{context.link}} lleva directo a los documentos en Discover: quien recibe el aviso no tiene que construir la búsqueda.
  • Pon nombre que diga qué pasa y dónde. "Alerta 3" a las tres de la mañana no ayuda.

4. Una política ILM con rollover y borrado

La guía anterior usaba un índice por día y una política que solo borraba. Con rollover, Elasticsearch crea un índice nuevo cuando el actual llega a un tamaño o una edad, y la fase de borrado cuenta desde ese momento. En Dev Tools:

Kibana · Dev Tools · política ILM
PUT _ilm/policy/logs-contoso-30d{  "policy": {    "phases": {      "hot": {        "actions": {          "rollover": { "max_primary_shard_size": "10gb", "max_age": "1d" }        }      },      "delete": {        "min_age": "30d",        "actions": { "delete": {} }      }    }  }}
  • max_age: 1d y max_primary_shard_size: 10gb: lo primero que se cumpla. Con poco volumen, un índice por día; si un día se dispara, se parte antes.
  • min_age: 30d en delete se mide desde el rollover: un índice vive unos 31 días.
  • Los Beats y los data streams logs-*-* usan por defecto las políticas integradas (logs, filebeat, winlogbeat), que hacen rollover pero no borran nunca. Revísalas en Stack Management › Index Lifecycle Policies y añádeles una fase de borrado, o asigna la tuya en su plantilla.

5. Un data stream propio

Un data stream es un nombre lógico (logs-contoso.servers-default) detrás del que hay índices ocultos (.ds-logs-contoso.servers-default-2026.11.03-000001). Se escribe siempre en el nombre y Elasticsearch hace el resto. Lo crea una plantilla de índice con data_stream:

Kibana · Dev Tools · plantilla del data stream
PUT _index_template/logs-contoso.servers{  "index_patterns": ["logs-contoso.servers-*"],  "data_stream": {},  "priority": 200,  "template": {    "settings": {      "index.lifecycle.name": "logs-contoso-30d",      "number_of_replicas": 0    }  }}
  • priority: 200, porque la plantilla integrada logs (patrón logs-*-*, prioridad 100) también encaja con ese nombre y gana la de prioridad más alta.
  • Los documentos necesitan @timestamp: el data stream lo exige.

En Logstash, la salida pasa de un índice con fecha al data stream:

/etc/logstash/conf.d/30-output.conf
output {  elasticsearch {    hosts => ["https://10.20.5.10:9200"]    data_stream => "true"    data_stream_type => "logs"    data_stream_dataset => "contoso.servers"    data_stream_namespace => "default"    user => "logstash_writer"    password => "${ES_PWD}"  }}

Para comprobar que la política se aplica: GET _data_stream/logs-contoso.servers-default muestra los índices y la política, y GET logs-contoso.servers-default/_ilm/explain la fase de cada uno. Un índice en ERROR en el explain es una política que no avanza y un disco que se llena.

En un data stream no se puede borrar el índice de escritura (el más reciente). Si necesitas cerrarlo, primero POST logs-contoso.servers-default/_rollover.

6. El ticket: "Kibana no muestra logs desde el sábado"

Lunes, 9:00. El panel del paso 1 está vacío desde el sábado a las 3:12. Logstash escribe esto en su log sin parar:

srv-elk-01 · journalctl -u logstash
retrying failed action with response code: 429 ({"type"=>"cluster_block_exception", "reason"=>"index [.ds-logs-contoso.servers-default-2026.11.01-000032] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block];"})

Elasticsearch tiene tres marcas de disco por nodo: low (85 %, deja de asignar shards nuevos), high (90 %, intenta mover shards a otro nodo) y flood-stage (95 %). Al pasar la última pone en todos los índices de ese nodo el bloqueo index.blocks.read_only_allow_delete: se puede leer y borrar, pero no escribir.

Kibana · Dev Tools
GET _cat/allocation?v&h=node,disk.percent,disk.used,disk.availnode         disk.percent disk.used disk.availsrv-elk-01             96   479.6gb     20.3gbGET _cluster/health?filter_path=status,number_of_nodes,unassigned_shards{"status":"yellow","number_of_nodes":1,"unassigned_shards":4}GET _cat/indices?v&s=store.size:desc&h=index,store.size&expand_wildcards=allindex                                                  store.size.ds-logs-contoso.servers-default-2026.11.01-000032          61.2gb.ds-logs-contoso.servers-default-2026.10.31-000031          58.7gb.ds-logs-contoso.servers-default-2026.10.04-000004           4.1gb
  • La salud del clúster sigue en amarillo, como siempre en un nodo único con réplicas pendientes. El bloqueo por disco no la pone en rojo: por eso nadie lo vio en el panel de estado.
  • Los dos últimos índices pesan quince veces lo normal. El panel de "equipos que más registran" señala a srv-app-07, que desde el viernes tiene la aplicación en nivel de log DEBUG.

Pasos:

  1. Cortar la causa: devolver el log de srv-app-07 a INFO (o parar su Filebeat mientras tanto).
  2. Liberar espacio borrando lo más antiguo que ya no se necesita. Con el bloqueo, borrar está permitido: DELETE .ds-logs-contoso.servers-default-2026.10.04-000004. Nunca borres ficheros a mano en el directorio de datos.
  3. Esperar a que se levante el bloqueo. Desde la versión 7.4, Elasticsearch quita read_only_allow_delete por sí solo cuando el disco del nodo baja de la marca high (90 %). Comprueba con GET _cat/allocation?v que estás por debajo.
  4. Si el disco ya está por debajo y los índices siguen bloqueados, quítalo a mano:
Kibana · Dev Tools · quitar el bloqueo
PUT */_settings?expand_wildcards=all{  "index.blocks.read_only_allow_delete": null}
  1. Comprobar que entra todo: Logstash reintenta los 429 por su cuenta. Mira en Discover que llegan eventos nuevos y si hay hueco. Lo que Filebeat no pudo enviar lo reintenta desde su registro; lo que se perdió, se anota en el ticket.

Subir la marca de flood-stage al 98 % para "salir del paso" solo aplaza el problema unas horas y deja el nodo sin margen. Si lo haces, vuelve a ponerla en null en cuanto liberes espacio.

Para que no se repita: la regla de Stack Monitoring Disk Usage threshold (o una regla propia sobre el disco) avisando al 80 %, la política del paso 4 con fase de borrado en todos los data streams y un tope de volumen por servidor revisado en el panel.

En el ticket: hora de inicio del bloqueo, servidor y causa del volumen, índices borrados, hora de vuelta a la normalidad y hueco de logs si lo hubo.

Siguientes pasos

  • La guía de ELK para centralizar logs cubre la instalación, el pipeline de Logstash y la búsqueda en Kibana.
  • La de Grafana sirve si el equipo prefiere tener los paneles y las alertas de Elasticsearch junto a los de otras fuentes.
  • Con más de un nodo, la fase warm de ILM mueve los índices viejos a discos más baratos, y las réplicas dejan el clúster en verde.

¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.

What you'll get

Going from "the logs are in Elasticsearch" to being told when something happens: a dashboard the team opens every morning, a rule that sends a message when there are too many failed logons, indices that expire on their own thanks to ILM and data streams, and the routine for the day the disk fills up and Elasticsearch goes read-only.

Before you start

  • Elasticsearch and Kibana 8.x running, as in the ELK log centralisation guide, with a user that has admin rights.
  • Winlogbeat on the Windows servers and Filebeat with the system module on the Linux ones. In 8.x they write to the winlogbeat-8.x.x and filebeat-8.x.x data streams.
  • In kibana.yml, the xpack.encryptedSavedObjects.encryptionKey key with at least 32 characters. Without it, Kibana will not let you create rules or connectors.
  • Licence: with Basic only the Index and Server log connectors are available. Email, Microsoft Teams or Webhook need a paid subscription (Gold or higher) or the 30-day trial.

1. A dashboard for Windows and Linux logs

First the data views, which tell Kibana which indices to read:

Kibana · Stack Management › Data Views › Create data view
NameWindows
Index patternwinlogbeat-*
Timestamp field@timestamp
Save data view to Kibana

Another one the same way with filebeat-* for Linux. Then Analytics › Dashboards › Create dashboard › Create visualization and, with Lens, four panels:

PanelData viewFilter (KQL)Chart
Failed logonsWindowsevent.code: 4625Bars per hour, top 10 winlog.event_data.TargetUserName
Locked-out accountsWindowsevent.code: 4740Table with time, account and host.name
Failed SSH on LinuxLinuxevent.dataset: "system.auth" and system.auth.ssh.event: "Failed"Top 10 source.ip
Noisiest hostsBoth(none)Bars by host.name

Save the dashboard with a tag (Tags: operations) and the Last 24 hours time range. The fourth panel is the one that spots a server left in debug logging before anyone else does: you will need it in step 6.

2. The connector

The connector is the channel the alert goes out through. You create it once and every rule uses it:

Kibana · Stack Management › Alerts and Insights › Connectors › Create connector
Microsoft Teams
Connector nameTeams · Operations
Webhook URLhttps://contoso.webhook.office.com/webhookb2/...
Save & test
  • The webhook URL is created by the channel owner in Teams. Treat it like a password: whoever has it can post to the channel.
  • Save & test sends a test message. If it does not arrive, the Kibana server has no Internet access or needs a proxy (xpack.actions.proxyUrl in kibana.yml).
  • With a Basic licence, the Index connector writes the alert into an index; useful for an alerts dashboard, but it notifies nobody.

3. An Elasticsearch query rule

Kibana · Stack Management › Alerts and Insights › Rules › Create rule › Elasticsearch query
NameWindows · over 20 failed logons in 5 min
Query typeKQL or Lucene
Data viewWindows
Queryevent.code: 4625
Whencount() over top 5 host.name
ThresholdIS ABOVE 20
Time windowFor the last 5 minutes
Check every1 minute
Test query
ActionsTeams · Operations
Action frequencyOn status changes
Run whenQuery matched
Message{{rule.name}} · {{context.title}} · {{context.link}}
Create rule
  • Test query tells you how many documents it finds right now. If it returns thousands, the threshold is wrong or a filter is missing.
  • On status changes sends one message when it fires and another when it recovers (add a second action with Run when: Recovered), not one every minute.
  • {{context.link}} goes straight to the documents in Discover: whoever gets the alert does not have to build the search.
  • Give it a name that says what is happening and where. "Alert 3" at three in the morning helps nobody.

4. An ILM policy with rollover and delete

The earlier guide used one index per day and a policy that only deleted. With rollover, Elasticsearch creates a new index when the current one reaches a size or an age, and the delete phase counts from that moment. In Dev Tools:

Kibana · Dev Tools · ILM policy
PUT _ilm/policy/logs-contoso-30d{  "policy": {    "phases": {      "hot": {        "actions": {          "rollover": { "max_primary_shard_size": "10gb", "max_age": "1d" }        }      },      "delete": {        "min_age": "30d",        "actions": { "delete": {} }      }    }  }}
  • max_age: 1d and max_primary_shard_size: 10gb: whichever comes first. With low volume, one index per day; if a day spikes, it splits earlier.
  • min_age: 30d in delete is measured from rollover: an index lives about 31 days.
  • The Beats and the logs-*-* data streams use the built-in policies by default (logs, filebeat, winlogbeat), which roll over but never delete. Review them in Stack Management › Index Lifecycle Policies and add a delete phase, or assign yours in their template.

5. Your own data stream

A data stream is a logical name (logs-contoso.servers-default) backed by hidden indices (.ds-logs-contoso.servers-default-2026.11.03-000001). You always write to the name and Elasticsearch does the rest. It is created by an index template with data_stream:

Kibana · Dev Tools · data stream template
PUT _index_template/logs-contoso.servers{  "index_patterns": ["logs-contoso.servers-*"],  "data_stream": {},  "priority": 200,  "template": {    "settings": {      "index.lifecycle.name": "logs-contoso-30d",      "number_of_replicas": 0    }  }}
  • priority: 200, because the built-in logs template (pattern logs-*-*, priority 100) also matches that name and the higher priority wins.
  • Documents need @timestamp: the data stream requires it.

In Logstash, the output moves from a dated index to the data stream:

/etc/logstash/conf.d/30-output.conf
output {  elasticsearch {    hosts => ["https://10.20.5.10:9200"]    data_stream => "true"    data_stream_type => "logs"    data_stream_dataset => "contoso.servers"    data_stream_namespace => "default"    user => "logstash_writer"    password => "${ES_PWD}"  }}

To check the policy is applied: GET _data_stream/logs-contoso.servers-default shows the backing indices and the policy, and GET logs-contoso.servers-default/_ilm/explain the phase of each one. An index in ERROR in the explain output is a policy that is stuck and a disk that is filling up.

In a data stream you cannot delete the write index (the newest one). If you need to close it off, first POST logs-contoso.servers-default/_rollover.

6. The ticket: "Kibana shows no logs since Saturday"

Monday, 9:00. The dashboard from step 1 has been empty since Saturday at 3:12. Logstash keeps writing this to its log:

srv-elk-01 · journalctl -u logstash
retrying failed action with response code: 429 ({"type"=>"cluster_block_exception", "reason"=>"index [.ds-logs-contoso.servers-default-2026.11.01-000032] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block];"})

Elasticsearch has three disk watermarks per node: low (85 %, stops allocating new shards), high (90 %, tries to move shards to another node) and flood-stage (95 %). Past the last one it puts the index.blocks.read_only_allow_delete block on every index on that node: you can read and delete, but not write.

Kibana · Dev Tools
GET _cat/allocation?v&h=node,disk.percent,disk.used,disk.availnode         disk.percent disk.used disk.availsrv-elk-01             96   479.6gb     20.3gbGET _cluster/health?filter_path=status,number_of_nodes,unassigned_shards{"status":"yellow","number_of_nodes":1,"unassigned_shards":4}GET _cat/indices?v&s=store.size:desc&h=index,store.size&expand_wildcards=allindex                                                  store.size.ds-logs-contoso.servers-default-2026.11.01-000032          61.2gb.ds-logs-contoso.servers-default-2026.10.31-000031          58.7gb.ds-logs-contoso.servers-default-2026.10.04-000004           4.1gb
  • Cluster health is still yellow, as it always is on a single node with pending replicas. The disk block does not turn it red: that is why nobody saw it on the status panel.
  • The last two indices are fifteen times the usual size. The "noisiest hosts" panel points at srv-app-07, whose application has been on DEBUG log level since Friday.

Steps:

  1. Stop the cause: put srv-app-07's logging back to INFO (or stop its Filebeat in the meantime).
  2. Free space by deleting the oldest data nobody needs. Deleting is allowed under the block: DELETE .ds-logs-contoso.servers-default-2026.10.04-000004. Never delete files by hand in the data directory.
  3. Wait for the block to lift. Since version 7.4, Elasticsearch removes read_only_allow_delete on its own once the node's disk drops below the high watermark (90 %). Check with GET _cat/allocation?v that you are below it.
  4. If the disk is already below it and the indices are still blocked, remove it by hand:
Kibana · Dev Tools · remove the block
PUT */_settings?expand_wildcards=all{  "index.blocks.read_only_allow_delete": null}
  1. Check everything flows in: Logstash retries the 429s on its own. Look in Discover for new events and for any gap. What Filebeat could not send it retries from its registry; anything that was lost goes in the ticket.

Raising the flood-stage watermark to 98 % to "get through it" only postpones the problem by a few hours and leaves the node with no headroom. If you do it, set it back to null as soon as you free space.

So it does not happen again: the Stack Monitoring Disk Usage threshold rule (or your own rule on disk) alerting at 80 %, the step 4 policy with a delete phase on every data stream, and a per-server volume cap reviewed on the dashboard.

In the ticket: when the block started, the server and cause of the volume, the indices deleted, when things were back to normal and any gap in the logs.

Next steps

  • The ELK log centralisation guide covers the installation, the Logstash pipeline and searching in Kibana.
  • The Grafana guide helps if the team prefers Elasticsearch dashboards and alerts next to those from other sources.
  • With more than one node, the ILM warm phase moves old indices to cheaper disks, and replicas turn the cluster green.

Is something missing, or different in your environment? Get in touch and I'll fix it.

Tech Career Lab · newsletter

¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.Found this useful? Every two weeks I send one practical idea for IT professionals: LinkedIn, projects, networking and hiring processes.

Apúntate y llévate las 33 ideasSign up and get the 33 ideas →