Każdy, kto pracował z systemem SIEM, zna to uczucie: godzina 7:00 rano, przyszliście dopiero do pracy i widzicie ekran rozświetlony dziesiątkami alertów. Próbujecie szybko połączyć kropki: czy to powtarzające się nieudane logowanie to po prostu jakiś pracownik, który zapomniał hasła, czy może początek ataku brute-force? Wazuh to platforma, która daje potężne możliwości w zakresie detekcji zagrożeń, jednak nawet najlepsze narzędzie potrzebuje rąk do pracy. Niestety, w firmach (zwłaszcza tych mniejszych) często jest tylko jedna osoba odpowiedzialna za security. Monitorowanie bezpieczeństwa bywa też często zadaniem pobocznym dla administratorów IT, którzy i tak są już zawaleni robotą związaną z utrzymaniem infrastruktury i nie mają czasu przeprowadzić porządnej weryfikacji alertów, bo co chwilę coś innego odrywa ich od pracy.

W natłoku codziennych obowiązków zespoły SOC / IT spędzają długie godziny na przekopywaniu się przez logi i alerty oraz na budowaniu skomplikowanych zapytań, by zrozumieć kontekst danego incydentu. Pomimo starań, nie zawsze się to udaje, ataki mogą przejść obok nosa niezauważone, bo zabrakło tej jednej informacji, która pozwoliłaby dostrzec szerszy kontekst. A gdyby tak zamiast analizować panele w Wazuhu, można by było prostu… z nim porozmawiać? I gdyby do tego sam system przyjął pozycję Senior SOC Analityka, który natychmiast interpretuje sytuację?

Z taką myślą stworzyłem Wazuh AI Assistant – otwartoźródłowe narzędzie, które zmienia sposób, w jaki wchodzimy w interakcję z alertami. Aplikacja działa jak live chatbot, który stale utrzymuje w pamięci podręcznej historię alertów z ostatnich godzin, pozwalając na intuicyjną rozmowę w naturalnym języku, a dodatkowo automatyzuje codzienne raportowanie statusu cyberbezpieczeństwa naszych systemów.

W tym wpisie pokażę Ci, jak taka integracja przenosi analizę incydentów w Wazuh na zupełnie nowy poziom i jak możesz wdrożyć ją u siebie przy użyciu dowolnego modelu AI.

Czym jest Wazuh AI Assistant

Jest to aplikacja napisana w Pythonie, stworzona na bazie skryptów przygotowanych wcześniej przez zespół Wazuh. Moim celem było zbudowanie pomostu, który pozwoli zaciągać surowe dane bezpośrednio z indeksów OpenSearch Wazuha. Dzięki takiemu podejściu aplikacja może działać na zupełnie osobnym hoście niż sam system SIEM. Następnie te dane są przekazywane do wybranego przez użytkownika modelu AI, który pomaga w błyskawiczny sposób je zinterpretować, wchodząc w rolę doświadczonego Senior SOC Analityka.

Dodatkowo chciałem, aby aplikacja była w stanie automatycznie wysyłać podsumowania mailowe na temat postury cyberbezpieczeństwa monitorowanej infrastruktury codziennie rano, aby osoba odpowiedzialna za system mogła przy porannej kawie szybko zweryfikować, co działo się w nocy.

Tak jak wspomniałem we wstępie, sam pomysł na aplikację zrodził się z moich własnych doświadczeń. Wdrażałem Wazuha już w kilku organizacjach i wiem, że to potężne narzędzie do monitorowania bezpieczeństwa i wykrywania zagrożeń. Jednak, jak to zawsze bywa w przypadku systemów SIEM, na końcu potrzebny jest człowiek, który będzie stale przeglądał dashboardy i analizował spływające zdarzenia, a tych ludzi w firmach po prostu brakuje. Moje narzędzie drastycznie to przyspiesza: zamiast żmudnie przekopywać się przez dziesiątki alertów i surowych logów, możemy po prostu porozmawiać z modelem AI, który wykona tę najcięższą pracę za nas.

Architektura i stack technologiczny

Projekt z założenia miał być lekki, modułowy i łatwy do wdrożenia na osobnym hoście. Aby to osiągnąć, postawiłem na sprawdzone i elastyczne technologie:

  • Backend: FastAPI (Python) – Wybrałem ten framework ze względu na jego niesamowitą wydajność oraz natywne wsparcie dla WebSockets. To właśnie dzięki WebSockets nasz live chatbot działa płynnie i pozwala na interakcję z modelem AI w czasie rzeczywistym.
  • Orkiestracja AI: LangChain – Służy jako rdzeń logiczny aplikacji. Odpowiada za zarządzanie kontekstem rozmowy, budowanie promptów (system prompt nadający rolę Senior SOC Analityka) oraz odpowiednie kierowanie zapytań.
  • Integracja z modelami: LiteLLM – Kluczowy element zapewniający elastyczność. LiteLLM działa jako uniwersalny tłumacz między aplikacją a wybranym przez Ciebie dostawcą AI. Chcesz OpenAI, Anthropic, a może w 100% lokalną Ollamę? Zmieniasz tylko konfigurację, a kod działa tak samo.
  • Wektoryzacja i Baza Wektorowa: HuggingFace Embeddings + FAISS – Aby model AI nie pogubił się w tysiącach linii logów, alerty z OpenSearch są zamieniane na wektory (przy użyciu modeli HuggingFace) i trafiają do lokalnej bazy FAISS. Dzięki temu chatbot potrafi błyskawicznie przeszukać historię ostatnich godzin i wyciągnąć dokładnie te zdarzenia, o które pyta użytkownik.
  • Źródło danych: OpenSearch (Wazuh Indexer) – Aplikacja łączy się bezpośrednio z bazą Wazuha, co pozwala odciążyć sam manager i daje pełen dostęp do surowych, oryginalnych alertów.
  • Automatyzacja powiadomień: SendGrid – Niezawodne i tanie API do wysyłki maili, które dba o to, aby precyzyjnie wygenerowany przez AI raport o posturze bezpieczeństwa trafił prosto do Twojej skrzynki odbiorczej.

Jak dokładnie działa aplikacja?

Serce systemu: Dynamiczne okno czasowe i zarządzanie kontekstem

