Il 17 febbraio 2015 il progetto Graylog ha pubblicato la versione 1.0, la prima marcata come stabile dopo anni di sviluppo sotto il nome graylog2. La piattaforma raccoglie i log di host eterogenei in un unico punto di ricerca e tiene l’indice separato dai metadati di configurazione, su due motori distinti.

Contesto e problema

In un’infrastruttura di medie dimensioni i log nascono dappertutto: sshd e sudo sui server, web server, firewall, switch, applicazioni con i loro formati. Finché restano in /var/log su ogni macchina, una ricerca trasversale — “chi si è autenticato come root da questo IP nell’ultima ora” — vuol dire fare ssh su ogni host e grep a mano. Per un’indagine di sicurezza non è praticabile, e l’attaccante che cancella i log locali cancella l’unica copia che esiste.

Centralizzare i log risponde a due esigenze diverse: tenere una copia degli eventi fuori dalla portata di un host compromesso, e interrogare l’insieme con una sola query. Lo stack syslog classico (rsyslog, syslog-ng) copre trasporto e inoltro, ma si ferma a file di testo remoti. Per cercare in modo strutturato serve un indice.

Nel 2015 la risposta più comune è lo stack ELK — Elasticsearch, Logstash, Kibana. Graylog copre lo stesso terreno ma divide i compiti in modo diverso: ingestion, instradamento, allarmi e interfaccia di ricerca stanno in un unico server applicativo, e a Elasticsearch resta il solo ruolo di backend di indicizzazione.

Architettura

Graylog 1.0 gira su tre processi:

  • graylog-server — applicazione JVM (Java) che riceve i messaggi, li elabora e serve la REST API
  • Elasticsearch — storage e ricerca full-text dei messaggi indicizzati
  • MongoDB — metadati di configurazione: definizioni degli stream, dashboard, utenti, allarmi

Tenere separati i due datastore è la scelta architetturale centrale. Su Elasticsearch finiscono i log, dati ad alto volume, in sola aggiunta e con retention a tempo; su MongoDB sta la configurazione, a basso volume ma che deve sopravvivere alla ricostruzione di un indice. Se cancelli e reindicizzi Elasticsearch non perdi stream e dashboard, perché vivono altrove.

L’interfaccia web (nella 1.0 una single-page application servita dal server stesso, dopo la fusione del vecchio graylog2-web-interface in Ruby) dialoga con il server solo via REST API. La stessa API è il punto d’aggancio per automazione e integrazioni esterne.

Ingestion e GELF

L’ingestion passa per gli input: ascoltatori che si configurano per protocollo e porta. Graylog 1.0 riceve syslog su UDP e TCP, GELF su UDP/TCP/HTTP, e raw TCP/UDP per il testo non strutturato.

syslog come trasporto ha un limite noto e ormai datato: la RFC 3164 (il “BSD syslog” del 2001, di fatto la descrizione a posteriori di una prassi già esistente) non garantisce una lunghezza minima del messaggio e impasta priorità, timestamp e testo in un’unica riga da decifrare con qualche euristica. La RFC 5424 del 2009 porta structured data e timestamp normalizzati, ma sul campo l’adozione resta parziale.

GELF — Graylog Extended Log Format — nasce per aggirare quei limiti. Un messaggio GELF è un oggetto JSON con campi fissi (version, host, short_message, timestamp, level) e campi aggiuntivi liberi, prefissati da underscore (_user_id, _request_path). Due dettagli pesano nella pratica di chi invia i log dai propri applicativi:

  • chunking — su UDP il messaggio può essere spezzato in più datagrammi, ognuno con un header di magic byte, message ID e numero di sequenza per la riassemblatura. Il limite è di 128 chunk per messaggio e arrivo completo entro 5 secondi, oltre i quali i frammenti parziali si buttano via
  • compressione — su UDP il payload può essere GZIP o ZLIB, riconosciuto dal magic byte; su TCP, invece, GELF non ha né chunking né compressione e si aspetta un payload per riga chiuso da null byte

Il vantaggio concreto di GELF è che il campo strutturato c’è già alla sorgente: l’applicazione emette _order_id=42 come campo, non come stringa da ritagliare più a valle con una regex fragile.

Il punto delicato: estrazione e ordine degli extractor

Quando il log arriva come testo syslog non strutturato, l’informazione utile va tirata fuori dopo l’ingestion. Graylog lo fa con gli extractor: regole applicate ai messaggi di un input che ricavano campi da una porzione di testo — con regex, pattern grok, parsing di sottostringhe o split su separatore. Un extractor grok su un access log Apache produce clientip, verb, response, bytes come campi interrogabili.

Il dettaglio operativo che si paga al primo deployment serio è l’ordine. Gli extractor di un input girano in sequenza, e uno può dipendere da un campo prodotto da quello prima. Sbagliare l’ordine vuol dire che la regola a valle non trova il campo che si aspetta e fallisce in silenzio: il messaggio entra lo stesso nell’indice, ma senza i campi attesi, e la query che li cerca semplicemente non lo restituisce. Nessun errore visibile: un evento che esiste e che la ricerca non vede.

La stessa cautela vale per le condizioni di estrazione. Un extractor che gira su tutti i messaggi di un input ad alto volume, con una regex non ancorata, costa CPU a ogni log. Sotto carico questo si vede come processing backlog — il journal dei messaggi in attesa di indicizzazione cresce, e i log compaiono nella ricerca con minuti di ritardo. Per un’indagine di sicurezza in corso, il ritardo tra evento e visibilità è già di per sé una proprietà di sicurezza.

Stream, allarmi e contesto SIEM

Gli stream smistano i messaggi in flussi logici con regole sui campi: tutti i messaggi con level ≤ 3, o tutti quelli da una certa sorgente. Lo stream è anche l’unità su cui si definiscono gli allarmi — condizioni come “più di N messaggi in M minuti” o “presenza di un campo” — con notifica via email o HTTP.

Questa combinazione di input, stream e allarmi copre una parte di ciò che si chiede a un SIEM (Security Information and Event Management): raccolta centralizzata, normalizzazione, ricerca e allerta su soglia. La correlazione vera tra eventi di sorgenti diverse — regole che incrociano un login fallito con un accesso riuscito subito dopo — resta da costruire a mano sopra stream e allarmi, e qui il confine con i prodotti SIEM commerciali è ancora netto.

Limiti

Graylog 1.0 si porta dietro l’accoppiamento alla versione di Elasticsearch dell’epoca: l’allineamento tra le due versioni non è libero, e un upgrade del backend va verificato contro la compatibilità del server. La pipeline di processing della 1.0 poggia sugli extractor per input, senza ancora un linguaggio di regole indipendente dall’input: una trasformazione complessa richiede di concatenare extractor o di pre-elaborare a monte.

Sul fronte licenza, il codice del server è GPLv3 e il formato GELF è documentato e implementabile da terzi; le librerie GELF per i linguaggi più diffusi ci sono, mantenute fuori dal progetto principale, con qualità e copertura disomogenee.


Immagine di copertina: Logo testuale di Graylog: la scritta “graylog” in minuscolo, con il nome “gray” piu chiaro e “log” piu scuro — logo di Graylog, pubblico dominio — https://commons.wikimedia.org/wiki/File:Graylog_logo.svg