
A Python application to filter and transfer Zeek logs to Elastic/OpenSearch+Humio. This app can also output pure JSON logs to stdout for further processing!
This Python application translates Zeek's ASCII TSV and JSON logs into ElasticSearch's bulk load JSON format.

Want to see multiple Zeek logs for the same connection ID (uid) or file ID (fuid)? Here are the hits from files.log, http.log, and conn.log for a single uid:

You can perform subnet searching on Zeek's 'addr' type:

You can create time series graphs, such as this NTP and HTTP graph:

IP Addresses can be Geolocated with the -g command line option:

Aggregations are simple and quick:

This application will "just work" when Zeek log formats change. The logic reads the field names and associated types to set up the mappings correctly in ElasticSearch.
This application will recognize gzip or uncompressed logs. This application assumes
you have ElasticSearch set up on your localhost at the default port.
If you do not have ElasticSearch you can output the JSON to stdout with the -s -b command line options
to process with the jq application.
You can add a keyword subfield to text fields with the -k command line option. This is useful
for aggregations in Kibana.
If Python is already on your system, there is nothing additional for you to copy over to your machine than Elasticsearch, Kibana, and zeek2es.py if you already have the requests library installed.
Assuming you meet the requirements, there is none. You just
copy zeek2es.py to your host and run it with Python. Once Zeek
logs have been imported with automatic index name generation (meaning, you did not supply the -i option)
you will find your indices named "zeek_zeeklogname_date", where zeeklogname is a log name like conn
and the date is in YYYY-MM-DD format. Set your Kibana index pattern to match zeek* in this case. If
you named your index with the -i option, you will need to create a Kibana index pattern that
matches your naming scheme.
If you are upgrading zeek2es, please see the section on upgrading zeek2es.
Now you can put logs in the VOLUME_MOUNT/data/logs directory (VOLUME_MOUNT you set in the .env file).
When logs are CREATED in this directory, zeek2es will begin processing them and pushing them into Elasticsearch.
You can then login to https://localhost:5601 with the username and password you set up in the .env file.
By default there is a self signed certificate, but you can change that if you edit the docker compose files. Once inside
Kibana you will go to Stack Management->Data Views and create a data view for logs* with the timestamp @timestamp.
Now you will be able to go to Discover and start searching your logs! Your data is persistent in the VOLUME_MOUNT/data directory you set.
If you would like to remove all data, just rm -rf VOLUME_MOUNT/data, substituting the directory you set into that remove command.
The next time you start your cluster it will be brand new for more data.
Most upgrades should be as simple as copying the newer zeek2es.py over
the old one. In some cases, the ES ingest pipeline required for the -g command line option
might change during an upgrade. Therefore, it is strongly recommend you delete
your ingest pipeline before you run a new version of zeek2es.py.
If you need to delete the "zeekgeoip" ES ingest pipeline
used to geolocate IP addresses with the -g command line option, you can either do it graphically
through Kibana's Stack Management->Ingest Pipelines or this command will do it for you:
curl -X DELETE "localhost:9200/_ingest/pipeline/zeekgeoip?pretty"
This command is strongly recommended whenever updating your copy of zeek2es.py.
If you would like to automatically import all conn.log files as they are created in a directory, the following fswatch command will do that for you:
fswatch -m poll_monitor --event Created -r /data/logs/zeek/ | awk '/^.*\/conn.*\.log\.gz$/' | parallel -j 5 python ~/zeek2es.py {} -g -d :::: -
If you have the jq command installed you can perform searches across all your logs for a common field like connection uid, even without ElasticSearch:
find /usr/local/var/logs -name "*.log.gz" -exec python ~/Source/zeek2es/zeek2es.py {} -s -b -z \; | jq -c '. | select(.uid=="CLbPij1vThLvQ2qDKh")'
You can use much more complex jq queries than this if you are familiar with jq.
If you want to remove all of your Zeek data from ElasticSearch, this command will do it for you:
curl -X DELETE http://localhost:9200/zeek*
Since the indices have the date appended to them, you could delete Dec 31, 2021 with the following command:
curl -X DELETE http://localhost:9200/zeek_*_2021-12-31
You could delete all conn.log entries with this command:
curl -X DELETE http://localhost:9200/zeek_conn_*
pip.There are two scripts that will help you make your logs into data streams such as logs-zeek-conn.
The first script is process_logs_as_datastream.sh and given
a list of logs and directories, will import them as such. The second script
is process_log.sh, and it can be used to import logs
one at a time. This script can also be used to monitor logs created in a directory with
fswatch. Both scripts have example command lines
if you run them without any parameters.
$ ./process_logs_as_datastream.sh
Usage: ./process_logs_as_datastream.sh NJOBS "ADDITIONAL_ARGS_TO_ZEEK2ES" "LIST_OF_LOGS_DELIMITED_BY_SPACES" DIR1 DIR2 ...
Example:
time ./process_logs_as_datastream.sh 16 "" "amqp bgp conn dce_rpc dhcp dns dpd files ftp http ipsec irc kerberos modbus modbus_register_change mount mqtt mysql nfs notice ntlm ntp ospf portmap radius reporter rdp rfb rip ripng sip smb_cmd smb_files smb_mapping smtp snmp socks ssh ssl stun syslog tunnel vpn weird wireguard x509" /usr/local/var/logs
$ ./process_log.sh
Usage: ./process_log.sh LOGFILENAME "ADDITIONAL_ARGS_TO_ZEEK2ES"
Example:
fswatch -m poll_monitor --event Created -r /data/logs/zeek | awk '/^.*\/(conn|dns|http)\..*\.log\.gz$/' | parallel -j 16 ./process_log.sh {} "" :::: -
You will need to edit these scripts and command lines according to your environment.
Any files having a name of a log such as conn_filter.txt in the lambda_filter_file_dir, by default your home directory, will be applied as a lambda
filter file to the corresponding log input. This allows you to set up all of your filters in one directory and import multiple log files with
that set of filters in one command with process_logs_as_datastream.sh.
The following lines should delete all Zeek data in ElasticSearch no matter if you use indices or data streams, or these helper scripts:
curl -X DELETE http://localhost:9200/zeek*?pretty
curl -X DELETE http://localhost:9200/_data_stream/zeek*?pretty
curl -X DELETE http://localhost:9200/_data_stream/logs-zeek*?pretty
curl -X DELETE http://localhost:9200/_index_template/zeek*?pretty
curl -X DELETE http://localhost:9200/_index_template/logs-zeek*?pretty
curl -X DELETE http://localhost:9200/_ilm/policy/zeek-lifecycle-policy?pretty
... or if using Elastic v8+ ...
curl -X DELETE -k -u elastic:password https://localhost:9200/zeek*?pretty
curl -X DELETE -k -u elastic:password https://localhost:9200/_data_stream/zeek*?pretty
curl -X DELETE -k -u elastic:password https://localhost:9200/_data_stream/logs-zeek*?pretty
curl -X DELETE -k -u elastic:password https://localhost:9200/_index_template/zeek*?pretty
curl -X DELETE -k -u elastic:password https://localhost:9200/_index_template/logs-zeek*?pretty
curl -X DELETE -k -u elastic:password https://localhost:9200/_ilm/policy/zeek-lifecycle-policy?pretty
But to be able to do this in v8+ you will need to configure Elastic as described in the section Elastic v8.0+.
If you'd like to try Cython, you must run python setup.py build_ext --inplace
first to generate your compiled file. You must do this every time you update zeek2es!