Wazuh: security platform with Docker and alerts on Telegram


Even if you already have a good SIEM (Security Information and Event Management) running in your infrastructure, you need to know about Wazuh. This was a great discovery for me, because you can personalize Wazuh as your main security monitor in a big infrastructure, or set Wazuh to be a great tool on your own home network.

Wazuh is a must-have service because it’s easy to install and the default configuration is already quite complete. But if you have need a custom set up, the level of configuration could supply any system stack.

What is Wazuh?

Wazuh, an open-source SIEM tool, provides a solution for threat detection, intrusion detection, vulnerability detection, log analysis, and the best of all, it teaches you how to prevent these issues. In this post, we are going to see the process of installing Wazuh on an Ubuntu Server using Docker, making the implementation seamless and efficient. I will also highlight a few points so you can move this service to your environment.

Why Wazuh?

Wazuh offers a scalable and flexible approach to security monitoring, making it an ideal choice for organizations of all sizes. By centralizing and analyzing security data from diverse sources, Wazuh empowers organizations to proactively respond to potential threats and vulnerabilities.


Prerequisites

Before we dive into the installation process, ensure that you have the following prerequisites in place:

  1. Linux Server: Ensure you have a clean installation, I’m going to use Ubuntu Server with Docker and Docker Compose .
  2. Wazuh documentation, you will need it for custom configuration

Note: I highly recommend following the step-by-step guide if you are going to set up a Wazuh in a production environment. In this case, this is a home lab, so I’m following the quick-start guide.


Important Note: For Telegram alerting, follow the instruction in the Telegram section, if you don’t mind about that, continue with the steps above.


Installation process

Single-node deployment

Clone the Wazuh repository to your server, then we are going to create or copy the certificates and change the default password:

$ git clone https://github.com/wazuh/wazuh-docker.git

You will need to provide a group of certificates for each node in the stack to secure communication between the nodes. You have two alternatives to provide these certificates:

Generate self-signed certificates for each cluster node.

We have created a Docker image to automate certificate generation using the Wazuh certs gen tool.

# Wazuh App Copyright (C) 2021 Wazuh Inc. (License GPLv2)
version: '3'

services:
  generator:
    image: wazuh/wazuh-certs-generator:0.0.1
    hostname: wazuh-certs-generator
    volumes:
      - ./config/wazuh_indexer_ssl_certs/:/certificates/
      - ./config/certs.yml:/config/certs.yml
    environment:
      - HTTP_PROXY=YOUR_PROXY_ADDRESS_OR_DNS

Execute the following command to get the desired certificates:

$ docker-compose -f generate-indexer-certs.yml run --rm generator

This saves the certificates into the config/wazuh_indexer_ssl_certs directory.

Provide your own certificates for each node.

In case you have your own certificates, provision them as follows in the config/wazuh_indexer_ssl_certs directory:

Indexer

config/wazuh_indexer_ssl_certs/root-ca.pem 
config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem configwazuh_indexer_ssl_certs/wazuh.indexer.pem 
config/wazuh_indexer_ssl_certs/admin.pem 
config/wazuh_indexer_ssl_certs/admin-key.pem

Manager

config/wazuh_indexer_ssl_certs/root-ca-manager.pem
config/wazuh_indexer_ssl_certs/wazuh.manager.pem
config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem

Dashboard

config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem
config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem
config/wazuh_indexer_ssl_certs/root-ca.pem

Start the Wazuh single-node deployment using docker-compose:

$ docker-compose up -d

Debugging

To know when the Wazuh indexer is up, the Wazuh dashboard container uses curl to run multiple queries to the Wazuh indexer API. You can expect to see several Failed to connect to Wazuh indexer port 9200 log messages or “Wazuh dashboard server is not ready yet ” until the Wazuh indexer is started. Then the setup process continues normally. It takes about 1 minute for the Wazuh indexer to start up. You can find the default Wazuh indexer credentials in the docker-compose.yml file.

The default username and password for the Wazuh dashboard are admin and SecretPassword. Do not forget to change the default password for the Wazuh indexer admin user.


Change the password of Wazuh users

To improve security, you can change the default password of the Wazuh users. There are two types of users:

  • Wazuh indexer users
  • Wazuh API users

