This blog post is the first in a series to demonstrate how to install and setup common SIEM platforms. The ultimate goal of each blog post is to empower the reader to choose their own adventure by selecting the best SIEM based on their goals or requirements. Each blog post in the series will provide Docker-compose v2, Docker-compose for Swarm, Ansible, Vagrant, and manual instructions to allow the reader to setup each platform with the deployment method of their choosing. This blog post will cover how to setup the Elastic stack formerly known as ELK. In addition to setting up the Elastic stack I will provide instructions to install Sysmon + Winlogbeat on Windows and Osquery + Filebeat on Ubuntu to ship logs to Elastic.
Goals
- Setup the Elastic stack with Docker
- Setup the Elastic stack with Ansible
- Setup the Elastic stack with Vagrant
- Setup the Elastic stack with manual instructions
- Test Elastic stack with Python script
- Ingest Sysmon logs into Elastic with Winlogbeat
- Ingest Osquery logs into Elastic with Filebeat
Update log
- July 15th 2021 – Updated Docker and Ansible playbooks from v7.10 to v7.13.2
- August 30th 2021 – Added Vagrantfile for Elastic
- October 22nd 2021 – Updated Docker and Ansible playbooks from v7.13.2 to v7.15.1
- January 11th 2022 – Updated Docker and Ansible playbooks from v7.15.1 to v7.16.2
Background
What is Elastic stack?
The ELK stack is an amazing and powerful collection of three open source projects – Elasticsearch, Logstash, and Kibana. Despite each one of these three technologies being a separate project, they have been built to work exceptionally well together. Elastic Stack is a complete end-to-end log analysis solution which helps in deep searching, analyzing and visualizing the log generated from different machines.
What is Sysmon?
System Monitor (Sysmon) is a Windows system service and device driver that, once installed on a system, remains resident across system reboots to monitor and log system activity to the Windows event log. It provides detailed information about process creations, network connections, and changes to file creation time. By collecting the events it generates using Windows Event Collection or SIEM agents and subsequently analyzing them, you can identify malicious or anomalous activity and understand how intruders and malware operate on your network.
What is Osquery?
Osquery exposes an operating system as a high-performance relational database. This allows you to write SQL-based queries to explore operating system data. With osquery, SQL tables represent abstract concepts such as running processes, loaded kernel modules, open network connections, browser plugins, hardware events or file hashes.
What is Winlogbeat?
Winlogbeat ships Windows event logs to Elasticsearch or Logstash. You can install it as a Windows service. Winlogbeat reads from one or more event logs using Windows APIs, filters the events based on user-configured criteria, then sends the event data to the configured outputs (Elasticsearch or Logstash). Winlogbeat watches the event logs so that new event data is sent in a timely manner. The read position for each event log is persisted to disk to allow Winlogbeat to resume after restarts.
What is Filebeat?
Filebeat is a lightweight shipper for forwarding and centralizing log data. Installed as an agent on your servers, Filebeat monitors the log files or locations that you specify, collects log events, and forwards them to Logstash for indexing.
Network diagram
Generate OpenSSL private key and public cert
git clone https://github.com/CptOfEvilMinions/ChooseYourSIEMAdventure
cd ChooseYourSIEMAdventure
vim conf/tls/tls.conf
and set:- Set the location information under
[dn]
C
– Set CountryST
– Set stateL
– Set cityO
– Enter organization nameemailAddress
– Enter a valid e-mail for your org
- Replace
example.com
in all fields with your domain - For alt names list all the valid DNS records for this cert
- Save and exit
- Set the location information under
openssl req -x509 -new -nodes -keyout conf/tls/tls.key -out conf/tls/tls.crt -config conf/tls/tls.conf
- Generate TLS private key and public certificate
Install/Setup Elastic stack v7.15 with Docker-compose v2.x
WARNING
The Docker-compose v2.x setup is for development use ONLY. The setup contains hard-coded credentials in configs and environment variables. For a more secure deployment please skip to the next section to use Ansible.
WARNING
git clone https://github.com/CptOfEvilMinions/ChooseYourSIEMAdventure
cd ChooseYourSIEMAdventure
vim .env
and set:ELASTIC_VERSION
– OPTIONAL – Set the version of Elastic you want to useSIEM_PASSWORD
– Set the password for the Elastic stackNGINX_VERSION
– OPTIONAL – Set the version of NGINX you want to use- Save and exit
docker-compose -f docker-compose-elastic.yml build
docker-compose -f docker-compose-elastic.yml up
Install/Setup Elastic stack v7.15 with Docker-compose v3.x (Swarm)
WARNING
The Docker-compose v3.x is for development use ONLY. The purpose of this setup is to demonstrate how to use the Elastic keystore. Therefore this setup is arguably more secure than Docker-compose v2.x because it uses the Elastic keystore to store credentials, which means that credentials/secrets are not stored in configuration files or environment variables.
WARNING
Create secrets
git clone https://github.com/CptOfEvilMinions/ChooseYourSIEMAdventure
cd ChooseYourSIEMAdventure
for user in 'elastic' 'kibana_system' 'logstash_system' 'beats_system' 'apm_system' 'remote_monitoring_user' 'logstash_writer'; do pass=$(openssl rand -base64 32 | tr -cd '[:alnum:]'); echo ${pass} | docker secret create elastic-builtin-${user} -; echo ${user} - ${pass}; done
- For loop to generate random passwords for each builtin user
Docker start stack
docker stack deploy -c docker-compose-swarm-elastic.yml elastic
docker exec -it $(docker ps | grep elastic_elasticsearch | awk '{print $1}') /usr/share/elasticsearch/elasticsearch-entrypoint.sh
- Execute script to setup builtin users
docker service logs -f elastic_elasticsearch
- Monitor Elasticsearch logs
docker service logs -f elastic_kibana
- Monitor Kibana logs
docker service logs -f elastic_logstash
- Monitor Logstash logs
Install/Setup Elastic stack v7.15 with Ansible
WARNING
This Ansible playbook will allocate half of the systems memory to Elasticsearch. For example, if a machine has 16GBs of memory, 8GBs of memory will be allocated to Elasticsearch.
WARNING
Init playbook
git clone https://github.com/CptOfEvilMinions/ChooseYourSIEMAdventure
cd ChooseYourSIEMAdventure
vim hosts.ini
add IP of Elastic server under[elastic]
vim group_vars/all.yml
and set:base_domain
– Set the domain where the server residestimezone
– OPTIONAL – The default timezone is UTC+0siem_username
– Ignore this settingsiem_password
– Ignore this setting
vim group_vars/elastic.yml
and set:hostname
– Set the desired hostname for the serverelastic_repo_version
– Change the repo version to install the Elastic stack – best to leave as defaultelastic_version
– Set the version of the Elastic stack to install- Save and exit
Run playbook
ansible-playbook -i hosts.ini deploy_elastic.yml -u <username> -K
Install/Setup Elastic stack with Vagrant
git clone https://github.com/CptOfEvilMinions/ChooseYourSIEMAdventure
cd ChooseYourSIEMAdventure
VAGRANT_VAGRANTFILE=Vagrantfile-elastic vagrant up
Manual install/Setup of Elastic stack v7.13
WARNING
These manual instructions will allocate half of the systems memory to Elasticsearch. For example, if a machine has 16GBs of memory, 8GBs of memory will be allocated to Elasticsearch.
WARNING
Init Linux instance
apt update -y && apt upgrade -y && reboot
- Update Ubuntu and reboot
timedatectl set-timezone Etc/UTC
- Set timezone to UTC +0
apt install wget net-tools git -y
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/tls/tls.conf -O /etc/ssl/tls.conf
- Download TLS config
- Go to the “Generate OpenSSL private key and public cert” section at the top for more details
openssl req -x509 -new -nodes -keyout /etc/ssl/private/elastic.key -out /etc/ssl/certs/elastic.crt -config /etc/ssl/tls.conf
- Generate self-signed public certificate and private key
chmod 440 /etc/ssl/private/elastic.key
chmod 644 /etc/ssl/certs/elastic.crt
- Set the proper permissions for the private key and public cert
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
- Add Elastic GPG key
apt-get install apt-transport-https -y
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
- Add Elastic repo
Install/Setup Elasticsearch 7.15
apt-get update && apt-get install elasticsearch=7.15.1 -y
- Install Elasticsearch
sed -i "s#-Xms1g#-Xms$(echo $(( $(dmidecode -t 17 | grep 'Size: ' | awk '{print $2}') / 2 ))"M")#g" /etc/elasticsearch/jvm.options
- Setting the maximum size of the total heap size for Elasticsearch
sed -i "s#-Xmx1g#-Xmx$(echo $(( $(dmidecode -t 17 | grep 'Size: ' | awk '{print $2}') / 2 ))"M")#g" /etc/elasticsearch/jvm.options
- Setting the initial size of the total heap size for Elasticsearch
echo 'xpack.security.enabled: true' >> /etc/elasticsearch/elasticsearch.yml
- Enable X-Pack security
echo 'xpack.security.transport.ssl.enabled: true' >> /etc/elasticsearch/elasticsearch.yml
- Enable X-Pack security transport SSL
echo 'discovery.type: single-node' >> /etc/elasticsearch/elasticsearch.yml
- Set to a single-node mode
systemctl restart elasticsearch
systemctl enable elasticsearch
yes | /usr/share/elasticsearch/bin/elasticsearch-setup-passwords -s auto > /tmp/elasticsearch-setup-passwords.txt
- Generate Elasticsearch passwords
cat /tmp/elasticsearch-setup-passwords.txt
curl -u elastic:<Elastic password> http://127.0.0.1:9200
Install/Setup Kibana 7.15
apt install kibana=7.15.1 -y
sed -i 's/#elasticsearch.username:/elasticsearch.username:/g' /etc/kibana/kibana.yml
- Set the Kibana username for Elasticsearch
sed -i "s/#elasticsearch.password: \"pass\"/elasticsearch.password: \"$(cat /tmp/elasticsearch-setup-passwords.txt | grep kibana_system | grep PASSWORD | awk '{print $4}')\"/g" /etc/kibana/kibana.yml
- Set the Kibana password for Elasticsearch
systemctl restart kibana
systemctl enable kibana
Install/Setup NGINX
apt install nginx -y
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/ansible/nginx/nginx.conf -O /etc/nginx/nginx.conf
- Download
nginx.conf
- Download
ln -s /etc/ssl/certs/elastic.crt /etc/ssl/certs/nginx.crt
ln -s /etc/ssl/private/elastic.key /etc/ssl/private/nginx.key
- Create symlinks to private key and public certificate
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/ansible/nginx/kibana.conf -O /etc/nginx/conf.d/kibana.conf
- Download
kibana.conf
- Download
systemctl restart nginx
systemctl enable nginx
Create Logstash user and role for Elastic
curl -X POST http://localhost:9200/_xpack/security/role/logstash_writer --user elastic:$(cat /tmp/elasticsearch-setup-passwords.txt | grep 'PASSWORD elastic' | awk '{print $4}') -H 'Content-Type: application/json' -d '{"cluster": ["manage_index_templates", "monitor", "manage_ilm"], "indices": [ {"names": [ "*" ], "privileges": ["write","create","delete","create_index","manage","manage_ilm"]}]}'
- Create an Elastic role that allows all users under this role to perform write, create, delete, create_index, manage, manager_ilm actions on Elastic
logstash_writer_password=$(openssl rand -base64 32 | tr -cd '[:alnum:]')
- Generate random password
echo -e "Changed password for user logstash_writer\nPASSWORD logstash_writer = $logstash_writer_password\n" >> /tmp/elasticsearch-setup-passwords.txt
echo $logstash_writer_password
curl --user elastic:$(cat /tmp/elasticsearch-setup-passwords.txt | grep 'PASSWORD elastic' | awk '{print $4}') -X POST http://localhost:9200/_security/user/logstash_writer -H 'Content-Type: application/json' -d '{"password": "$logstash_writer_password", "roles": [ "logstash_writer" ], "full_name": "Logstash writer", "email": "logstash_writer@<domain>"}'
- Create an Elastic user with the role logstash_writer
Install/Setup Logstash 7.15
apt install logstash=1:7.15.1-1 -y
/usr/share/logstash/bin/logstash-plugin install logstash-filter-json_encode
- Install plugin
mkdir /etc/logstash/tls
- Make directory for TLS private key and public certificate
openssl req -x509 -new -nodes -keyout /etc/logstash/tls/logstash.key -out /etc/logstash/tls/logstash.crt -config /etc/ssl/tls.conf
- Generate self-signed public certificate and private key for Logstash
mkdir /etc/logstash/tls
- Make directory for TLS private key and public certificate
chown logstash:logstash /etc/logstash/tls/logstash.key /etc/logstash/tls/logstash.crt
chmod 644 /etc/logstash/tls/logstash.crt
chmod 600 /etc/logstash/tls/logstash.key
- Set the correct permissions for TLS private key and public certificate
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/ansible/elastic/02-input-beats.conf -O /etc/logstash/conf.d/02-input-beats.conf
- Download Logstash Beats input config
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/ansible/elastic/30-output-elasticsearch.conf -O /etc/logstash/conf.d/30-output-elasticsearch.conf
- Download Logstash Elasticsearch output config
sed -i 's/{{ logstash_writer_username }}/logstash_writer/g' /etc/logstash/conf.d/30-output-elasticsearch.conf
- Set the Logstash username for Elasticsearch
sed -i "s/{{ logstash_writer_password }}/$logstash_writer_password/g" /etc/logstash/conf.d/30-output-elasticsearch.conf
- Set the Logstash password for Elasticsearch
systemctl restart logstash
systemctl enable logstash
tail -f /var/log/logstash/logstash-plain.log
Setup UFW
ufw allow OpenSSH
- Allow SSH access
ufw allow 'NGINX http'
- Allow HTTP
ufw allow 'NGINX https'
- Allow HTTPS
ufw allow 5044/tcp
- Allow Logstash
ufw enable
Login into Elastic WebGUI
- Open a browser to
https://<IP addr or FQDN of Elastic>:<Ansible - 443, Docker - 8443>
and login- Username:
elastic
- Password:
<Docker the value of SIEM_PASSWORD in .env, Ansible output for the Elastic user during setup>
- Select “Log in”
- Username:
Test Elastic stack
cd ChooseYourSIEMAdventure/pipeline_testers
virtualenv -p python3 venv
pip3 install -r requirements.txt
python3 beats_input_test.py --platform elastic --host <IP addr of Elastic> --api_port <Elasticsearch port - default 9200> --ingest_port <Logstash port - default 5044> --siem_username elastic --siem_password <Elasticsearch password>
- Log into Elastic
- Expand the menu on the left > Stack Management > Index management
- Expand the menu on the left > Stack Management > Index patterns
- Select “Create index pattern”
- Enter
python-logstash-*
into Define an index pattern - Select “Next step”
- Select “@timestamp” for Time field
- Select “Create index pattern”
- Select “Discover” in the top left
- Enter
<random message>
into search
Ingest Sysmon logs with Winlogbeat on Windows 10
Install/Setup Sysmon v13 on Windows 10
- Login into Windows VM
- Open Powershell as Administrator
cd $ENV:TMP
Invoke-WebRequest -Uri https://download.sysinternals.com/files/Sysmon.zip -OutFile Sysmon.zip
- Download Sysmon
Expand-Archive .\Sysmon.zip -DestinationPath .
- Unzip Sysmon
Invoke-WebRequest -Uri https://raw.githubusercontent.com/olafhartong/sysmon-modular/master/sysmonconfig.xml -OutFile sysmonconfig.xml
- Download Sysmon config
.\Sysmon.exe -accepteula -i .\sysmonconfig.xml
- Install Sysmon driver and load Sysmon config
- Enter
eventvwr
into Powershell - Expand Application and Services Logs > Microsoft > Windows > Sysmon
Install/Setup Winlogbeat on Windows 10
cd $ENV:TEMP
Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/winlogbeat/winlogbeat-7.10.0-windows-x86_64.zip -OutFile winlogbeat-7.10.0-windows-x86_64.zip
- Download Winlogbeat
Expand-Archive .\winlogbeat-7.10.0-windows-x86_64.zip -DestinationPath .
- Unzip Winogbeat
mv .\winlogbeat-7.10.0-windows-x86_64 'C:\Program Files\winlogbeat'
- Move WInlogbeat to the Program Files directory
cd 'C:\Program Files\winlogbeat\'
- Change to the Program Files directory
Invoke-WebRequest -Uri https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/winlogbeat/winlogbeat.yml -OutFile winlogbeat.yml
- code Download Winglogbeat config
- Using your favorite text editor open
C:\Program Files\winlogbeat\winlogbeat.yml
- Open the document from the command line with Visual Studio Code:
code .\winlogbeat.yml
- Open the document from the command line with Notepad:
notepad.exe.\winlogbeat.yml
- Open the document from the command line with Visual Studio Code:
- Scroll down to the
output.logstash:
- Replace
logstash_ip_addr
with the IP address of FQDN of Logstash - Replace
logstash_port
with the port Logstash uses to ingest Beats (default 5044)
- Replace
powershell -Exec bypass -File .\install-service-winlogbeat.ps1
Set-Service -Name "winlogbeat" -StartupType automatic
Start-Service -Name "winlogbeat"
Get-Service -Name "winlogbeat"
Ingest Osquery logs with Filebeat on Ubuntu 20.04
Install/Setup Osquery v4.6.0 on Ubuntu 20.04
- Log into VM with SSH
sudo su
export OSQUERY_KEY=1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $OSQUERY_KEY
- Add Osquery GPG key for repo
add-apt-repository 'deb [arch=amd64] https://pkg.osquery.io/deb deb main'
- Add Osquery repo
apt-get update -y && apt-get install osquery -y
- Install Osquery
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/osquery/linux-osquery.conf -O /etc/osquery/osquery.conf
sed -i 's#/etc/osquery/packs/ossec-rootkit.conf#/usr/share/osquery/packs/ossec-rootkit.conf#g' /etc/osquery/osquery.conf
- Download Osquery config
- Copy of Palantir config
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/osquery/linux-osquery.flags -O /etc/osquery/osquery.flags
- Download Osquery flags
systemctl restart osqueryd
systemctl enable osqueryd
Install/Setup Filebeat v7.10 on Ubuntu 20.04
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add -
- Add Elastic repo GPG key
apt-get install apt-transport-https -y
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
- Add Elastic repo
apt-get update && sudo apt-get install filebeat -y
- Install Filebeat
wget https://raw.githubusercontent.com/CptOfEvilMinions/ChooseYourSIEMAdventure/main/conf/filebeat/linux-filebeat.yml -O /etc/filebeat/filebeat.yml
- Download Filebeat config
sed -i 's/{{ logstash_ip_addr }}/<Logstash IP addr>/g' /etc/filebeat/filebeat.yml
sed -i 's/{{ logstash_port }}/<Logstash Beats port - default 5044>/g' /etc/filebeat/filebeat.yml
- Set the IP address and port for Logastash
filebeat modules enable osquery
- Enable Osquery module for Filebeat
systemctl restart filebeat
systemctl enable filebeat
Create Elastic index patterns
Create Osquery index pattern
- Log into Elastic
- Settings > Stack Management > Data > Index Management
- Ensure that an Osquery index exists
- Settings > Stack Management > Kibana > Index patterns
- Select “Create index pattern”
- Define an index pattern
- Enter
osquery-*
for Index pattern name - Select “Next step”
- Enter
- Configure settings
- Select @timestamp for Time field
- Select “Create index pattern”
- Define an index pattern
- Settings > Overview > Discover
Create Sysmon index pattern
- Log into Elastic
- Settings > Stack Management > Data > Index Management
- Ensure that an Sysmon index exists
- Settings > Stack Management > Kibana > Index patterns
- Select “Create index pattern”
- Define an index pattern
- Enter
sysmon-*
for Index pattern name- Select “Next step”
- Enter
- Configure settings
- Select
event.created
for Time field - Select “Create index pattern”
- Select
- Define an index pattern
- Settings > Overview > Discover
- Select “sysmon” index
Lessons learned
New skills/knowledge
- Learned Elastic stack v7.10 and v7.13
- Learned how to use the Elastic API to create a role and user for Logstash
- Implemented authentication on Elasticsearch
What I would have done better
- I would have liked to implement the Elastic keystore for Docker Swarm