Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Adminie… Czy znamy Twoje grzechy? ;-) Sprawdź!
Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Adminie… Czy znamy Twoje grzechy? ;-) Sprawdź!
Na sam początek wróćmy do naszej hipotetycznej sytuacji z >poprzedniego artykułu. Musiałeś napisać zapytanie pokazujące maksymalną ilość zalogowanych użytkowników w wybranym przedziale czasu na dashboardzie – wyłącznie dla systemów Ubuntu (ustaliliśmy, że informacja ta znajduje się w inwentarzu hosta).
Utworzyłeś więc panel z następującym zapytaniem:
|
To zapytanie pozwoliło Ci stworzyć elegancką tabelę w Grafanie:

Po pewnym czasie zacząłeś jednak dostawać maile z informacją, że „w tabelce jest za dużo danych”. Wziąłeś się więc do roboty i zacząłeś sprawdzać, co może być problemem.
Po wielu godzinach analizy struktury bazy danych udało Ci się znaleźć kilka przyczyn:
Po odkryciu tych dodatkowych założeń udało Ci się napisać następujące zapytanie:
|
Po uwzględnieniu wszystkich tych założeń udało się poprawnie wyświetlić dane (zauważ, że zniknął „wyłączony host”):

Udało się uratować sytuację – jesteś z siebie dumny, że wszystko zadziałało. Pozostaje jednak pewien niesmak, ponieważ osiągnięcie tego efektu wymagało kilku godzin analizowania struktury bazy danych, szczególnie w przypadku zadania, które na pierwszy rzut oka wydawało się dość trywialne.
Cała ta hipotetyczna sytuacja miała pokazać jedną z głównych wad bezpośrednich zapytań do bazy danych – konieczność znajomości jej struktury. Niestety, Zabbix nie udostępnia oficjalnych schematów bazy danych ani informacji o tym, jakie wartości mogą występować w poszczególnych kolumnach. Dodatkowo, przy bardziej skomplikowanych zapytaniach musimy dołączać kolejne tabele, co może skutkować wydłużonym czasem odpowiedzi i utrudnionym utrzymaniem takich zapytań w dłuższej perspektywie.
Dlatego w dzisiejszym artykule przyjrzymy się kolejnej metodzie wyciągania danych ze środowiska Zabbix – własnym zapytaniom do API. Miej na uwadze, że artykuł skupia się głównie na możliwościach pobierania danych do Grafany za pomocą API Zabbix. Nie będziemy tutaj szczegółowo omawiać samego API (solidną dawkę wiedzy powinieneś zacząć od >oficjalnej dokumentacji) ani struktury JSON – jako administrator Zabbixa zapewne nie raz miałeś już z nią do czynienia.
Zaczynamy!
Architektura środowiska nie uległa znaczącym zmianom – wciąż bazujemy na tej samej konfiguracji. Zmianie podlega jedynie sposób komunikacji ze środowiskiem Zabbix, ponieważ tym razem wracamy do komunikacji za pomocą HTTP lub HTTPS:

Dodatkowe założenia w tym przykładzie:
Ponieważ posiadamy już użytkownika grafana_api do pobierania danych, tym razem pokażemy drugą metodę autoryzacji do API – za pomocą tokenu API.
Aby go wygenerować, należy wejść w zakładkę Users – API tokens, a następnie kliknąć w prawym górnym rogu Create API token:

W nowym oknie konfiguracja wygląda następująco:
Całość konfiguracji wygląda następująco:

Jeżeli wszystko wypełniliśmy poprawnie, w nowym oknie wyświetli się podsumowanie i co najważniejsze – wygenerowany token do API. W tym momencie pamiętaj o jego zapisaniu (np. poprzez skopiowanie do schowka za pomocą przycisku Copy to clipboard) – gdy zamkniesz okienko przyciskiem Close, nie będzie już możliwości ponownego podejrzenia tokenu.

Posiadając token API dla użytkownika grafana_api, możemy przejść do konfiguracji pluginu odpowiedzialnego za wysyłanie zapytań API w środowisku Grafana.
Kiedy mamy już utworzonego użytkownika read-only oraz zapewnioną możliwość połączenia z serwerem Zabbix z poziomu serwera grafana-12-1, możemy przejść do konfiguracji oficjalnego pluginu służący do wysyłania zapytań API o nazwie Infinity.
W tym celu wybieramy z menu Connections – Data sources, a następnie Add new data source:

W wyszukiwarce źródeł danych wpisujemy infinity i klikamy w odpowiedni wynik:

Ciekawostką jest to, że w tym momencie moglibyśmy już kliknąć przycisk Save & test i faktycznie korzystać z tak skonfigurowanego źródła danych. Byłoby ono bardzo uniwersalne i moglibyśmy wykorzystywać je do komunikacji z różnymi endpointami API. Wymagałoby to jednak konfiguracji podstawowych parametrów połączenia (w szczególności tokenu autoryzacyjnego) w każdym panelu osobno.
Dlatego skonfigurujemy to źródło danych w taki sposób, aby służyło wyłącznie do wysyłania zapytań API do środowiska Zabbix, a token autoryzacyjny był konfigurowany tylko raz – na poziomie źródła danych. Takie podejście ogranicza ekspozycję tokenu autoryzacyjnego, który pozostaje widoczny tylko na poziomie źródła danych, a nie w konfiguracji paneli.
Na początku uzupełnij pole Name – wybierz taką wartość, które jednoznacznie wskazuje na to źródło danych np. zabbix-API-7-0, a następnie przejdź w zakładkę Authentication:

W zakładce Authentication dostępnych jest kilka metod uwierzytelniania. Ponieważ API Zabbixa korzysta z mechanizmu Bearer Token, wybieramy tę opcję i wklejamy wcześniej wygenerowany token.
Dodatkowo, w sekcji Allowed hosts wpiszmy pełny adres API Zabbix. Autor przypomina, że to URL, do którego łączymy się do Zabbixa, razem z endpointem API api_jsonrpc.php, w naszym przykładzie będzie to:
http://192.168.88.240/api_jsonrpc.php
Pamiętaj, aby po wpisaniu adresu kliknąć Add, tak aby pojawił się on na liście poniżej:

Przejdźmy teraz do sekcji URL, Headers & Params i omówmy poszczególne pola:
W naszym przykładzie zakładamy poprawną konfigurację zapytań, dlatego pozostawiamy tę sekcję pustą.

W sekcji Network konfigurujemy ustawienia sieciowe:

W sekcji Security możemy określić, z jakich adresów URL wolno korzystać w ramach tego źródła danych (Allowed hosts). Zauważ jednak, że pole to jest dokładnie tym samym co pole w sekcji Authentication – zawsze zawiera te same dane. Jeżeli uzupełniłeś je wcześniej, to zobaczysz tutaj adres URL API naszego środowiska Zabbix.
Dodatkowe ustawienie (Query security) dotyczy zachowania pluginu w sytuacji, gdy w zapytaniu skonfigurowanym w panelu pojawią się wrażliwe dane. Co to znaczy “wrażliwe dane”? Przez wrażliwe dane rozumiany jest nagłówek Authorization (co nie jest wprost opisane w dokumentacji, ale wynika z analizy kodu źródłowego pluginu na czas pisania artykułu).
Jeżeli ustawimy ten nagłówek z poziomu panelu (a nie z poziomu źródła danych, tak jak powyżej), to możliwe zachowania:


Ponieważ nagłówek autoryzacyjny został przez nas już skonfigurowany na poziomie źródła danych, ze względów bezpieczeństwa ustawiamy to pole na Deny.

Pozostałe opcje pozostawiamy puste, ale warto je krótko omówić:
Po wprowadzeniu wszystkich danych we wszystkich sekcjach klikamy Save & test.
Jeżeli konfiguracja została wykonana poprawnie, Grafana wyświetli komunikat potwierdzający udane połączenie:

Aby zweryfikować, czy połączenie działa poprawnie, spróbujemy pobrać dane o naszym użytkowniku za pomocą API Zabbix. W tym celu otwieramy sekcję Explore, którą znajdziesz w menu po lewej stronie:

Upewnij się, że jako źródło danych wybrane jest wcześniej skonfigurowane połączenie „zabbix-API-7-0”. Po jego wyborze pojawi się dość rozbudowany kreator zapytań:
Po wypełnieniu podstawowych parametrów zapytania, wypełnijmy teraz informacje o zapytaniu, klikając na przycisk Headers, Body, Request params:

Pojawi nam się dodatkowa sekcja, gdzie możemy ustawić tzw. “Payload”. Typ zapytania zostawiamy na Raw, natomiast Body Content Type zmieniamy na JSON. Zmiana ta spowoduje ustawienie nagłówka Content-Type na wartość application/json. Jeżeli nie wymusiłeś tego nagłówka podczas konfiguracji źródła danych, to inna wartość tego pola niż JSON spowoduje błąd:
error while performing the infinity query. unsuccessful HTTP response code status code : 412 Precondition Failed |
Autor jednak zachęca do ustawiania typu JSON, ponieważ wtedy zapytanie zostanie sformatowane, a plugin przeprowadzi wstępną walidację struktury JSON (podkreślając na czerwono sytuację, gdy zapytanie nie jest poprawnym JSON-em).
Przypomnijmy, że chcemy pobrać dane o użytkowniku. Wklejamy więc jako zawartość zapytania prosty JSON wyciągający wszystkie dane o użytkowniku (więcej informacji o metodzie user.get można przeczytać w >dokumentacji):
{ |
Zatrzymajmy się i przeanalizujmy nasze zapytanie API:
jsonrpc: "2.0" |
Określa wersję protokołu JSON-RPC, której używa Zabbix. W tym przypadku jest to wersja 2.0 – obowiązkowa dla wszystkich zapytań do API Zabbix.
method: "user.get" |
Nazwa metody, którą wywołujemy. user.get służy do pobierania informacji o użytkownikach w systemie Zabbix.
params: {} |
Parametry wywołania metody. W tym przykładzie pozostawiamy je puste, co oznacza, że API zwróci wszystkie dane o użytkownikach, do których ma dostęp użytkownik wykonujący zapytanie za pomocą tokenu.
W praktyce można tu dodać filtry, np. na konkretnego użytkownika, grupę użytkowników lub inne kryteria. Warto pamiętać, że jeśli zapytanie wykonuje zwykły użytkownik, API zwróci tylko dane dotyczące tego konkretnego użytkownika – nie zobaczy danych innych użytkowników.
id: 1 |
Identyfikator zapytania. Jest to wartość dowolna, ale musi być unikalna w danym zapytaniu, aby móc powiązać odpowiedź z konkretnym żądaniem. W odpowiedzi API zwróci to samo id, co pozwala upewnić się, że otrzymana odpowiedź odpowiada właśnie temu zapytaniu.
Wracając do konfiguracji naszego zapytania, nie dodajemy już żadnych dodatkowych nagłówków (a w szczególności nagłówka autoryzacyjnego – ponieważ został on dodany na poziomie źródła danych i będzie automatycznie dołączany do wszystkich zapytań) ani parametrów URL. Sekcja powinna wyglądać w następujący sposób:

W tym momencie, po kliknięciu Run Query powinien pojawić się mniej więcej taki wynik:

Dzięki temu wiemy, że połączenie działa. Wynik może wyglądać inaczej niż oczekiwaliśmy, ponieważ API zawsze zwraca trzy obiekty:
Nas interesuje tylko wynik, dlatego chcemy wyświetlić dane, które znajdują się w obiekcie result. Aby wyświetlić tylko te dane, przechodzimy do sekcji Parsing options & Result fields i w polu Rows/Root wpisujemy ścieżkę JSON:
$.result |
Jeżeli nie znasz się na ścieżkach JSON (ang. JSON Path), jako administrator Zabbix powinieneś znać podstawy – w razie wątpliwości warto zajrzeć do >dokumentacji Zabbix oraz użyć narzędzi do sprawdzania ścieżki JSON, np. >Jsonpathfinder. Po wprowadzeniu powyższej ścieżki JSON oraz ponwnym kliknięciu Run query, powinniśmy zobaczyć już tabelkę z wszystkimi danymi o naszym użytkowniku:

Reszta konfiguracji nie będzie potrzebna w dalszych przykładach, więc omówimy ją krótko:


Pokazaliśmy, jak skonfigurować zapytania do API Zabbix za pomocą pluginu Infinity i jak w prosty sposób przetestować połączenie w Grafanie. Dzięki temu wiesz już, że pobieranie danych przez API może być wygodne i przejrzyste – bez konieczności wchodzenia w struktury bazy danych.
W kolejnym artykule zajmiemy się parserem UQL, pokazując jego możliwości w pracy z danymi z API Zabbix w Grafanie. To właśnie tam pokażemy, jak skonfigurować zapytania i zapoznać się z jego składnią, aby sprawnie przetwarzać dane z API Zabbix.
Jednocześnie zapraszamy na nasze nowe duże szkolenie Zabbix Expert z ponad 50% rabatem! Zapisy tutaj: https://zabbix.sekurak.pl
Jeżeli po przeczytaniu tego artykułu poczułeś satysfakcję podobną do tej przy łyknięciu dobrej kawy, możesz wesprzeć autora równie >dobrą kawką!
~ Albert Przybylski, zawodowo: Architekt ds. Monitoringu w firmie Aplitt, prywatnie: pełnoprawny fanatyk Zabbixa zasilany kawą