{"id":7317,"date":"2020-11-29T13:37:44","date_gmt":"2020-11-29T10:37:44","guid":{"rendered":"https:\/\/kifarunix.com\/?p=7317"},"modified":"2024-03-14T23:37:11","modified_gmt":"2024-03-14T20:37:11","slug":"configure-elk-stack-alerting-with-elastalert","status":"publish","type":"post","link":"https:\/\/kifarunix.com\/configure-elk-stack-alerting-with-elastalert\/","title":{"rendered":"Configure ELK Stack Alerting with ElastAlert"},"content":{"rendered":"
Welcome to our tutorial on how to configure ELK Stack alerting with ElastAlert. As much as ELK Stack enables you to collect, process\/parse, index and visualize various system data, it can as well be configured to alert on various events. The alerting features enable you to watch for changes or anomalies in your data and perform the necessary actions in response.if certains event conditions are met<\/em>. ELK stack supports alerting but it is available as a paid subscription and you need a license to use. A 30 day trial version is also available. Well, in this tutorial, we will be using the open-source alternative to Elasticsearch X-Pack alerting feature, ElastAlert.<\/p>\n\n\n\n ElastAlert<\/a> is to be reliable<\/a>, highly modular<\/a>, and easy to set up<\/a> and configure<\/a>.<\/em> It works by combining Elasticsearch with two types of components, rule types and alerts. Elasticsearch is periodically queried and the data is passed to the rule type, which determines when a match is found. When a match occurs, it is given to one or more alerts, which take action based on the match. This is configured by a set of rules, each of which defines a query, a rule type, and a set of alerts.<\/em><\/p>\n\n\n\n Several rule types with common monitoring paradigms are included with ElastAlert:<\/em><\/p>\n\n\n\n Currently, ElastAlert have built in support for these alert types:<\/p>\n\n\n\n There are quite a number of requirements for the installation of ElastAlert as outlined on the requirements page<\/a>. These include;<\/p>\n\n\n\n Follow the links below to install and setup ELK\/Elastic Stack.<\/p>\n\n\n\n Install ELK Stack on Ubuntu 20.04<\/a><\/p>\n\n\n\n Installing ELK Stack on CentOS 8<\/a><\/p>\n\n\n\n Deploy a Single Node Elastic Stack Cluster on Docker Containers<\/a><\/p>\n\n\n\n Install Elastic Stack 7 on Fedora 30\/Fedora 29\/CentOS 7<\/a><\/p>\n\n\n\n Install Elastic Stack 7 on Ubuntu 18.04\/Debian 9.8<\/a><\/p>\n\n\n\n Of course the log data collected are unix timestamped.<\/p>\n\n\n\n In this demo, we are installing ElastAlert on our Elastic stack server running on a CentOS 8 system. Note that you can as well install Elastalert on the client from where you are shipping logs.<\/p>\n\n\n\n As per the requirements above, Python 3.6 is needed for ElastAlert. On CentOS 8, you can install Python 3.6 by executing the command below (if not already installed);<\/p>\n\n\n\n For other distros, refer to the respective documentation on installing Python 3.6.<\/p>\n\n\n\n Similarly, for our CentOS 8 system running Python 3, then you can install PIP by executing the command below;<\/p>\n\n\n\n Refer to your OS distro for specifics on installing PIP.<\/p>\n\n\n\n Similarly, you need to install GNU Compiler Collection (gcc);<\/p>\n\n\n\n You might need to install the Development Tools<\/strong>, which provides comprehensive build tools but installing GCC suffice.<\/p>\n\n\n\n Once the requirements of installing ElastAlert are in place, you can now install latest release version of ElastAlert.<\/p>\n\n\n\n Well, you got two options here;<\/p>\n\n\n\n Next, install ElastAlert Elasticsearch module (for ES version 5 and above).<\/p>\n\n\n\n You can now configure ElastAlert for ELK Stack alerting.<\/p>\n\n\n\n First off, the ElastAlert (as per our installation method of cloning its Github repo) ships with example configuration file, Rename this configuration file removing the .example<\/em> suffix.<\/p>\n\n\n\n The configuration file is highly commented. By default, without comment and empty lines, this is how it looks like;<\/p>\n\n\n\n Open the ElastAlert configuration file for editing;<\/p>\n\n\n\n The only thing we gonna change in the default configuration file is the IP address and port for ES.<\/p>\n\n\n\n Find the IP on which ES is listening<\/p>\n\n\n\n Then;<\/p>\n\n\n\n If your ES is configured with SSL\/Authentication, be sure to set the respective specifics on ElastAlert config file.<\/p>\n\n\n\n Save and exit the config.<\/p>\n\n\n\n This is how our config file then looks like;<\/p>\n\n\n\n Create an ElastAlert index on Elasticsearch to enable it to store information<\/em> and metadata about its queries and alerts<\/em>.<\/p>\n\n\n\n If you encounter the error, After creating the indices, if you navigate to Kibana under stack management > Elasticsearch > Index management, you should be able to see such indices;<\/p>\n\n\n\n As per our setup, the ElastAlert rules are located under, ElastAlert supports different types of rules as explained on Rule Types<\/a> page as well various alert channel types as outlined on ElastAlert Alerts<\/a> page.<\/p>\n\n\n\n In this setup, we will test a few rule type and use email for alerting.<\/p>\n\n\n\n If you check under the example rules directory, we have SSH rules file, In this setup, we are collecting logs from the end points using Filebeat. We would be to alerted via mail in case there is a more than failed 5 login attempts on an end point. Hence, below is our sample SSH configuration without comment lines;<\/p>\n\n\n\n The above search for the authentication failure event type on the index, filebeat-*. It then sent alerts if three failed login attempts are noticed in under a minute. Be sure to set the correct index name and the correct search string for your events.<\/p>\n\n\n\n Save and exit the file once you are done making changes.<\/p>\n\n\n\n Note, for email alerting to work, you need to configure SMTP for email relay. You can check the guide below for setting up Postfix on Ubuntu\/Fedora.<\/p>\n\n\n\n Configure Postfix to Use Gmail SMTP on Ubuntu 20.04<\/a><\/p>\n\n\n\n Configure Postfix to Use Gmail SMTP on Ubuntu 18.04<\/a><\/p>\n\n\n\n Configure Postfix as Send-Only SMTP Server on Fedora 29<\/a><\/p>\n\n\n\n Once you have configured your rule, you need to test whether it actually works. ElastAlert provides a script called The script is installed under, \/usr\/local\/bin;<\/p>\n\n\n\n For example, to test the SSH rule above, navigate to<\/p>\n\n\n\n The script shows the output similar to below;<\/p>\n\n\n\n As you can see, there SSH failed events currently match in our Filebeat index, I am gonna simulate multiple failed ssh events and rerun the script.<\/p>\n\n\n\n As you can see above, we have 5 events in under one minute;<\/p>\n\n\n\n Event Details (Email Body):<\/p>\n\n\n\n Use –help option to see the script arguments you can use. <\/p>\n\n\n\n Once you have confirmed that your query is working fine, it is time to run ElastAlert. ElastAlert can be run as a daemon via supervisord or via Python.<\/p>\n\n\n\n You can as well run it on standard output using the elastalert binary, For example, you run ElastAlert against all rules defined in the rules directory;<\/p>\n\n\n\n To specify a specific rules file;<\/p>\n\n\n\n E.g<\/p>\n\n\n\n In this setup, we run ElastAlert as a service;<\/a><\/p>\n\n\n\n Reload systemd configurations;<\/p>\n\n\n\n Start and enable the service to run on boot;<\/p>\n\n\n\n Checking the status;<\/p>\n\n\n\n To run with ElastAlert Python, see running ElastAlert<\/a>.<\/p>\n\n\n\n Simulate the events and verify if any alert is send and received on mail;<\/p>\n\n\n And that marks the end of our tutorial on how to send ELK stack alerts with ElastAlert via Email. Feel free to explore other alert channels.<\/p>\n\n\n\n Running ElastAlert for the First time<\/a><\/p>\n\n\n\n Monitor Linux System Metrics with ELK Stack<\/a><\/p>\n\n\n\n Visualize WordPress User Activity Logs on ELK Stack<\/a><\/p>\n\n\n\n\n
frequency<\/code> type)<\/em><\/li>\n\n\n\n
spike<\/code> type)<\/em><\/li>\n\n\n\n
flatline<\/code> type)<\/em><\/li>\n\n\n\n
blacklist<\/code> and
whitelist<\/code> type)<\/em><\/li>\n\n\n\n
any<\/code> type)<\/em><\/li>\n\n\n\n
change<\/code> type)<\/em><\/li>\n<\/ul>\n\n\n\n
\n
Sending ELK Stack Alerts with ElastAlert<\/h2>\n\n\n\n
Installing ElastAlert in Linux<\/a><\/h3>\n\n\n\n
\n
Install and Setup Elastic\/ELK Stack<\/h4>\n\n\n\n
Installing Python 3 on Linux<\/h4>\n\n\n\n
dnf install python36 python3-devel<\/code><\/pre>\n\n\n\n
Install PIP on Linux<\/h4>\n\n\n\n
dnf install python3-pip<\/code><\/pre>\n\n\n\n
dnf install gcc<\/code><\/pre>\n\n\n\n
Installing ElastAlert<\/h4>\n\n\n\n
\n
pip3 install elastalert<\/code><\/pre>\n\n\n\n
\n
git clone https:\/\/github.com\/Yelp\/elastalert.git \/opt\/elastalert<\/code><\/pre>\n\n\n\n
cd \/opt\/elastalert<\/code><\/pre>\n\n\n\n
pip3 install \"setuptools>=11.3\" -U<\/code><\/pre>\n\n\n\n
python3 setup.py install<\/code><\/pre>\n\n\n\n
Install Elasticsearch ElastAlert Module<\/h4>\n\n\n\n
pip3 install \"elasticsearch>=5.0.0\"<\/code><\/pre>\n\n\n\n
cd ~<\/code><\/pre>\n\n\n\n
Configuring ELK Stack Alerting with ElastAlert<\/h3>\n\n\n\n
\/opt\/elastalert\/config.yml.example<\/strong><\/code>.<\/p>\n\n\n\n
cp \/opt\/elastalert\/config.yaml{.example,}<\/code><\/pre>\n\n\n\n
rules_folder: example_rules\nrun_every:\n minutes: 1\nbuffer_time:\n minutes: 15\nes_host: elasticsearch.example.com\nes_port: 9200\nwriteback_index: elastalert_status\nwriteback_alias: elastalert_alerts\nalert_time_limit:\n days: 2\n<\/code><\/pre>\n\n\n\n
\n
rules_folder<\/strong><\/code> is where ElastAlert will load rule configuration files from, which in our case is
\/opt\/elastalert\/example_rules<\/code><\/strong>.<\/li>\n\n\n\n
run_every<\/code> <\/strong>is how often ElastAlert will query Elasticsearch.<\/li>\n\n\n\n
buffer_time<\/strong><\/code> is the size of the query window, stretching backwards from the time each query is run.<\/li>\n\n\n\n
es_host<\/strong><\/code> is the address of an Elasticsearch cluster where ElastAlert will store data about its state, queries run, alerts, and errors. Each rule may also use a different Elasticsearch host to query against.<\/li>\n\n\n\n
es_port<\/strong><\/code> is the port corresponding to
es_host<\/code>.<\/li>\n\n\n\n
writeback_index<\/strong><\/code> is the name of the index in which ElastAlert will store data. We will create this index later.<\/li>\n\n\n\n
alert_time_limit<\/strong><\/code> is the retry window for failed alerts.<\/li>\n<\/ul>\n\n\n\n
Define the Address and the Port for the Elasticsearch node;<\/h4>\n\n\n\n
vim \/opt\/elastalert\/config.yaml<\/code><\/pre>\n\n\n\n
ss -altnp | grep :9200<\/code><\/pre>\n\n\n\n
LISTEN 0 128 [::ffff:192.168.57.30]:9200 *:*<\/code><\/pre>\n\n\n\n
...\n# The Elasticsearch hostname for metadata writeback\n# Note that every rule can have its own Elasticsearch host\nes_host: 192.168.57.30\n<\/strong>\n# The Elasticsearch port\nes_port: 9200\n<\/strong>...\n<\/code><\/pre>\n\n\n\n
less \/opt\/elastalert\/config.yaml<\/pre>\n\n\n\n
rules_folder: \/opt\/elastalert\/example_rules\nrun_every:\n minutes: 1\nbuffer_time:\n minutes: 15\nes_host: 192.168.57.30\nes_port: 9200\nwriteback_index: elastalert_status\nwriteback_alias: elastalert_alerts\nalert_time_limit:\n days: 2\n<\/code><\/pre>\n\n\n\n
Create ElastAlert Index on Elasticsearch<\/h4>\n\n\n\n
elastalert-create-index<\/code><\/pre>\n\n\n\n
Elastic Version: 7.8.1\nReading Elastic 6 index mappings:\nReading index mapping 'es_mappings\/6\/silence.json'\nReading index mapping 'es_mappings\/6\/elastalert_status.json'\nReading index mapping 'es_mappings\/6\/elastalert.json'\nReading index mapping 'es_mappings\/6\/past_elastalert.json'\nReading index mapping 'es_mappings\/6\/elastalert_error.json'\nNew index elastalert_status created\nDone!\n<\/code><\/pre>\n\n\n\n
AttributeError: module 'yaml' has no attribute 'FullLoader'<\/strong><\/code>, while creating the ElastAlert ES indices, you can reinstall PyYAML;<\/p>\n\n\n\n
sudo pip3 install --ignore-installed PyYAML<\/code><\/pre>\n\n\n\n
<\/figure>\n\n\n\n
Creating ElastAlert Rules and Alerting<\/h4>\n\n\n\n
\/opt\/elastalert\/example_rules<\/code><\/strong> directory.<\/p>\n\n\n\n
ls \/opt\/elastalert\/example_rules\/ -1<\/code><\/pre>\n\n\n\n
example_cardinality.yaml\nexample_change.yaml\nexample_frequency.yaml\nexample_new_term.yaml\nexample_opsgenie_frequency.yaml\nexample_percentage_match.yaml\nexample_single_metric_agg.yaml\nexample_spike_single_metric_agg.yaml\nexample_spike.yaml\njira_acct.txt\nssh-repeat-offender.yaml\nssh.yaml\n<\/code><\/pre>\n\n\n\n
ELK Stack Email Alerting on Multiple Failed SSH Logins<\/h5>\n\n\n\n
\/opt\/elastalert\/example_rules\/ssh.yaml<\/strong><\/code>.<\/p>\n\n\n\n
vim \/opt\/elastalert\/example_rules\/ssh.yaml<\/code><\/pre>\n\n\n\n
name: Sample SSH Rule\ntype: frequency\nnum_events: 3\ntimeframe:\n minutes: 1\nfilter:\n- query:\n query_string:\n query: \"event.type:authentication_failure\"\nindex: filebeat-*\nrealert:\n minutes: 1\nquery_key:\n - source.ip\ninclude:\n - host.hostname\n - user.name\n - source.ip\ninclude_match_in_root: true\nalert_subject: \"SSH Bruteforce Attacks Detected on {}\"\nalert_subject_args:\n - host.hostname\nalert_text: |-\n Multiple SSH failed logins detected on {}.\n Details of the event:\n - User: {}\n - Source IP: {}\nalert_text_args:\n - host.hostname\n - user.name\n - source.ip\nalert:\n - email:\n from_addr: \"elk@kifarunix-demo.com\"\n email: \"gentoo@kifarunix-demo.com\"\nalert_text_type: alert_text_only\n<\/code><\/pre>\n\n\n\n
Testing ElastAlert Rule<\/h4>\n\n\n\n
elastalert-test-rule<\/strong><\/code> for validating the configured rules.<\/p>\n\n\n\n
which elastalert-test-rule<\/code><\/pre>\n\n\n\n
\/usr\/local\/bin\/elastalert-test-rule<\/code><\/pre>\n\n\n\n
elastalert-test-rule --config \/opt\/elastalert\/config.yaml \/opt\/elastalert\/example_rules\/ssh.yaml<\/code><\/pre>\n\n\n\n
INFO:elastalert:Note: In debug mode, alerts will be logged to console but NOT actually sent.\n To send them but remain verbose, use --verbose instead.\nDidn't get any results.\nINFO:elastalert:Note: In debug mode, alerts will be logged to console but NOT actually sent.\n To send them but remain verbose, use --verbose instead.\n1 rules loaded\nINFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts\nINFO:elastalert:Queried rule SSH abuse (ElastAlert 3.0.1) - 2 from 2020-12-01 21:13 EAT to 2020-12-01 21:14 EAT: 0 \/ 0 hits\n\nWould have written the following documents to writeback index (default is elastalert_status):\n\nelastalert_status - {'rule_name': 'SSH abuse (ElastAlert 3.0.1) - 2', 'endtime': datetime.datetime(2020, 12, 1, 18, 14, 56, 92899, tzinfo=tzutc()), 'starttime': datetime.datetime(2020, 12, 1, 18, 13, 55, 492899, tzinfo=tzutc()), 'matches': 0, 'hits': 0, '@timestamp': datetime.datetime(2020, 12, 1, 18, 14, 56, 416136, tzinfo=tzutc()), 'time_taken': 0.08273959159851074}\n<\/code><\/pre>\n\n\n\n
INFO:elastalert:Queried rule SSH abuse (ElastAlert 3.0.1) - 2 from 2020-12-01 21:13 EAT to 2020-12-01 21:14 EAT: 0 \/ 0 hits<\/strong><\/code>.<\/p>\n\n\n\n
elastalert-test-rule --config \/opt\/elastalert\/config.yaml \/opt\/elastalert\/example_rules\/ssh.yaml<\/code><\/pre>\n\n\n\n
INFO:elastalert:Note: In debug mode, alerts will be logged to console but NOT actually sent.\n To send them but remain verbose, use --verbose instead.\nDidn't get any results.\nINFO:elastalert:Note: In debug mode, alerts will be logged to console but NOT actually sent.\n To send them but remain verbose, use --verbose instead.\n1 rules loaded\nINFO:apscheduler.scheduler:Adding job tentatively -- it will be properly scheduled when the scheduler starts\nINFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 22:04 EAT to 2020-12-01 22:05 EAT: 5 \/ 5 hits\nINFO:elastalert:Alert for Sample SSH Rule at 2020-12-01T22:05:06+03:00:\nINFO:elastalert:Multiple SSH failed logins detected on solr.\nDetails of the event:\n - User: gen_t00\n - Source IP: 192.168.57.1\n\n\n\nWould have written the following documents to writeback index (default is elastalert_status):\n\nsilence - {'exponent': 0, 'rule_name': 'Sample SSH Rule.192.168.57.1', '@timestamp': datetime.datetime(2020, 12, 1, 19, 5, 17, 14585, tzinfo=tzutc()), 'until': datetime.datetime(2020, 12, 1, 19, 6, 17, 14577, tzinfo=tzutc())}\n\nelastalert_status - {'rule_name': 'Sample SSH Rule', 'endtime': datetime.datetime(2020, 12, 1, 19, 5, 16, 979897, tzinfo=tzutc()), 'starttime': datetime.datetime(2020, 12, 1, 19, 4, 16, 379897, tzinfo=tzutc()), 'matches': 1, 'hits': 5, '@timestamp': datetime.datetime(2020, 12, 1, 19, 5, 17, 15185, tzinfo=tzutc()), 'time_taken': 0.012313127517700195}\n<\/code><\/pre>\n\n\n\n
INFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 21:30 EAT to 2020-12-01 21:31 EAT: 5 \/ 5 hits<\/code><\/pre>\n\n\n\n
Multiple SSH failed logins detected on solr.\nDetails of the event:\n - User: gen_t00\n - Source IP: 192.168.57.1<\/code><\/pre>\n\n\n\n
elastalert-test-rule --help<\/pre>\n\n\n\n
Running ElastAlert<\/h3>\n\n\n\n
\/usr\/local\/bin\/elastalert<\/strong><\/code>.<\/p>\n\n\n\n
\/usr\/local\/bin\/elastalert --verbose --config \/opt\/elastalert\/config.yaml<\/code><\/pre>\n\n\n\n
\/usr\/local\/bin\/elastalert --verbose --config \/opt\/elastalert\/config.yaml --rule \/path\/to\/rules-file.yaml<\/code><\/pre>\n\n\n\n
\/usr\/local\/bin\/elastalert --verbose --config \/opt\/elastalert\/config.yaml --rule \/opt\/elastalert\/example_rules\/ssh.yaml<\/code><\/pre>\n\n\n\n
1 rules loaded\nINFO:elastalert:Starting up\nINFO:elastalert:Disabled rules are: []\nINFO:elastalert:Sleeping for 59.99993 seconds\nINFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 22:01 EAT to 2020-12-01 22:16 EAT: 8 \/ 8 hits\nINFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 22:16 EAT to 2020-12-01 22:31 EAT: 0 \/ 0 hits\nINFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 22:31 EAT to 2020-12-01 22:46 EAT: 0 \/ 0 hits\nINFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 22:46 EAT to 2020-12-01 23:01 EAT: 0 \/ 0 hits\nINFO:elastalert:Queried rule Sample SSH Rule from 2020-12-01 23:01 EAT to 2020-12-01 23:12 EAT: 0 \/ 0 hits\nINFO:elastalert:Sent email to ['gentoo@kifarunix-demo.com']\nINFO:elastalert:Ignoring match for silenced rule Sample SSH Rule.192.168.57.1\nINFO:elastalert:Ran Sample SSH Rule from 2020-12-01 22:01 EAT to 2020-12-01 23:12 EAT: 0 query hits (0 already seen), 2 matches, 1 alerts sent\n<\/code><\/pre>\n\n\n\n
cat > \/etc\/systemd\/system\/elastalert.service << 'EOL'\n[Unit]\nDescription=ELK Stack ElastAlert Service\nAfter=elasticsearch.service\n \n[Service]\nType=simple\nWorkingDirectory=\/opt\/elastalert\nExecStart=\/usr\/local\/bin\/elastalert --verbose --config \/opt\/elastalert\/config.yaml\n \n[Install]\nWantedBy=multi-user.target\nEOL\n<\/code><\/pre>\n\n\n\n
systemctl daemon-reload<\/code><\/pre>\n\n\n\n
systemctl enable --now elastalert<\/code><\/pre>\n\n\n\n
systemctl status elastalert<\/code><\/pre>\n\n\n\n
\u25cf elastalert.service - ELK Stack ElastAlert Service\n Loaded: loaded (\/etc\/systemd\/system\/elastalert.service; enabled; vendor preset: disabled)\n Active: active (running) since Tue 2020-12-01 23:18:47 EAT; 38s ago\n Main PID: 7340 (elastalert)\n Tasks: 12 (limit: 17931)\n Memory: 43.9M\n CGroup: \/system.slice\/elastalert.service\n \u2514\u25007340 \/bin\/python3 \/usr\/local\/bin\/elastalert --verbose --config \/opt\/elastalert\/config.yaml\n\nDec 01 23:18:59 elastic.kifarunix-demo.com elastalert[7340]: INFO:elastalert:Queried rule SSH abuse - reapeat offender from 2020-12-01 22:31 EAT to 2020-12-01 22:46 EAT: 0>\nDec 01 23:18:59 elastic.kifarunix-demo.com elastalert[7340]: INFO:elastalert:Queried rule Event spike from 2020-12-01 23:16 EAT to 2020-12-01 23:18 EAT: 0 \/ 0 hits\n...\n<\/code><\/pre>\n\n\n\n
<\/figure><\/div>\n\n\n
Reference<\/h3>\n\n\n\n
Other Tutorials<\/h3>\n\n\n\n