To change the password of these Wazuh users, perform the following steps. You must run the commands from your single-node directory, depending on your Wazuh on Docker deployment.

Wazuh indexer users

To change the password of the default admin and kibanaserver users, do the following. You can only change one at a time.

Setting a new hash

Stop the deployment stack if it’s running:

$ docker-compose down

Run this command to generate the hash of your new password. Once the container launches, input the new password and press Enter.

$ docker run --rm -ti wazuh/wazuh-indexer:4.7.2 bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/hash.sh

Copy the generated hash and open the config/wazuh_indexer/internal_users.yml file. Locate the block for the user you are changing password for.

Replace the hash.

  • admin user
...
admin:
  hash: "$2y$12$K/SpwjtB.wOHJ/Nc6GVRDuc1h0rM1DfvziFRNPtk27P.c4yDr9njO"
  reserved: true
  backend_roles:
  - "admin"
  description: "Demo admin user"
...
  • kibanaserver user
...
kibanaserver:
  hash: "$2a$12$4AcgAt3xwOWadA5s5blL6ev39OXDNhmOesEoo33eZtrq2N0YrU3H."
  reserved: true
  description: "Demo kibanaserver user"
...

Setting the new password

Open the docker-compose.yml file. Change all occurrences of the old password with the new one. For example, for a single-node deployment:

  • admin user
...
services:
  wazuh.manager:
    environment:
      - INDEXER_URL=https://wazuh.indexer:9200
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=SecretPassword
      - FILEBEAT_SSL_VERIFICATION_MODE=full
      - SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
      - SSL_CERTIFICATE=/etc/ssl/filebeat.pem
      - SSL_KEY=/etc/ssl/filebeat.key
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=MyS3cr37P450r.*-
  wazuh.dashboard:
    environment:
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=SecretPassword
      - WAZUH_API_URL=https://wazuh.manager
      - DASHBOARD_USERNAME=kibanaserver
      - DASHBOARD_PASSWORD=kibanaserver
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=MyS3cr37P450r.*-
...

kibanaserver user

...
services:
  wazuh.dashboard:
    environment:
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=SecretPassword
      - WAZUH_API_URL=https://wazuh.manager
      - DASHBOARD_USERNAME=kibanaserver
      - DASHBOARD_PASSWORD=kibanaserver
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=MyS3cr37P450r.*-
...

Applying the changes

Start the deployment stack.

$ docker-compose up -d

Run docker ps and note the name of the first Wazuh indexer container. For example, single-node-wazuh.indexer-1, or multi-node-wazuh1.indexer-1.

Run docker exec -it <WAZUH_INDEXER_CONTAINER_NAME> bash to enter the container. For example:

$ docker exec -it single-node-wazuh.indexer-1 bash

Set the following variables:

export INSTALLATION_DIR=/usr/share/wazuh-indexer
CACERT=$INSTALLATION_DIR/certs/root-ca.pem
KEY=$INSTALLATION_DIR/certs/admin-key.pem
CERT=$INSTALLATION_DIR/certs/admin.pem
export JAVA_HOME=/usr/share/wazuh-indexer/jdk

Wait for the Wazuh indexer to initialize properly. The waiting time can vary from two to five minutes. It depends on the size of the cluster, the assigned resources, and the speed of the network. Then, run the securityadmin.sh script to apply all changes.

$ bash /usr/share/wazuh-indexer/plugins/opensearch-security/tools/securityadmin.sh -cd /usr/share/wazuh-indexer/opensearch-security/ -nhnv -cacert  $CACERT -cert $CERT -key $KEY -p 9200 -icl

Exit the Wazuh indexer container and login with the new credentials on the Wazuh dashboard.


Checking the installation

List the containers in the directory where the Wazuh docker-compose.yml file is located:

$ docker-compose ps

You should get something like this

            Name                           Command               State                                           Ports
--------------------------------------------------------------------------------------------------------------------------------------------------------------
single-node_wazuh.dashboard_1   /entrypoint.sh                   Up      443/tcp, 0.0.0.0:443->5601/tcp,:::443->5601/tcp
single-node_wazuh.indexer_1     /entrypoint.sh opensearchw ...   Up      0.0.0.0:9200->9200/tcp,:::9200->9200/tcp
single-node_wazuh.manager_1     /init                            Up      0.0.0.0:1514->1514/tcp,:::1514->1514/tcp,0.0.0.0:1515->1515/tcp,:::1515->1515/tcp,1516/tcp,0.0.0.0:514->514/udp,:::514->514/udp,                                                                       0.0.0.0:55000->55000/tcp,:::55000->55000/tcp