Największym wyzwaniem przy integracji systemów SIEM z modelami AI jest ograniczone okno kontekstowe samych modeli oraz wysokie koszty zapytań API. Przesłanie wszystkich logów z całego dnia do LLM mogłoby szybko zapchać pamięć podręczną modelu, a przy okazji błyskawicznie wyczyścić Twój portfel.

Aby rozwiązać ten problem, postanowiłem oprzeć asystenta o dynamiczne okno czasowe. Domyślnie wynosi ono 6 godzin, ale czas ten można bardzo łatwo dostosować do własnych potrzeb w pliku konfiguracyjnym aplikacji.

Jak to działa w praktyce? Przy pierwszym uruchomieniu aplikacja zaciąga z Wazuha alerty z określonego przedziału czasowego i zapisuje je w lokalnej bazie wektorowej na dysku. Następnie, co 15 minut, uruchamia się automatyczny proces aktualizacji: system dociąga najnowsze zdarzenia, a te najstarsze usuwa z bazy, dzięki czemu stale utrzymuje precyzyjne, ruchome okno pamięci.

Warto dodać, że aplikacja nie ogranicza się tylko do standardowych powiadomień. Agreguje i analizuje ona dane z następujących indeksów OpenSearch:

  • wazuh-alerts-* (główne alerty bezpieczeństwa)
  • wazuh-monitoring-* (logi wydajnościowe i statusy agentów)
  • wazuh-states-vulnerabilities-* (informacje o wykrytych podatnościach)
  • wazuh-states-inventory-* (dane o inwentarzu systemowym i konfiguracji hostów)

Dzięki temu, kiedy otwierasz webowe UI i zaczynasz rozmowę, sztuczna inteligencja ma natychmiastowy, pełny wgląd w to, co działo się w Twojej infrastrukturze w ciągu ostatnich kilku godzin. Model AI zyskuje kompletny obraz sytuacji, wie nie tylko o samym incydencie, ale potrafi go też automatycznie powiązać z podatnościami systemu czy aktualną konfiguracją zaatakowanego hosta. Nie tracimy czasu na przesyłanie gigabajtów zbędnych danych, a sztuczna inteligencja dostaje dokładnie ten wycinek rzeczywistości, który jest kluczowy do przeprowadzenia szybkiej analizy śledczej.

Prywatność danych i dowolność modeli AI

W cyberbezpieczeństwie prywatność danych to świętość. Nie każdy chce (a ze względów regulacyjnych często wręcz nie może) wysyłać surowych logów systemowych do zewnętrznych, publicznych modeli AI, takich jak OpenAI czy Anthropic (i umówmy się: bez umów biznesowych, ogólnie nie powinno się tego robić).

Dlatego w swoim projekcie postawiłem na integrację z LiteLLM. To otwartoźródłowe oprogramowanie (dostępne w wersji self-hosted), które coraz więcej firm wykorzystuje do centralnego zarządzania modelami AI. Dzięki niemu możemy podpiąć pod asystenta praktycznie dowolny model.

Co to oznacza w praktyce? Jeśli Twoja organizacja posiada biznesowe umowy z komercyjnymi vendorami gwarantujące poufność danych, możesz śmiało korzystać z modeli takich jak Claude Sonnet czy GPT-4o, zachowując pełną kontrolę nad budżetem i limitami zapytań API. Z kolei jeśli polityka firmy wymaga pełnego odizolowania danych (on-premise), bez problemu podepniesz pod asystenta lokalną Ollamę z uruchomionym modelem Llama 3 lub Mistral. To Ty decydujesz, jaki model bada Twoje alerty, gdzie są przetwarzane Twoje dane i na jakich zasadach się to odbywa.

Raport o posturze bezpieczeństwa prosto na maila

Pamiętasz scenariusz z porannym przeglądaniem paneli Wazuha, od którego zacząłem ten wpis? Moja aplikacja rozwiązuje również ten problem. Dzięki wbudowanej integracji z Sendgrid, system automatycznie generuje i wysyła codzienne podsumowanie postury bezpieczeństwa Twojej infrastruktury dokładnie o godzinie 7:00 rano (oczywiście ten czas możesz swobodnie dostosować w konfiguracji). Zamiast witać dzień w stresie i od razu przekopywać surowe logi, możesz spokojnie pić poranną kawę, czytając gotowe, czytelne streszczenie najważniejszych zdarzeń z systemu SIEM z ostatnich godzin.

Dlaczego akurat Sendgrid? Wybrałem to rozwiązanie, ponieważ jest sprawdzone i sam niezwykle często używam go do wysyłki maili w innych projektach. Posiada świetną, oficjalną bibliotekę API dla Pythona, jest niezawodne, bezpieczne i stosunkowo tanie. Oczywiście, jeśli wolicie korzystać z lokalnego serwera pocztowego (np. Postfix) lub Microsoft Exchange, kod jest w pełni otwarty, możecie wrzucić aplikację do dowolnego asystenta AI do kodowania i bez problemu dostosować mechanizm wysyłki do własnych potrzeb.

Wdrożenie aplikacji

Cały projekt jest publicznie dostępny i gotowy do pobrania na moim GitHubie: https://github.com/jedrzejboguszynski/wazuh-ai-assistant

Aby ułatwić Wam start, przygotowałem proces wdrożenia w dwóch różnych wariantach, zależnie od Waszych preferencji:

  • Docker (oraz Docker Compose) – Zdecydowanie najwygodniejsza i najszybsza opcja, która pozwala odizolować aplikację od systemu i uruchomić ją jednym poleceniem.
  • systemd – Klasyczne podejście, idealne, jeśli wolicie uruchomić asystenta jako natywną usługę systemową bezpośrednio na wybranym hoście z systemem Linux.

Przejdziemy teraz przez oba te warianty krok po kroku. Pokażę Wam, jak prawidłowo uruchomić aplikację, a na koniec podrzucę kilka sprawdzonych porad dotyczących samej konfiguracji oraz codziennego korzystania z asystenta.

Przygotowanie użytkownika w systemie Wazuh i konfiguracja Wazuh-indexer

Zanim uruchomimy naszą aplikację, musimy przygotować dla niej dedykowane konto w systemie Wazuh. Użytkownik ten będzie potrzebował uprawnień do odczytu danych z odpowiednich indeksów OpenSearch. Procedura konfiguracji wygląda następująco:

Zaloguj się do panelu Web UI Wazuha. Z menu bocznego po lewej stronie wybierz sekcję Indexer Management -> Security.

W panelu zarządzania bezpieczeństwem OpenSearch Indexera przejdź do zakładki Internal users i kliknij przycisk Create internal user.

Wprowadź nazwę użytkownika oraz wygeneruj silne, bezpieczne hasło. W polu Backend roles dopisz rolę readall_and_monitor. Na koniec zatwierdź wszystko, klikając Create.

Ważna uwaga: Rola readall_and_monitor daje uprawnienia do odczytu wszystkich indeksów w systemie, w tym tych zawierających wrażliwe dane telemetryczne i logi systemowe. Dane uwierzytelniające tego użytkownika pod żadnym pozorem nie mogą wpaść w niepowołane ręce. Przechowuj je wyłącznie w bezpiecznym menedżerze haseł i upewnij się, że dostęp do pliku konfiguracyjnego samej aplikacji jest odpowiednio ograniczony.

Następnie musimy upewnić się, że nasz Wazuh Indexer jest dostępny na porcie 9200 z zewnątrz. Krok ten jest kluczowy, jeśli zamierzacie hostować asystenta AI na osobnym serwerze (jeśli odpalacie go lokalnie, bezpośrednio na maszynie z Wazuhem, możecie go pominąć).

Otwórz plik konfiguracyjny Wazuh Indexera: /etc/wazuh-indexer/opensearch.yml i znajdź parametr network.host (domyślnie jest on ustawiony na 127.0.0.1). Zmień jego wartość na konkretny adres IP serwera, na którym działa Wazuh. Jeżeli maszyna znajduje się w odizolowanej sieci, posiada jeden interfejs sieciowy oraz prawidłowo skonfigurowany firewall (co jest absolutną podstawą), możesz ustawić tę wartość na 0.0.0.0. Sprawi to, że indexer będzie nasłuchiwał połączeń na wszystkich dostępnych interfejsach sieciowych.

network.host: "0.0.0.0"
node.name: "node-1"
cluster.initial_master_nodes:
- "node-1"
cluster.name: "wazuh-cluster"

node.max_local_storage_nodes: "3"
path.data: /var/lib/wazuh-indexer
path.logs: /var/log/wazuh-indexer

plugins.security.ssl.http.pemcert_filepath: /etc/wazuh-indexer/certs/wazuh-indexer.pem
plugins.security.ssl.http.pemkey_filepath: /etc/wazuh-indexer/certs/wazuh-indexer-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem
plugins.security.ssl.transport.pemcert_filepath: /etc/wazuh-indexer/certs/wazuh-indexer.pem
plugins.security.ssl.transport.pemkey_filepath: /etc/wazuh-indexer/certs/wazuh-indexer-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: /etc/wazuh-indexer/certs/root-ca.pem
plugins.security.ssl.http.enabled: true
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.transport.resolve_hostname: false
plugins.security.ssl.http.enabled_ciphers:
  - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
  - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
  - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
  - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
plugins.security.ssl.http.enabled_protocols:
  - "TLSv1.2"
plugins.security.authcz.admin_dn:
- "CN=admin,OU=Wazuh,O=Wazuh,L=California,C=US"
plugins.security.check_snapshot_restore_write_privileges: true
plugins.security.enable_snapshot_restore_privilege: true
plugins.security.nodes_dn:
- "CN=indexer,OU=Wazuh,O=Wazuh,L=California,C=US"
plugins.security.restapi.roles_enabled:
- "all_access"
- "security_rest_api_access"