Access Wazuh Manager

Once the container is running, you can access the Wazuh manager’s web interface by opening a web browser and navigating to https://<your-server-ip> or this could be https://<your-server-ip>:<port>, the port depends on your compose configuration:

... 
wazuh.dashboard:
    image: wazuh/wazuh-dashboard:4.7.1
    hostname: wazuh.dashboard
    restart: always
    ports:
      - 443:5601
...

Log in to start configuring and monitoring your security events.

Finally!

Using Wazuh

Once you login, you’ll find a dashboard like this:

Note: This is my home server, I already added three agents. Yours is going to be empty.

Add agents

We are going to start adding agents to later test all the features Wazuh have. Go to the agent sections and click on “Deploy new agent”.

This part is really straightforward, first select your OS

In server address, add the IP/FQDN of the Wazuh server

Then add a name to identify the endpoint, and if you want, you can make groups to have better organization

In the end, you are going to see a command you have to run on your endpoint. In the case of windows, open the PowerShell as admin and copy the command.

Windows

Linux

Click close, go back to agents, and after a minute, you will see your agent connected and running:

All right, let’s click in one agent to see what’s going on in the endpoint. On mati-win11, an agent running on Windows 11, we get a lot of information. First we have our ID that identify the agent on the infrastructure, also the status, IP, version of Wazuh agent, group, OS, node and registration/last discovery date. Above this information, we can find all the security assessment.


Quick tour in every Dashboard component

The Mitre tactics framework is a knowledge base and model for cyber adversary behavior, reflecting the various phases of an adversary’s attack lifecycle and the platforms they are known to target. More in MITRE ATT&CK and the Enterprise tactics.

Wazuh helps implement compliance requirements for regulatory compliance support and visibility. This is done by providing automation, improved security controls, log analysis, and incident response.

The default Wazuh ruleset provides support for PCI DSS, HIPAA, NIST 800-53, TSC, and GDPR frameworks and standards. Wazuh rules and decoders are used to detect attacks, system errors, security misconfigurations, and policy violations. More information about compliance here.

Each Wazuh agent has its own local database where it stores the current state of each SCA (Security Configuration Assessment). The Wazuh server maintains an SCA database for all agents that are enrolled to it. Wazuh agents only send the differences detected between scans to the Wazuh server. If there has been no change, only a summary of the SCA scan is sent, in this way unnecessary network traffic is avoided while keeping the SCA database on the Wazuh server up to date. The Wazuh server then uses those updates to issue alerts that are shown in the Wazuh dashboard.

Windows CIS
Ubuntu CIS

Clicking on Ubuntu server CIS, we can see every test CIS do. This check, for example, is about chony, the time-server. As we can see, The task is about “Ensure chrony is enabled and running“, the result is “fail“. Above we get a Rationale, a description about why it is important to fix this issue, and more impressive (for me at least) a Remediation description to know how to solve it. How cool is that? New in security? In 20 minutes you have a professional tool to know more about your flaws and more important, learn how to solve it!

Learn how to solve security issues!

Testing Wazuh: Attempt SSH login

Let go back, and click on “Security events“:

Here is another dashboard with all the events on this specific node. As we can see, I have “0 Authentication failures“. Let’s fail some ssh logins to see whats happend with Wazuh

After failing ssh attempts:

Take a closer look to “Attempt to login using a non-existent user“. Here, you can see the ssh attempt with “testuser” on the Ubuntu server. With all the details of this event. As I mentioned in the beginning of this post, I don’t configure anything, this is a default rule for ssh connections.


CVE: Common Vulnerabilities and Exposures

By default Wazuh brings CVE detection disable, let’s enabled the CVE so we also know how to make configuration on the endpoints:

In this case we have to remember that we are using Docker, so the configuration is different than the default one. For configuration without docker, follow the official documentation.