plugins.security.system_indices.enabled: true
plugins.security.system_indices.indices: [".opendistro-alerting-config", ".opendistro-alerting-alert*", ".opendistro-anomaly-results*", ".opendistro-anomaly-detector*", ".opendistro-anomaly-checkpoints", ".opendistro-anomaly-detection-state>

### Option to allow Filebeat-oss 7.10.2 to work ###
compatibility.override_main_response_version: true

Po wprowadzeniu zmian zrestartuj usługę Wazuh Indexera, aby nowa konfiguracja sieciowa została zaaplikowana:

sudo systemctl restart wazuh-indexer

Musimy również zrestartować usługę Wazuh Dashboard, aby całość działała prawidłowo. Jeśli zmieniłeś adres na 0.0.0.0, wszystko powinno ruszyć od razu po restarcie. Jeżeli natomiast wstawiłeś tam specyficzny adres IP serwera, musisz go odzwierciedlić także w konfiguracji samego dashboardu w pliku /etc/wazuh-dashboard/opensearch_dashboards.yml (szukaj parametru opensearch.hosts), tak aby komponenty mogły się ze sobą bezproblemowo skomunikować.

sudo systemctl restart wazuh-dashboard

Aby sprawdzić, czy usługa prawidłowo nasłuchuje na nowym adresie, możemy użyć polecenia ss -tulpn:

root@wazuh:~# ss -tulpn
Netid    State     Recv-Q    Send-Q                                   Local Address:Port         Peer Address:Port    Process
udp      UNCONN    0         0                                         192.168.0.60:68                0.0.0.0:*        users:(("dhcpcd",pid=4105,fd=3))
udp      UNCONN    0         0                          [2a02:a314:c591:9e80::2610]:546                  [::]:*        users:(("dhcpcd",pid=1101,fd=3))
udp      UNCONN    0         0            [2a02:a314:c591:9e80:1ef8:5ec4:6dd1:75d9]:546                  [::]:*        users:(("dhcpcd",pid=1042,fd=3))
udp      UNCONN    0         0                   [fe80::b6a9:2460:51ca:ae67]%enp0s8:546                  [::]:*        users:(("dhcpcd",pid=916,fd=3))
tcp      LISTEN    0         128                                            0.0.0.0:22                0.0.0.0:*        users:(("sshd",pid=751,fd=6))
tcp      LISTEN    0         511                                            0.0.0.0:443               0.0.0.0:*        users:(("node",pid=618,fd=19))
tcp      LISTEN    0         128                                            0.0.0.0:1514              0.0.0.0:*        users:(("wazuh-remoted",pid=1224,fd=4))
tcp      LISTEN    0         128                                            0.0.0.0:1515              0.0.0.0:*        users:(("wazuh-authd",pid=1019,fd=6))
tcp      LISTEN    0         2048                                           0.0.0.0:55000             0.0.0.0:*        users:(("python3",pid=964,fd=45))
tcp      LISTEN    0         128                                               [::]:22                   [::]:*        users:(("sshd",pid=751,fd=7))
tcp      LISTEN    0         4096                                                 *:9200                    *:*        users:(("java",pid=8508,fd=618))
tcp      LISTEN    0         4096                                                 *:9300                    *:*        users:(("java",pid=8508,fd=616))
tcp      LISTEN    0         2048                                              [::]:55000                [::]:*        users:(("python3",pid=964,fd=47))

Następnie musimy otworzyć port na naszej zaporze sieciowej. Jako że OpenSearch Indexer jest główną bazą danych zawierającą wszystkie alerty oraz krytyczne informacje z systemu SIEM, reguła ta musi być maksymalnie restrykcyjna. Zezwolimy na połączenia na porcie 9200/tcp wyłącznie na interfejsie sieciowym, na którym nasłuchuje Wazuh Indexer, i tylko z konkretnego adresu IP, z którego będzie łączyć się nasz Wazuh AI Assistant. Oczywiście domyślna polityka Waszego firewalla dla ruchu wchodzącego powinna być bezwzględnie ustawiona na DROP lub REJECT (blokowanie całego ruchu, który nie został jawnie dopuszczony).

sudo iptables -A INPUT -p tcp -i <interface_name> -s <source_ip> --dport 9200 -j ACCEPT

Po dodaniu reguły możemy zweryfikować, czy nasz Wazuh Indexer prawidłowo przepuszcza ruch i nasłuchuje na danym porcie z poziomu zewnętrznego hosta (maszyny, na której stanie asystent AI). Użyjemy do tego klasycznego, niezawodnego polecenia telnet <adres_ip> 9200. Jeśli konfiguracja sieciowa oraz reguły firewalla zostały wdrożone poprawnie, na ekranie terminala powinniśmy zobaczyć komunikat informujący o udanym połączeniu:

Trying 192.168.0.60...
Connected to 192.168.0.60.
Escape character is '^]'.

Po skonfigurowaniu wszystkich niezbędnych elementów po stronie serwera Wazuh, jesteśmy w pełni gotowi, aby przejść do właściwego etapu, czyli uruchomienia i konfiguracji samego asystenta AI.

Istotne parametry konfiguracyjne przed uruchomieniem

Zanim ostatecznie uruchomisz asystenta, warto zwrócić uwagę na dwa parametry w pliku konfiguracyjnym, które bezpośrednio wpływają na stabilność i logikę działania aplikacji:

  • Okno czasowe synchronizacji danych (DAYS_RANGE) Domyślnie parametr ten został ustawiony na wartość 0.25 (czyli 6 godzin). W przypadku infrastruktury, dla której budowałem to rozwiązanie, był to optymalny przedział, system generował w ciągu doby grubo ponad 400 tysięcy zdarzeń. Tak ogromna ilość danych nie mieściła się w oknie kontekstowym modelu językowego (testowane na Claude 3.5 Sonnet) podczas jednej analizy. Zmniejszenie okna do 6 godzin pozwoliło idealnie wstrzelić się w limity modelu i przekazać mu do weryfikacji kompletny zestaw danych z danego okresu. Wartość tę należy bezwzględnie dostosować do natężenia ruchu i liczby alertów generowanych przez Twój system Wazuh.
  • Automatyczne raporty e-mail (DAILY_REPORT_TIME) Podsumowania stanu cyberbezpieczeństwa infrastruktury (generowane na bazie danych z Wazuha i wysyłane przez platformę SendGrid) domyślnie są wysyłane codziennie o godzinie 07:00 rano. Godzina ta jest sprawdzana na podstawie strefy czasowej ustawionej w systemie operacyjnym hosta. To idealna pora, aby przy porannej kawie zapoznać się z szybkim, zwięzłym podsumowaniem tego, co działo się w sieci podczas nocnej zmiany. Parametr ten możesz oczywiście swobodnie zmodyfikować i dopasować do własnego harmonogramu pracy.
Wariant 1: Uruchomienie za pomocą Docker i Docker Compose

Aby uruchomić asystenta w kontenerze, na Twoim hoście musi być zainstalowany silnik Docker wraz z wtyczką Docker Compose.

Pierwszym krokiem jest sklonowanie repozytorium projektu na lokalną maszynę i przejście do katalogu głównego aplikacji za pomocą terminala (CLI):

git clone https://github.com/jedrzejboguszynski/wazuh-ai-assistant.git
cd wazuh-ai-assistant/

Następnie musimy uzupełnić plik docker-compose.yml odpowiednimi zmiennymi środowiskowymi. W pliku tym konfigurujemy parametry połączenia dla Wazuh Indexera, platformy LiteLLM (odpowiedzialnej za integrację z modelami AI) oraz usługi SendGrid (opcjonalnie, jeśli asystent ma wysyłać powiadomienia e-mail). W tym miejscu definiujemy również bezpieczne hasło dostępowe, które będzie wymagane podczas logowania do panelu webowego (Web UI) samego asystenta.

version: "3.9"

services:
  wazuh-ai-agent:
    build: .
    container_name: wazuh-ai-agent
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      # Connecting with Wazuh Indexer (OpenSearch)
      - OPENSEARCH_INDEXES=wazuh-alerts-*,wazuh-monitoring-*,wazuh-states-vulnerabilities-*,wazuh-states-inventory-*
      - OPENSEARCH_URL=https://<ADRES_IP_SERWERA_WAZUH>:9200
      - OPENSEARCH_USER=<TWÓJ_UŻYTKOWNIK_WAZUH_INDEXER>
      - OPENSEARCH_PASSWORD=<HASŁO_UŻYTKOWNIKA_WAZUH_INDEXER>
      - OPENSEARCH_VERIFY_SSL=false

      # LiteLLM integration
      - LITELLM_API_BASE=<ADRES_INSTANCJI_LITELLM>
      - LITELLM_API_KEY=<TWÓJ_KLUCZ_API_LITELLM>
      - LITELLM_MODEL=<NAZWA_MODELU_AI>

      # Assistent Web UI access control
      - WEB_PASSWORD=<TWOJE_HASŁO_DO_WEBUI_ASYSTENTA>
      - WEB_USERNAME=admin

      # Data sync configuration
      - DAYS_RANGE=0.25
      - AUTO_REFRESH_ENABLED=true
      - AUTO_REFRESH_INTERVAL=15

      # Optional email reports configuration
      - DAILY_REPORT_TIME=07:00
      - SENDGRID_API_KEY=<TWÓJ_KLUCZ_API_SENDGRID>
      - SENDGRID_FROM_EMAIL=<ADRES_NADAWCY_EMAIL>
      - SENDGRID_TO_EMAILS=<ADRES_ODBIORCY_EMAIL>

      - PYTHONUNBUFFERED=1
    volumes:
      - ./data:/app/data

Po uzupełnieniu wszystkich zmiennych środowiskowych zapisujemy plik i uruchamiamy nasz kontener w tle jednym poleceniem:

docker compose up -d

Po zbudowaniu obrazu i uruchomieniu kontenera musimy uzbroić się w odrobinę cierpliwości. Aplikacja zacznie teraz zaciągać rekordy z Wazuh Indexera z ostatnich 6 godzin i przy użyciu procesora (CPU) rozpocznie ich konwersję (embedding) do wektorowej bazy danych przechowywanej lokalnie na dysku.

Pierwsza synchronizacja i przetworzenie danych może potrwać od 20 do nawet 40 minut – w zależności od tego, jak potężnym sprzętem dysponujecie. To idealny moment, żeby zrobić sobie kawkę, popatrzeć przez okno i dać głowie chwilę odpocząć. ☕

Każda kolejna, automatyczna synchronizacja uruchamiana co 15 minut będzie już przebiegać błyskawicznie, ponieważ system będzie dociągał i wektoryzował wyłącznie najnowsze, pojedyncze zdarzenia.

Logi z tego procesu wyglądają następująco:

INFO:     Started server process [1]

INFO:     Waiting for application startup.

🚀 Starting FastAPI app and loading vector store...

✅ Configuration validation passed

✅ Successfully connected to OpenSearch (status: yellow)

🔄 Loading existing data from disk...

📂 No saved vectorstore found on disk

📥 No cached data found, will perform initial load from OpenSearch

🔄 Loading fresh data from OpenSearch (past 0.25 days)...

📥 Fetching data from OpenSearch: 2026-06-23T02:48:28.000Z to 2026-06-23T08:48:28.000Z

📑 Querying indexes: wazuh-alerts-*, wazuh-monitoring-*, wazuh-states-vulnerabilities-*, wazuh-states-inventory-*

📊 Found 126093 records across all indexes
📥 Fetched 2000/126093 records...

📥 Fetched 4000/126093 records (1285 rec/s, ETA: 95s)

📥 Fetched 6000/126093 records (1224 rec/s, ETA: 98s)
.
.
.
📥 Fetched 126000/126093 records (1467 rec/s, ETA: 0s)

📥 Fetched 126093/126093 records (1456 rec/s, ETA: 0s)

✅ Successfully loaded 126093 records from OpenSearch

  📋 wazuh-alerts-4.x-2026.06.23: 125472 records

  📋 wazuh-monitoring-2026.26w: 621 records

✅ 126093 records loaded from the last 0.25 day(s).

📦 Processing 126093 records...

⚡ Using 4 CPU cores, processing 17 batches...

   Progress: 5/17 batches (40371 chunks so far)

   Progress: 10/17 batches (80223 chunks so far)

   Progress: 15/17 batches (111886 chunks so far)

   Progress: 17/17 batches (127702 chunks so far)

📦 Creating FAISS index with 127702 document chunks...

⚡ Generating embeddings (this may take a while)...

✅ FAISS index created successfully

💾 Vectorstore saved to disk at /app/data/vectorstore

📊 Cached 126093 records from 2026-06-23 02:48 to 2026-06-23 08:48

🤖 Initializing LiteLLM proxy with model 'claude-sonnet-4-5-20250929' at ...

✅ QA chain initialized successfully with Claude via LiteLLM.

✅ Startup complete - ready to accept connections

🔄 Auto-refresh enabled: Will sync every 15 minutes

✅ Auto-refresh started (interval: 15 minutes)

📅 Daily report scheduler started

   Schedule: 07:00 UTC daily

   Recipients: j.boguszynski@boguszynski-solutions.pl✅ Daily report scheduler started (sends at 07:00 UTC)

   Auto-enabled (SendGrid configured)

INFO:     Application startup complete.


INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

Po pojawieniu się w logach komunikatu Uvicorn running on http://0.0.0.0:8000, nasz asystent jest w pełni gotowy do pracy. Możemy teraz otworzyć przeglądarkę i uruchomić jego panel Web UI pod wskazanym adresem (wpisując IP hosta, na którym działa kontener, oraz port 8000).

Wariant 2: Uruchomienie jako usługa systemd

Aby uruchomić asystenta bezpośrednio w systemie jako usługę systemd, należy w pierwszej kolejności utworzyć dedykowanego użytkownika systemowego. Ze względów bezpieczeństwa aplikacja nigdy nie powinna być uruchamiana z uprawnieniami konta root.

Dedykowanego użytkownika o nazwie wazuh-ai, pozbawionego możliwości bezpośredniego logowania do powłoki oraz posiadającego własny katalog domowy, utworzymy za pomocą poniższego polecenia:

sudo useradd -r -m -s /bin/false wazuh-ai

Klonujemy repozytorium do bezpiecznego katalogu na serwerze Linux, najlepiej do ścieżki /opt/. Po pobraniu plików musimy również przekazać prawa własności do tego katalogu naszemu nowo utworzonemu użytkownikowi, aby usługa miała możliwość zapisu lokalnej bazy wektorowej.

cd /opt/
sudo git clone https://github.com/jedrzejboguszynski/wazuh-ai-assistant.git
chown -R wazuh-ai:wazuh-ai /opt/wazuh-ai-assistant/
cd wazuh-ai-assistant/

Następnie musimy stworzyć wirtualne środowisko Pythona (venv) dla naszego użytkownika i zainstalować w nim wszystkie wymagane pakiety z pliku requirements.txt. Użycie wirtualnego środowiska zapewni izolację zależności asystenta od bibliotek systemowych. Wszystkie operacje wykonujemy jako użytkownik wazuh-ai, aby pliki środowisko miały od razu poprawne uprawnienia:

sudo -u wazuh-ai python3 -m venv venv
sudo -u wazuh-ai venv/bin/pip install --upgrade pip
sudo -u wazuh-ai venv/bin/pip install -r requirements.txt

Mając już gotowe środowisko Pythona, musimy przygotować plik ze zmiennymi środowiskowymi, który posłuży jako centralna konfiguracja naszej aplikacji. Zdefiniujemy w nim parametry połączenia do Wazuh Indexera, platformy LiteLLM oraz (opcjonalnie, jeśli chcemy otrzymywać codzienne raporty) dane uwierzytelniające do usługi SendGrid.

cp /opt/wazuh-ai-assistant/env.example /opt/wazuh-ai-assistant/.env

Otwieramy plik .env przy pomocy wybranego edytora tekstu (np. nano) i uzupełniamy parametry konfiguracyjne aplikacji:

# Wazuh AI Agent Configuration
# Auto-generated from docker-compose.yml
# Generated on: 2026-06-18 15:00:22
#
# To run locally:
#   export $(cat .env | grep -v '^#' | xargs)
#   python3 agentic_soc.py

# ===== OpenSearch Configuration =====
OPENSEARCH_INDEXES=wazuh-alerts-*,wazuh-monitoring-*,wazuh-states-vulnerabilities-*,wazuh-states-inventory-*
OPENSEARCH_PASSWORD=<HASŁO_UŻYTKOWNIKA_WAZUH_INDEXER>
OPENSEARCH_URL=https://<ADRES_IP_SERWERA_WAZUH>:9200
OPENSEARCH_USER=<TWÓJ_UŻYTKOWNIK_WAZUH_INDEXER>
OPENSEARCH_VERIFY_SSL=false

# ===== LiteLLM Configuration =====
LITELLM_API_BASE=<ADRES_INSTANCJI_LITELLM>
LITELLM_API_KEY=<TWÓJ_KLUCZ_API_LITELLM>
LITELLM_MODEL=<NAZWA_MODELU_AI>

# ===== Web UI Authentication =====
WEB_PASSWORD=<TWOJE_HASŁO_DO_WEBUI_ASYSTENTA>
WEB_USERNAME=admin

# ===== Auto-Refresh Configuration =====
AUTO_REFRESH_ENABLED=true
AUTO_REFRESH_INTERVAL=15

# ===== Daily Email Reports =====
DAILY_REPORT_TIME=07:00
SENDGRID_API_KEY=<TWÓJ_KLUCZ_API_SENDGRID>
SENDGRID_FROM_EMAIL=<ADRES_NADAWCY_EMAIL>
SENDGRID_TO_EMAILS=<ADRES_NADAWCY_EMAIL>

# ===== Other Configuration =====
# Time range for data loading (in days)
# 0.25 = 6 hours (optimal for AI context window - ~87K records)
# 0.5 = 12 hours (~175K records)
# 1 = 24 hours (~350K records - may overflow context)
DAYS_RANGE=0.25
PYTHONUNBUFFERED=1

Po zapisaniu pliku ze zmiennymi środowiskowymi musimy skonfigurować plik usługi systemowej, który będzie odpowiedzialny za automatyczne uruchamianie asystenta wraz ze startem systemu. W repozytorium projektu znajduje się już gotowy, przygotowany do tego celu szablon konfiguracji. Wystarczy skopiować go do systemowego katalogu /etc/systemd/system/.

sudo cp /opt/wazuh-ai-assistant/systemd/wazuh-ai-agent.service /etc/systemd/system/
sudo chown root:root /etc/systemd/system/wazuh-ai-agent.service
sudo chmod 644 /etc/systemd/system/wazuh-ai-agent.service

Następnie przeładowujemy menedżera konfiguracji systemd, aby system wykrył nowo dodany plik usługi, a następnie uruchamiamy asystenta i włączamy jego automatyczny start przy każdym uruchomieniu serwera.

sudo systemctl daemon-reload
sudo systemctl start wazuh-ai-agent
sudo systemctl enable wazuh-ai-agent

Po pierwszym uruchomieniu usługi musimy uzbroić się w odrobinę cierpliwości. Aplikacja zacznie teraz zaciągać rekordy z Wazuh Indexera z ostatnich 6 godzin i przy użyciu procesora (CPU) rozpocznie ich konwersję (embedding) do wektorowej bazy danych przechowywanej lokalnie na dysku.

Pierwsza synchronizacja i przetworzenie danych może potrwać od 20 do nawet 40 minut – w zależności od tego, jak potężnym sprzętem dysponujecie. To idealny moment, żeby zrobić sobie kawkę, popatrzeć przez okno i dać głowie chwilę odpocząć. ☕

Każda kolejna, automatyczna synchronizacja uruchamiana co 15 minut będzie już przebiegać błyskawicznie, ponieważ system będzie dociągał i wektoryzował wyłącznie najnowsze, pojedyncze zdarzenia.

Usługa automatycznie przekazuje wszystkie logi do systemowego mechanizmu journald. Dzięki temu możemy na bieżąco śledzić proces uruchamiania i pracy asystenta za pomocą polecenia journalctl -fu wazuh-ai-agent:

INFO:     Started server process [1]

INFO:     Waiting for application startup.

🚀 Starting FastAPI app and loading vector store...

✅ Configuration validation passed

✅ Successfully connected to OpenSearch (status: yellow)

🔄 Loading existing data from disk...

📂 No saved vectorstore found on disk

📥 No cached data found, will perform initial load from OpenSearch

🔄 Loading fresh data from OpenSearch (past 0.25 days)...

📥 Fetching data from OpenSearch: 2026-06-23T02:48:28.000Z to 2026-06-23T08:48:28.000Z

📑 Querying indexes: wazuh-alerts-*, wazuh-monitoring-*, wazuh-states-vulnerabilities-*, wazuh-states-inventory-*

📊 Found 126093 records across all indexes
📥 Fetched 2000/126093 records...

📥 Fetched 4000/126093 records (1285 rec/s, ETA: 95s)

📥 Fetched 6000/126093 records (1224 rec/s, ETA: 98s)
.
.
.
📥 Fetched 126000/126093 records (1467 rec/s, ETA: 0s)

📥 Fetched 126093/126093 records (1456 rec/s, ETA: 0s)

✅ Successfully loaded 126093 records from OpenSearch

  📋 wazuh-alerts-4.x-2026.06.23: 125472 records

  📋 wazuh-monitoring-2026.26w: 621 records

✅ 126093 records loaded from the last 0.25 day(s).

📦 Processing 126093 records...

⚡ Using 4 CPU cores, processing 17 batches...

   Progress: 5/17 batches (40371 chunks so far)

   Progress: 10/17 batches (80223 chunks so far)

   Progress: 15/17 batches (111886 chunks so far)

   Progress: 17/17 batches (127702 chunks so far)

📦 Creating FAISS index with 127702 document chunks...

⚡ Generating embeddings (this may take a while)...

✅ FAISS index created successfully

💾 Vectorstore saved to disk at /app/data/vectorstore

📊 Cached 126093 records from 2026-06-23 02:48 to 2026-06-23 08:48

🤖 Initializing LiteLLM proxy with model 'claude-sonnet-4-5-20250929' at ...

✅ QA chain initialized successfully with Claude via LiteLLM.

✅ Startup complete - ready to accept connections

🔄 Auto-refresh enabled: Will sync every 15 minutes

✅ Auto-refresh started (interval: 15 minutes)

📅 Daily report scheduler started

   Schedule: 07:00 UTC daily

   Recipients: j.boguszynski@boguszynski-solutions.pl✅ Daily report scheduler started (sends at 07:00 UTC)

   Auto-enabled (SendGrid configured)

INFO:     Application startup complete.


INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

Po pojawieniu się w logach komunikatu Uvicorn running on http://0.0.0.0:8000, nasz asystent jest w pełni gotowy do pracy. Możemy teraz otworzyć przeglądarkę i uruchomić jego panel Web UI pod wskazanym adresem (wpisując IP hosta, na którym działa kontener, oraz port 8000).

Zabezpieczenie panelu Web UI za pomocą Nginx Reverse Proxy (SSL/TLS)

W przypadku wdrażania aplikacji w sieci firmowej kluczowe jest odpowiednie zabezpieczenie panelu Web UI przy użyciu szyfrowania SSL/TLS. Pozwoli to zapobiec przesyłaniu danych logowania otwartym tekstem (plaintext) wewnątrz sieci lokalnej.

Najlepszym rozwiązaniem tego problemu jest konfiguracja serwera Nginx jako tzw. reverse proxy. Gotowy szablon pliku konfiguracyjnego znajdziesz bezpośrednio w katalogu /nginx/ w repozytorium projektu.

Kopiujemy plik konfiguracyjny do katalogu z konfiguracją serwera Nginx:

sudo cp /opt/wazuh-ai-assistant/nginx/wazuh-ai-agent.conf /etc/nginx/sites-available/

Otwieramy plik do edycji i aktualizujemy nazwę domenową (server_name) oraz wskazujemy poprawną ścieżkę do naszych certyfikatów SSL/TLS (np. wygenerowanych przez wewnętrzne CA lub Let’s Encrypt):

server_name wazuh-ai.twojadomena.local;

ssl_certificate /etc/ssl/certs/wazuh-ai-assistant.crt;
ssl_certificate_key /etc/ssl/private/wazuh-ai-assistant.key;

Przed restartem musimy jeszcze włączyć nową konfigurację, tworząc dowiązanie symboliczne (symlink) do katalogu sites-enabled. Na koniec weryfikujemy poprawność składni plików i restartujemy usługę Nginx, aby nowa konfiguracja zaczęła działa:

sudo ln -s /etc/nginx/sites-available/wazuh-ai-assistant.conf /etc/nginx/sites-enabled/
sudo systemctl restart nginx

Ważna uwaga: Jeżeli uruchamiacie serwer Nginx (reverse proxy) na innym hoście niż sama aplikacja wazuh-ai-assistant, musicie pamiętać o odpowiedniej modyfikacji dyrektywy proxy_pass.

Prezentacja działania asystenta

Kiedy panel Web UI oraz live chat naszego asystenta są już w pełni dostępne, możemy swobodnie zacząć zadawać mu pytania. Warto dokładnie i precyzyjnie opisywać swoje oczekiwania, dzięki temu aplikacja skuteczniej przeszuka lokalną bazę wektorową i przekaże do modelu LLM kontekst o najwyższej trafności.

Poniższe zrzuty ekranu pochodzą z produkcyjnego systemu Wazuh. Chciałem jak najlepiej zaprezentować, jak aplikacja radzi sobie przy przetwarzaniu bardzo dużej liczby danych, dlatego widoczne na nich wrażliwe informacje zostały odpowiednio zredagowane.

W zależności od tego, jakie źródła danych mamy podpięte pod system Wazuh, asystenta możemy odpytywać również o znacznie bardziej szczegółowe elementy naszej infrastruktury, a nawet o tematy, które nie są bezpośrednio związane z samym cyberbezpieczeństwem.

Jeśli chodzi o codzienne podsumowania mailowe, które asystent generuje i wysyła automatycznie każdego ranka, prezentują się one następująco:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
WAZUH DAILY SECURITY REPORT
Generated: 2026-06-23 05:02 UTC
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

# Cybersecurity Posture Summary

## Section 1: Top 5 Critical Security Alerts (Triage Priority)

### 1. **CRITICAL: Repeated Systemd Service Failures on [Internal server]**
- **Alert IDs**: #1, #18, #27
- **Severity**: Level 5 | Rule ID: [Redacted]
- **Triage Priority**: **HIGH**
- **Rationale**: Multiple systemd service failures on the [Internal server] CI/CD server within a 1-minute window (04:47:24 - 04:48:06 UTC) indicates potential service instability, resource exhaustion, or targeted attack against build infrastructure. [Internal server] is a critical asset in the software supply chain.
- **Recommended Action**: Immediate investigation of [Internal server] service logs, resource utilization, and recent configuration changes. Verify integrity of [Internal server] processes and check for unauthorized modifications.

### 2. **CRITICAL: Web Server 400 Errors from Multiple External IPs to [Internal server]**
- **Alert IDs**: #3, #14, #16, #20, #26, #30
- **Severity**: Level 5 | Rule ID: [Redacted]
- **Source IPs**: [Public IP Addresses]
- **Triage Priority**: **HIGH**
- **Rationale**: Multiple 400 Bad Request errors from diverse external IPs targeting production [Internal server] system suggests reconnaissance activity, malformed attack payloads, or API abuse attempts. Pattern indicates potential automated scanning or exploitation attempts.
- **Recommended Action**: Analyze HTTP request patterns and payloads; correlate source IPs against threat intelligence feeds; review WAF/IDS logs; implement rate limiting if not present.

### 3. **CRITICAL: Suspicious Web Server 400 Error on [Internal server] from Cloud Infrastructure IP**
- **Alert ID**: #4
- **Severity**: Level 5 | Rule ID: [Redacted]
- **Source IP**: [Public IP] [Vendor Name]
- **Triage Priority**: **HIGH**
- **Rationale**: 400 error from a cloud hosting provider IP [Vendor Name] targeting [Internal server] CI/CD server is anomalous. Combined with concurrent systemd failures, this may indicate coordinated attack activity or compromised external automation attempting to interact with build infrastructure.
- **Recommended Action**: Block suspicious IP pending investigation; review [Internal server] authentication logs; verify no unauthorized webhooks or integrations; check for brute-force attempts.

### 4. **MEDIUM: Abnormal File System Activity Burst Across Multiple Critical Systems**
- **Alert IDs**: #2, #5, #6, #7-#13, #15, #17, #19, #22-#25, #28-#29
- **Severity**: Level 5 | Rule ID: [Redacted]
- **Affected Systems**: [Internal servers]
- **Triage Priority**: **MEDIUM**
- **Rationale**: Concentrated file creation activity across 6+ critical infrastructure systems within 2-minute window (04:47:23 - 04:48:05) is unusual. While file additions may be legitimate (logs, temp files, updates), the synchronous timing pattern across disparate systems warrants investigation for coordinated malicious activity or misconfigured automation.
- **Recommended Action**: Correlate file paths and types across systems; verify against scheduled maintenance windows; check for unauthorized scheduled tasks; review file integrity monitoring baselines.

### 5. **MEDIUM: Repeated Targeting Pattern Against [Internal server] from [Public IP] and [Public IP]**
- **Alert IDs**: #3, #14, #16, #26
- **Severity**: Level 5 | Rule ID: [Redacted]
- **Source IPs**: [Public IP] (3 occurrences), [Public IP] (2 occurrences)
- **Triage Priority**: **MEDIUM**
- **Rationale**: Persistent 400 errors from same source IPs within 12-minute window indicates sustained reconnaissance or automated attack tooling. These IPs are demonstrating persistence despite failed requests.
- **Recommended Action**: Geo-locate source IPs; check against business partner/customer IP ranges; implement temporary IP blocking; escalate to Tier 2 for deeper packet analysis if activity continues.

---

## Section 2: High-Level Cybersecurity Posture Executive Summary

### Overall Security Posture: **MODERATE RISK** ⚠️

The organization's cybersecurity posture reflects a **mature monitoring capability** with comprehensive visibility across [Internal numer of servers] monitored endpoints, but reveals **concerning activity patterns** requiring immediate attention to prevent potential security incidents.

### Key Metrics (4-Day Analysis Period: June 19-23, 2026)

**Alert Volume Analysis:**
- **Total Security Events**: [Redacted] recorded events
- **Critical/High Severity (Levels 10-12)**: [Redacted] alerts ([Redacted]% of total)
- **Medium Severity (Levels 7-9)**: [Redacted] alerts ([Redacted]%)
- **Low Severity (Levels 5-6)**: [Redacted] alerts ([Redacted]%)

**Threat Landscape Assessment:**
- **No Active Vulnerabilities**: Zero unpatched CVEs detected across monitored systems indicates strong patch management discipline
- **Service Availability Concerns**: Recurring systemd failures on critical CI/CD infrastructure ([Internal server]) suggest reliability issues that could impact business operations
- **External Threat Activity**: Multiple web application probing attempts from geographically diverse sources indicate the organization is under active reconnaissance
- **Insider Threat/Misconfiguration Risk**: Abnormal file system activity patterns across multiple systems may indicate unauthorized automation or configuration drift

### Strategic Recommendations

1. **Immediate**: Address [Internal server] service stability issues and investigate correlation with external 400 errors to rule out active exploitation
2. **Short-term**: Implement enhanced web application firewall rules and rate limiting for production [Internal server] instance
3. **Medium-term**: Conduct root cause analysis of the [Redacted] alerts to optimize detection rules and reduce analyst fatigue
4. **Ongoing**: Maintain current patch management excellence while enhancing behavioral anomaly detection capabilities

### Compliance Alignment (NIST Framework)
- **IDENTIFY (ID)**: ✅ Strong asset visibility with [Internal numer of servers] monitored agents
- **PROTECT (PR)**: ✅ Excellent vulnerability management (0 active CVEs)
- **DETECT (DE)**: ⚠️ Comprehensive logging but potential alert tuning needed
- **RESPOND (RS)**: ⚠️ Requires validation of incident response readiness for observed patterns
- **RECOVER (RC)**: ℹ️ Insufficient data to assess recovery capabilities

**Overall Assessment**: The organization demonstrates strong foundational security controls with effective vulnerability management and monitoring coverage. Primary risks center on **service reliability of critical infrastructure** and **web application security** requiring enhanced protection against external reconnaissance activities.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Report generated by Wazuh AI Agent
Powered by Claude via LiteLLM | NIST Vulnerability Guidance Applied
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Przydatne linki:

  • Wazuh SIEM/XDR – oficjalna strona produktu, tutaj znajdziesz specyfikację i pełną dokumentację systemu.
  • Program Ambasadorów Wazuh – dołącz do społeczności open-source i pomóż nam rozwijać system Wazuh.