In this case, I’m using a asingle node configuration. If you need you can have a multi-node configuration (bigger systems). Go to the docker directory where you install wazuh and follow this path: ./wazuh-docker/single-node/config/wazuh_cluster/wazuh_manager.conf. Here we are going to enable the vulnerability scan. Change the following lines and set enable for your differents OS endpoints:

<vulnerability-detector>
   <enabled>yes</enabled>
   <interval>5m</interval>
   <min_full_scan_interval>6h</min_full_scan_interval>
   <run_on_start>yes</run_on_start>

   <!-- Ubuntu OS vulnerabilities -->
   <provider name="canonical">
      <enabled>yes</enabled>
      <os>trusty</os>
      <os>xenial</os>
      <os>bionic</os>
      <os>focal</os>
      <os>jammy</os>
      <update_interval>1h</update_interval>
   </provider>

   <!-- Debian OS vulnerabilities -->
   <provider name="debian">
      <enabled>yes</enabled>
      <os>buster</os>
      <os>bullseye</os>
      <os>bookworm</os>
      <update_interval>1h</update_interval>
   </provider>

   <!-- RedHat OS vulnerabilities -->
   <provider name="redhat">
      <enabled>yes</enabled>
      <os>5</os>
      <os>6</os>
      <os>7</os>
      <os>8</os>
      <os>9</os>
      <update_interval>1h</update_interval>
   </provider>

   <!-- Windows OS vulnerabilities -->
   <provider name="msu">
      <enabled>yes</enabled>   
      <update_interval>1h</update_interval>
   </provider>

   <!-- Aggregate vulnerabilities -->
   <provider name="nvd">
      <enabled>yes</enabled>
      <update_interval>1h</update_interval>
   </provider>
</vulnerability-detector>

Remember to restart the agent once you complete the changes:

$ docker-compose stop 
$ docker-compose up -d

Sometimes after the restart, you may notice the dashboard is not fully available, the first vulnerability scan uses CPU power to collect the first data, so be patience.

When wazuh is up again, go to Agents -> Vulneratibilities, and you will find a report for each agent you have. Let’s see the report on the Windows 11 OS:

Here is a Critical Vulnerability on the VLC installation:

Checking the CVE that affect VLC on NVD:

As the NVD web says, we need to update to 3.0.20 to patch this vulneratility, let’s check VLC:

All right! Vulneraty fixed 😎.


Telegram Alerts

To get the alerts on telegram we need to create a docker image first. Luckly, Wazuh is one step head and the repository comes with a script to create a new docker images.

Creating a Docker image

After clonning the repository, modify the Dockerfile on ./wazuh-docker/build-docker-images/wazuh-manager/Dockerfile

$ git clone https://github.com/wazuh/wazuh-docker.git
# Wazuh Docker Copyright (C) 2017, Wazuh Inc. (License GPLv2)
FROM ubuntu:jammy

RUN rm /bin/sh && ln -s /bin/bash /bin/sh

ARG WAZUH_VERSION
ARG WAZUH_TAG_REVISION
ARG FILEBEAT_TEMPLATE_BRANCH
ARG FILEBEAT_CHANNEL=filebeat-oss
ARG FILEBEAT_VERSION=7.10.2
ARG WAZUH_FILEBEAT_MODULE

RUN apt-get update && apt install curl apt-transport-https lsb-release xz-utils gnupg pip -y
RUN pip3 install requests

[...]

Note at the beginning of the file, we are going to add pip package to the instalation, and the create a new task to install requests using pip. Pip is the package installer for Python, and requests is a HTML library.

Now let’s build this wazuh images (this post could be old, so check out to the version of wazuh you need):

$ build-docker-images/build-images.sh -v 4.8.0

This step take time (7 minutes ETC, in my home server), so after a while, you should check your new images using:

$ docker image ls | grep -i wazuh
wazuh/wazuh-dashboard              4.8.0       d29e3fe9cc0e   4 hours ago     1.03GB
wazuh/wazuh-indexer                4.8.0       f37a435e9399   4 hours ago     2.25GB
wazuh/wazuh-manager                4.8.0       0ab64de94f51   4 hours ago     11GB

Provide your own certificates for each node.

In case you have your own certificates, provision them as follows in the config/wazuh_indexer_ssl_certs directory:

Indexer

config/wazuh_indexer_ssl_certs/root-ca.pem 
config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem configwazuh_indexer_ssl_certs/wazuh.indexer.pem 
config/wazuh_indexer_ssl_certs/admin.pem 
config/wazuh_indexer_ssl_certs/admin-key.pem

Manager

config/wazuh_indexer_ssl_certs/root-ca-manager.pem
config/wazuh_indexer_ssl_certs/wazuh.manager.pem
config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem

Dashboard

config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem
config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem
config/wazuh_indexer_ssl_certs/root-ca.pem

Generate self-signed certificates for each cluster node.

With the images ready, next step will be create the certificates. I have problems with the default configuration, so I will show you what I did. Move to ./wazuh-docker/single-node/config/wazuh_indexer_ssl_certs and delete every folder:

$ sudo rm -rf ./wazuh-docker/single-node/config/wazuh_indexer_ssl_certs/*

Now increase max_map_count on your host. This command must be run with root permissions:

# sysctl -w vm.max_map_count=262144

Run the .yml to generate the certificates, that in the ./wazuh-docker/single-node directory and will fill with the new certs the wazuh_indexer_ssl_certs.

$ docker-compose -f generate-indexer-certs.yml run --rm generator

Create a bot on telegram

To send Wazuh alerts to a Telegram chat, we need to create a bot. We have to send a couple of messages to @BotFather. After starting the bot with the /start command, we have to send the /newbot command to start creating the bot, and we will choose the name of the bot, wazuh_mm_bot in this case.

We can also set a profile picture:

Now chat with the bot and write /start

Once the bot is ready, we need the chat id, this is the identifier of the conversation we are having with the bot. To get the chat id we have to access this webpage:

https://api.telegram.org/bot<YOUR-BOT-TOKEN>/getUpdates
{"ok":true,"result":[{"update_id":530302469,"message":{"message_id":27,"from":{"id":38488931,"is_bot":false,"first_name":"xxxxxx","last_name":"xxxxxx","username":"xxxxxx" ,"language_code":"es"},"chat":{"id":xxxxxxxxx,"first_name":"xxxxxxx","last_name":"xxxxxxx","username":"xxxxxxx","type":"p rivate"},"date":1595488212,"text":"a"}}]}

With the chat id and the api token, we are ready for the script.


Python Script

The adition of requests we made previously on the docker image will help us in the following script. We have to set the interpreter to be used by the script:

#!/usr/bin/env python3

The script will have three arguments:

  • alert_file: file containing the alert.
  • hook_url: defined in the ossec.conf, contains the token.
alert_file = open(sys.argv[1])
hook_url = sys.argv[3]

Now the function to generate the message, remember to set your chat_id:

def create_message(alert_json):
    # Get alert information
    title = alert_json['rule']['description'] if 'description' in alert_json['rule'] else ''
    description = alert_json['full_log'] if 'full_log' in alert_json else ''
    description.replace("\\n", "\n")
    alert_level = alert_json['rule']['level'] if 'level' in alert_json['rule'] else ''
    groups = ', '.join(alert_json['rule']['groups']) if 'groups' in alert_json['rule'] else ''
    rule_id = alert_json['rule']['id'] if 'rule' in alert_json else ''
    agent_name = alert_json['agent']['name'] if 'name' in alert_json['agent'] else ''
    agent_id = alert_json['agent']['id'] if 'id' in alert_json['agent'] else ''

    # Format message with markdown
    msg_content = f'*{title}*\n\n'
    msg_content += f'_{description}_\n'
    msg_content += f'*Groups:* {groups}\n' if len(groups) > 0 else ''
    msg_content += f'*Rule:* {rule_id} (Level {alert_level})\n'
    msg_content += f'*Agent:* {agent_name} ({agent_id})\n' if len(agent_name) > 0 else ''

    msg_data = {}
    msg_data['chat_id'] = CHAT_ID
    msg_data['text'] = msg_content
    msg_data['parse_mode'] = 'markdown'

    # Debug information
    with open('/var/ossec/logs/integrations.log', 'a') as f:
        f.write(f'MSG: {msg_data}\n')

    return json.dumps(msg_data)

In this case, messages will have the following information:

  • title: description of the alert, if it exists.
  • description: complete log of the alert.
  • groups: groups of the rule.
  • rule: rule identifier and its level.
  • agent: agent’s name and identifier.
actual alert on telegram

You can also modify the information sent by the script by adding fields from the alerts in the alerts.json file.

The message is written in markdown format, we can play with the format of the message that will be sent. With the alert format done, we can send it to Telegram using:

msg_data = create_message(alert_json)
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
response = requests.post(hook_url, headers=headers, data=msg_data)

Add some debug message in case there is any problem with the script:

with open('/var/ossec/logs/integrations.log', 'a') as f:
    f.write(f'MSG: {msg_data}\n')

with open('/var/ossec/logs/integrations.log', 'a') as f:
    f.write(f'RESPONSE: {response}\n')

The final script

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import json

try:
    import requests
except Exception:
    print("No module 'requests' found. Install: pip3 install requests")
    sys.exit(1)

CHAT_ID = "xxxxxxxx"


def create_message(alert_json):
    # Get alert information
    title = alert_json['rule']['description'] if 'description' in alert_json['rule'] else ''
    description = alert_json['full_log'] if 'full_log' in alert_json else ''
    description.replace("\\n", "\n")
    alert_level = alert_json['rule']['level'] if 'level' in alert_json['rule'] else ''
    groups = ', '.join(alert_json['rule']['groups']) if 'groups' in alert_json['rule'] else ''
    rule_id = alert_json['rule']['id'] if 'rule' in alert_json else ''
    agent_name = alert_json['agent']['name'] if 'name' in alert_json['agent'] else ''
    agent_id = alert_json['agent']['id'] if 'id' in alert_json['agent'] else ''

    # Format message with markdown
    msg_content = f'*{title}*\n\n'
    msg_content += f'_{description}_\n'
    msg_content += f'*Groups:* {groups}\n' if len(groups) > 0 else ''
    msg_content += f'*Rule:* {rule_id} (Level {alert_level})\n'
    msg_content += f'*Agent:* {agent_name} ({agent_id})\n' if len(agent_name) > 0 else ''

    msg_data = {}
    msg_data['chat_id'] = CHAT_ID
    msg_data['text'] = msg_content
    msg_data['parse_mode'] = 'markdown'

    # Debug information
    with open('/var/ossec/logs/integrations.log', 'a') as f:
        f.write(f'MSG: {msg_data}\n')

    return json.dumps(msg_data)


# Read configuration parameters
alert_file = open(sys.argv[1])
hook_url = sys.argv[3]

# Read the alert file
alert_json = json.loads(alert_file.read())
alert_file.close()

# Send the request
msg_data = create_message(alert_json)
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
response = requests.post(hook_url, headers=headers, data=msg_data)

# Debug information
with open('/var/ossec/logs/integrations.log', 'a') as f:
    f.write(f'RESPONSE: {response}\n')

sys.exit(0)

Save the script as custom-telegram. You can change the name, but remember that it must start with “custom-“. More information about custom integration here


Configuring Wazuh to send alerts to Telegram

Let’s edit ./wazuh-docker/single-node/config/wazuh_cluster/wazuh_manager.conf. This is the famous “ossec.conf” file that is been using inside the container, it’s linked to our local server using “volumes” in the docker-compose.yml

[...]
  <!-- Telegram bot -->
  <integration>
    <name>custom-telegram</name>
    <hook_url>https://api.telegram.org/bot<BOT-API-HERE>/sendMessage</hook_url>
    <alert_format>json</alert_format>
  </integration>


</ossec_config>
[...]

I didn’t knowed where to add this instegration block, so I add it almost at the end of the file, inside <ossec_config>.

Create a new directory on ./wazuh-docker/single-node, and copy the script inside. Then, give the following permissions and ownership:

$ mkdir single-node/integrations
$ mv custom-telegram single-node/integrations
$ sudo chown -R root:root single-node/integrations
$ sudo chmod -R 750 single-node/integrations

Edit the docker-compose.yml file to match the same image you previously build, and add the integration folder to the volumes

# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2)
version: '3.7'

services:
  wazuh.manager:
    image: wazuh/wazuh-manager:4.8.0
    hostname: wazuh.manager
    restart: always
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 655360
        hard: 655360
    ports:
      - "1514:1514"
      - "1515:1515"
      - "514:514/udp"
      - "55000:55000"
    environment:
      - INDEXER_URL=https://wazuh.indexer:9200
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=ChangetoEnvPass
      - FILEBEAT_SSL_VERIFICATION_MODE=full
      - SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
      - SSL_CERTIFICATE=/etc/ssl/filebeat.pem
      - SSL_KEY=/etc/ssl/filebeat.key
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=APIPASS.*-
    volumes:
      - wazuh_api_configuration:/var/ossec/api/configuration
      - wazuh_etc:/var/ossec/etc
      - wazuh_logs:/var/ossec/logs
      - wazuh_queue:/var/ossec/queue
      - wazuh_var_multigroups:/var/ossec/var/multigroups
      - wazuh_active_response:/var/ossec/active-response/bin
      - wazuh_agentless:/var/ossec/agentless
      - wazuh_wodles:/var/ossec/wodles
      - filebeat_etc:/etc/filebeat
      - filebeat_var:/var/lib/filebeat
      - /home/user/wazuh-docker/single-node/integrations:/var/ossec/integrations
      - ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
      - ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf

  wazuh.indexer:
    image: wazuh/wazuh-indexer:4.8.0
    hostname: wazuh.indexer
    restart: always
    ports:
      - "9200:9200"
    environment:
      - "OPENSEARCH_JAVA_OPTS=-Xms1024m -Xmx1024m"
      - 'INDEXER_PASSWORD=ChangetoEnvPass'
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - wazuh-indexer-data:/var/lib/wazuh-indexer
      - ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.key
      - ./config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.pem
      - ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
      - ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
      - ./config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
      - ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml

  wazuh.dashboard:
    image: wazuh/wazuh-dashboard:4.8.0
    hostname: wazuh.dashboard
    restart: always
    ports:
      - 443:5601
    environment:
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=ChangetoEnvPass
      - WAZUH_API_URL=https://wazuh.manager
      - DASHBOARD_USERNAME=kibanaserver
      - DASHBOARD_PASSWORD=kibanaserver
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=APIPASS.*-
    volumes:
      - ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
      - ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
      - ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
      - ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
      - wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
      - wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
    depends_on:
      - wazuh.indexer
    links:
      - wazuh.indexer:wazuh.indexer
      - wazuh.manager:wazuh.manager

volumes:
  wazuh_api_configuration:
  wazuh_etc:
  wazuh_logs:
  wazuh_queue:
  wazuh_var_multigroups:
  wazuh_active_response:
  wazuh_agentless:
  wazuh_wodles:
  filebeat_etc:
  filebeat_var:
  wazuh-indexer-data:
  wazuh-dashboard-config:
  wazuh-dashboard-custom:

Final step, light a candle 🕯️ and run the docker-compose.yml:

$ docker-compose up -d

I test the alerts trying to login via ssh using a fake user: testuserTelegram


Troubleshoot note

If the bot isn’t working, enter the container to check the logs:

$ docker ps
acd4bd78jef6   wazuh/wazuh-manager:4.8.0          "/init"                  2 hours ago    Up 2 hours            0.0.0.0:1514-1515->1514-1515/tcp, :::1514-1515->1514-1515/tcp, 0.0.0.0:5
$ docker exec -it acd4bd78jef6 bash
root@wazuh:/# cat /var/log/ossec.log | grep -i telegram | tail

if you have a message like this:

2024/02/14 01:28:06 wazuh-integratord: ERROR: Couldn't execute command (integrations /tmp/custom-telegram-1707874086--958114520.alert  https://api.telegram.or                          g/botYOUR-API-KEY-HERE/sendMessage   10 3 > /dev/null 2>&1). Check file and permissions.

Change the ownership of the integrations directory inside the container:

root@wazuh:/# chown -R root:wazuh /var/ossec/integrations

By installing Wazuh, you’ve taken a significant step toward reinforcing your organization’s cybersecurity defenses. Wazuh’s powerful features and ease of integration make it an invaluable tool for monitoring and responding to security threats effectively. Continue to explore Wazuh’s capabilities, i will see you in the next post.

References

Leave a Comment

Your email address will not be published. Required fields are marked *