Uproszczenie interfejsu API Check Point za pomocą zestawu SDK języka Python

Uproszczenie interfejsu API Check Point za pomocą zestawu SDK języka PythonPełną moc interakcji z API ujawnia się, gdy zostanie ona wykorzystana w połączeniu z kodem programu, gdy możliwe stanie się dynamiczne generowanie żądań API oraz narzędzia do analizy odpowiedzi API. Jednak nadal pozostaje to niezauważalne Zestaw deweloperski oprogramowania Pythona (zwany dalej SDK Pythona) dla Sprawdź API zarządzania punktami, ale na próżno. Znacząco ułatwia życie programistom i entuzjastom automatyzacji. Python zyskał ostatnio ogromną popularność, więc postanowiłem wypełnić lukę i przejrzeć główne funkcje. Zestaw deweloperski API Pythona firmy Check Point. Artykuł ten stanowi doskonałe uzupełnienie innego artykułu na temat Habré Sprawdź API punktu R80.10. Zarządzanie poprzez CLI, skrypty i nie tylko. Przyjrzymy się, jak pisać skrypty przy użyciu Python SDK i przyjrzymy się bliżej nowej funkcjonalności Management API w wersji 1.6 (obsługiwanej począwszy od R80.40). Aby zrozumieć artykuł, będziesz potrzebować podstawowej wiedzy na temat pracy z API i Pythonem.

Check Point aktywnie rozwija API i obecnie wydano następujące produkty:

Pakiet SDK języka Python obsługuje obecnie tylko interakcję z interfejsem API zarządzania i API Gai. W tym module przyjrzymy się najważniejszym klasom, metodom i zmiennym.

Uproszczenie interfejsu API Check Point za pomocą zestawu SDK języka Python

Instalacja modułu

Moduł cpapi instaluje się szybko i łatwo z oficjalne repozytorium Check Point na githubie przez pypeć. Szczegółowa instrukcja montażu dostępna jest w README.md. Moduł ten jest przystosowany do współpracy z Pythonem w wersji 2.7 i 3.7. W tym artykule zostaną podane przykłady użycia Pythona 3.7. Jednakże zestaw SDK języka Python można uruchomić bezpośrednio z serwera Check Point Management Server (Smart Management), ale obsługują one tylko język Python 2.7, więc ostatnia sekcja zawiera kod dla wersji 2.7. Zaraz po zainstalowaniu modułu polecam zapoznać się z przykładami w katalogach przykłady_python2 и przykłady_python3.

Pierwsze kroki

Abyśmy mogli pracować z komponentami modułu cpapi musimy dokonać importu z modułu cpapi co najmniej dwie wymagane klasy:

Klient API и APIClientArgs

from cpapi import APIClient, APIClientArgs

Klasa APIClientArgs odpowiada za parametry połączenia z serwerem API oraz klasę Klient API odpowiada za interakcję z API.

Określanie parametrów połączenia

Aby zdefiniować różne parametry połączenia z API, należy utworzyć instancję klasy APIClientArgs. W zasadzie jego parametry są predefiniowane i uruchamiając skrypt na serwerze sterującym nie trzeba ich podawać.

client_args = APIClientArgs()

Jednak w przypadku uruchamiania na hoście innej firmy należy określić przynajmniej adres IP lub nazwę hosta serwera API (znanego również jako serwer zarządzania). W poniższym przykładzie definiujemy parametr połączenia z serwerem i przypisujemy mu adres IP serwera zarządzającego w postaci ciągu znaków.

client_args = APIClientArgs(server='192.168.47.241')

Przyjrzyjmy się wszystkim parametrom i ich wartościom domyślnym, których można użyć podczas łączenia się z serwerem API:

Argumenty metody __init__ klasy APIClientArgs

class APIClientArgs:
    """
    This class provides arguments for APIClient configuration.
    All the arguments are configured with their default values.
    """

    # port is set to None by default, but it gets replaced with 443 if not specified
    # context possible values - web_api (default) or gaia_api
    def __init__(self, port=None, fingerprint=None, sid=None, server="127.0.0.1", http_debug_level=0,
                 api_calls=None, debug_file="", proxy_host=None, proxy_port=8080,
                 api_version=None, unsafe=False, unsafe_auto_accept=False, context="web_api"):
        self.port = port
        # management server fingerprint
        self.fingerprint = fingerprint
        # session-id.
        self.sid = sid
        # management server name or IP-address
        self.server = server
        # debug level
        self.http_debug_level = http_debug_level
        # an array with all the api calls (for debug purposes)
        self.api_calls = api_calls if api_calls else []
        # name of debug file. If left empty, debug data will not be saved to disk.
        self.debug_file = debug_file
        # HTTP proxy server address (without "http://")
        self.proxy_host = proxy_host
        # HTTP proxy port
        self.proxy_port = proxy_port
        # Management server's API version
        self.api_version = api_version
        # Indicates that the client should not check the server's certificate
        self.unsafe = unsafe
        # Indicates that the client should automatically accept and save the server's certificate
        self.unsafe_auto_accept = unsafe_auto_accept
        # The context of using the client - defaults to web_api
        self.context = context

Wierzę, że argumenty jakie można zastosować w instancjach klasy APIClientArgs są intuicyjne dla administratorów Check Pointa i nie wymagają dodatkowych komentarzy.

Łączenie poprzez APIClient i menedżera kontekstu

Klasa Klient API Najwygodniejszym sposobem korzystania z niego jest użycie menedżera kontekstu. Do instancji klasy APIClient należy jedynie przekazać parametry połączenia, które zostały zdefiniowane w poprzednim kroku.

with APIClient(client_args) as client:

Menedżer kontekstu nie wykona automatycznie wywołania logowania do serwera API, ale przy wyjściu z niego wykona wywołanie wylogowania. Jeśli z jakiegoś powodu wylogowanie nie jest wymagane po zakończeniu pracy z wywołaniami API, należy rozpocząć pracę bez korzystania z menedżera kontekstu:

client = APIClient(clieng_args)

Test połączenia

Najłatwiej sprawdzić, czy połączenie spełnia określone parametry, korzystając z metody sprawdź_odcisk palca. Jeżeli weryfikacja sumy skrótu sha1 dla odcisku palca certyfikatu API serwera nie powiedzie się (zwrócona zostanie metoda Fałszywy), to zazwyczaj jest to spowodowane problemami z połączeniem i możemy przerwać wykonywanie programu (lub dać użytkownikowi możliwość poprawienia danych połączenia):

    if client.check_fingerprint() is False:
        print("Could not get the server's fingerprint - Check connectivity with the server.")
        exit(1)

Proszę pamiętać, że w przyszłości klasa Klient API sprawdzi każde wywołanie API (methods api_call и api_query, porozmawiamy o nich nieco dalej) certyfikat odcisków palców sha1 na serwerze API. Jeśli jednak podczas sprawdzania odcisku palca sha1 certyfikatu serwera API zostanie wykryty błąd (certyfikat jest nieznany lub został zmieniony), metoda sprawdź_odcisk palca zapewni możliwość automatycznego dodawania/zmiany informacji na jego temat na komputerze lokalnym. Sprawdzanie to można całkowicie wyłączyć (ale można to zalecić tylko wtedy, gdy skrypty są uruchamiane na samym serwerze API, podczas łączenia się z 127.0.0.1), używając argumentu APIClientArgs - unsafe_auto_accept (więcej o APIClientArgs przeczytasz wcześniej w „Definiowanie parametrów połączenia”).

client_args = APIClientArgs(unsafe_auto_accept=True)

Zaloguj się do serwera API

У Klient API są aż 3 metody logowania do serwera API i każda z nich rozumie znaczenie sid(session-id), który jest automatycznie używany przy każdym kolejnym wywołaniu API w nagłówku (nazwa w nagłówku tego parametru to X-chkp-sid), więc nie ma potrzeby dalszego przetwarzania tego parametru.

metoda logowania

Opcja użycia loginu i hasła (w przykładzie nazwa użytkownika admin i hasło 1q2w3e przekazywane są jako argumenty pozycyjne):

     login = client.login('admin', '1q2w3e')  

W metodzie logowania dostępne są także dodatkowe opcjonalne parametry, oto ich nazwy i wartości domyślne:

continue_last_session=False, domain=None, read_only=False, payload=None

Metoda login_with_api_key

Opcja użycia klucza API (obsługiwana od wersji zarządzania R80.40/Management API v1.6, "3TsbPJ8ZKjaJGvFyoFqHFA==" jest to wartość klucza API dla jednego z użytkowników na serwerze zarządzania z metodą autoryzacji klucza API):

     login = client.login_with_api_key('3TsbPJ8ZKjaJGvFyoFqHFA==') 

W metodzie login_with_api_key dostępne są te same opcjonalne parametry, co w metodzie Zaloguj Się.

metoda login_as_root

Możliwość zalogowania się na maszynę lokalną z serwerem API:

     login = client.login_as_root()

Dla tej metody dostępne są tylko dwa opcjonalne parametry:

domain=None, payload=None

I wreszcie API wywołuje samo siebie

Mamy dwie możliwości wykonywania wywołań API poprzez metody api_call и api_query. Zastanówmy się, jaka jest między nimi różnica.

api_call

Ta metoda ma zastosowanie do wszystkich połączeń. Jeśli to konieczne, musimy przekazać ostatnią część wywołania interfejsu API i ładunku w treści żądania. Jeśli ładunek jest pusty, w ogóle nie można go przesłać:

api_versions = client.api_call('show-api-versions') 

Dane wyjściowe dla tego żądania poniżej cięcia:

In [23]: api_versions                                                           
Out[23]: 
APIResponse({
    "data": {
        "current-version": "1.6",
        "supported-versions": [
            "1",
            "1.1",
            "1.2",
            "1.3",
            "1.4",
            "1.5",
            "1.6"
        ]
    },
    "res_obj": {
        "data": {
            "current-version": "1.6",
            "supported-versions": [
                "1",
                "1.1",
                "1.2",
                "1.3",
                "1.4",
                "1.5",
                "1.6"
            ]
        },
        "status_code": 200
    },
    "status_code": 200,
    "success": true
})
show_host = client.api_call('show-host', {'name' : 'h_8.8.8.8'})

Dane wyjściowe dla tego żądania poniżej cięcia:

In [25]: show_host                                                              
Out[25]: 
APIResponse({
    "data": {
        "color": "black",
        "comments": "",
        "domain": {
            "domain-type": "domain",
            "name": "SMC User",
            "uid": "41e821a0-3720-11e3-aa6e-0800200c9fde"
        },
        "groups": [],
        "icon": "Objects/host",
        "interfaces": [],
        "ipv4-address": "8.8.8.8",
        "meta-info": {
            "creation-time": {
                "iso-8601": "2020-05-01T21:49+0300",
                "posix": 1588358973517
            },
            "creator": "admin",
            "last-modifier": "admin",
            "last-modify-time": {
                "iso-8601": "2020-05-01T21:49+0300",
                "posix": 1588358973517
            },
            "lock": "unlocked",
            "validation-state": "ok"
        },
        "name": "h_8.8.8.8",
        "nat-settings": {
            "auto-rule": false
        },
        "read-only": false,
        "tags": [],
        "type": "host",
        "uid": "c210af07-1939-49d3-a351-953a9c471d9e"
    },
    "res_obj": {
        "data": {
            "color": "black",
            "comments": "",
            "domain": {
                "domain-type": "domain",
                "name": "SMC User",
                "uid": "41e821a0-3720-11e3-aa6e-0800200c9fde"
            },
            "groups": [],
            "icon": "Objects/host",
            "interfaces": [],
            "ipv4-address": "8.8.8.8",
            "meta-info": {
                "creation-time": {
                    "iso-8601": "2020-05-01T21:49+0300",
                    "posix": 1588358973517
                },
                "creator": "admin",
                "last-modifier": "admin",
                "last-modify-time": {
                    "iso-8601": "2020-05-01T21:49+0300",
                    "posix": 1588358973517
                },
                "lock": "unlocked",
                "validation-state": "ok"
            },
            "name": "h_8.8.8.8",
            "nat-settings": {
                "auto-rule": false
            },
            "read-only": false,
            "tags": [],
            "type": "host",
            "uid": "c210af07-1939-49d3-a351-953a9c471d9e"
        },
        "status_code": 200
    },
    "status_code": 200,
    "success": true
})

api_query

Od razu zastrzegam, że metoda ta ma zastosowanie tylko w przypadku wywołań, których wyjście obejmuje offset. Wnioskowanie takie ma miejsce wtedy, gdy zawiera lub może zawierać dużą ilość informacji. Może to być na przykład żądanie listy wszystkich obiektów hostów utworzonych na serwerze zarządzania. Dla takich żądań API domyślnie zwraca listę 50 obiektów (w odpowiedzi możesz zwiększyć limit do 500 obiektów). Aby nie pobierać informacji kilka razy, zmieniając parametr offset w żądaniu API, istnieje metoda api_query, która działa to automatycznie. Przykłady wywołań, w których potrzebna jest ta metoda: show-sessions, show-hosts, show-networks, show-wildcards, show-groups, show-adres-ranges, show-simple-gateways, show-simple-clusters, show-access-roles, show-trusted-clients, pakiety pokazowe. W rzeczywistości w nazwach tych wywołań API widzimy słowa w liczbie mnogiej, więc obsługa tych wywołań będzie łatwiejsza api_query

show_hosts = client.api_query('show-hosts') 

Dane wyjściowe dla tego żądania poniżej cięcia:

In [21]: show_hosts                                                             
Out[21]: 
APIResponse({
    "data": [
        {
            "domain": {
                "domain-type": "domain",
                "name": "SMC User",
                "uid": "41e821a0-3720-11e3-aa6e-0800200c9fde"
            },
            "ipv4-address": "192.168.47.1",
            "name": "h_192.168.47.1",
            "type": "host",
            "uid": "5d7d7086-d70b-4995-971a-0583b15a2bfc"
        },
        {
            "domain": {
                "domain-type": "domain",
                "name": "SMC User",
                "uid": "41e821a0-3720-11e3-aa6e-0800200c9fde"
            },
            "ipv4-address": "8.8.8.8",
            "name": "h_8.8.8.8",
            "type": "host",
            "uid": "c210af07-1939-49d3-a351-953a9c471d9e"
        }
    ],
    "res_obj": {
        "data": {
            "from": 1,
            "objects": [
                {
                    "domain": {
                        "domain-type": "domain",
                        "name": "SMC User",
                        "uid": "41e821a0-3720-11e3-aa6e-0800200c9fde"
                    },
                    "ipv4-address": "192.168.47.1",
                    "name": "h_192.168.47.1",
                    "type": "host",
                    "uid": "5d7d7086-d70b-4995-971a-0583b15a2bfc"
                },
                {
                    "domain": {
                        "domain-type": "domain",
                        "name": "SMC User",
                        "uid": "41e821a0-3720-11e3-aa6e-0800200c9fde"
                    },
                    "ipv4-address": "8.8.8.8",
                    "name": "h_8.8.8.8",
                    "type": "host",
                    "uid": "c210af07-1939-49d3-a351-953a9c471d9e"
                }
            ],
            "to": 2,
            "total": 2
        },
        "status_code": 200
    },
    "status_code": 200,
    "success": true
})

Przetwarzanie wyników wywołań API

Następnie możesz użyć zmiennych i metod klasy Odpowiedź API(zarówno wewnątrz menedżera kontekstu, jak i na zewnątrz). Na zajęciach Odpowiedź API Predefiniowane są 4 metody i 5 zmiennych, najważniejsze omówimy bardziej szczegółowo.

Uproszczenie interfejsu API Check Point za pomocą zestawu SDK języka Python

sukces

Na początek warto upewnić się, że wywołanie API zakończyło się sukcesem i zwróciło wynik. Jest na to metoda sukces:

In [49]: api_versions.success                                                   
Out[49]: True

Zwraca True, jeśli wywołanie API powiodło się (kod odpowiedzi - 200) i False, jeśli nie powiodło się (dowolny inny kod odpowiedzi). Wygodne jest użycie natychmiast po wywołaniu API, aby wyświetlić różne informacje w zależności od kodu odpowiedzi.

if api_ver.success: 
    print(api_versions.data) 
else: 
    print(api_versions.err_message) 

Kod statusu

Zwraca kod odpowiedzi po wykonaniu wywołania API.

In [62]: api_versions.status_code                                               
Out[62]: 400

Możliwe kody odpowiedzi: 200,400,401,403,404,409,500,501.

set_success_status

W takim przypadku może zaistnieć konieczność zmiany wartości statusu sukcesu. Technicznie rzecz biorąc, możesz tam umieścić wszystko, nawet zwykły ciąg znaków. Ale prawdziwym przykładem byłoby zresetowanie tego parametru na False pod pewnymi warunkami towarzyszącymi. Poniżej zwróć uwagę na przykład, gdy na serwerze zarządzającym działają zadania, ale to żądanie uznamy za nieudane (zmienną sukcesu ustawimy na Fałszywy, pomimo tego, że wywołanie API zakończyło się sukcesem i zwróciło kod 200).

for task in task_result.data["tasks"]:
    if task["status"] == "failed" or task["status"] == "partially succeeded":
        task_result.set_success_status(False)
        break

odpowiedź()

Metoda odpowiedzi umożliwia przeglądanie słownika z kodem odpowiedzi (kod_statusu) i treścią odpowiedzi (body).

In [94]: api_versions.response()                                                
Out[94]: 
{'status_code': 200,
 'data': {'current-version': '1.6',
  'supported-versions': ['1', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6']}}

dane

Pozwala zobaczyć tylko treść odpowiedzi (treść) bez zbędnych informacji.

In [93]: api_versions.data                                                      
Out[93]: 
{'current-version': '1.6',
 'supported-versions': ['1', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6']}

Komunikat o błędzie

Informacje te są dostępne tylko wtedy, gdy podczas przetwarzania żądania API wystąpił błąd (kod odpowiedzi nie 200). Przykładowe wyjście

In [107]: api_versions.error_message                                            
Out[107]: 'code: generic_err_invalid_parameter_namenmessage: Unrecognized parameter [1]n'

Przydatne przykłady

Poniżej znajdują się przykłady użycia wywołań API dodanych w interfejsie Management API 1.6.

Najpierw przyjrzyjmy się, jak działają połączenia dodaj hosta и dodaj zakres adresów. Załóżmy, że musimy utworzyć wszystkie adresy IP podsieci 192.168.0.0/24, której ostatni oktet to 5, jako obiekty typu Host, a wszystkie pozostałe adresy IP zapisać jako obiekty typu zakresu adresów. W takim przypadku wyklucz adres podsieci i adres rozgłoszeniowy.

Zatem poniżej znajduje się skrypt rozwiązujący ten problem i tworzący 50 obiektów typu Host i 51 obiektów typu zakresu adresów. Aby rozwiązać problem, potrzeba 101 wywołań API (nie licząc ostatniego wywołania publikacji). Ponadto za pomocą modułu timeit obliczamy czas potrzebny na wykonanie skryptu do momentu opublikowania zmian.

Skrypt używający funkcji add-host i add-address-range

import timeit
from cpapi import APIClient, APIClientArgs

start = timeit.default_timer()

first_ip = 1
last_ip = 4

client_args = APIClientArgs(server="192.168.47.240")

with APIClient(client_args) as client: 
     login = client.login_with_api_key('3TsbPJ8ZKjaJGvFyoFqHFA==')
     for ip in range(5,255,5):
         add_host = client.api_call("add-host", {"name" : f"h_192.168.0.{ip}", "ip-address": f'192.168.0.{ip}'})
     while last_ip < 255:
         add_range = client.api_call("add-address-range", {"name": f"r_192.168.0.{first_ip}-{last_ip}", "ip-address-first": f"192.168.0.{first_ip}", "ip-address-last": f"192.168.0.{last_ip}"})
         first_ip+=5
         last_ip+=5
     stop = timeit.default_timer() 
     publish = client.api_call("publish")
     
print(f'Time to execute batch request: {stop - start} seconds')

W moim środowisku laboratoryjnym wykonanie tego skryptu zajmuje od 30 do 50 sekund, w zależności od obciążenia serwera zarządzania.

Zobaczmy teraz, jak rozwiązać ten sam problem za pomocą wywołania API dodaj-obiekty-partia, którego obsługa została dodana w wersji API 1.6. To wywołanie umożliwia utworzenie wielu obiektów jednocześnie w jednym żądaniu API. Co więcej, mogą to być obiekty różnego typu (na przykład hosty, podsieci i zakresy adresów). Dzięki temu nasze zadanie można rozwiązać w ramach jednego wywołania API.

Skrypt używający add-objects-batch

import timeit
from cpapi import APIClient, APIClientArgs

start = timeit.default_timer()

client_args = APIClientArgs(server="192.168.47.240")

objects_list_ip = []
objects_list_range = []

for ip in range(5,255,5):
    data = {"name": f'h_192.168.0.{ip}', "ip-address": f'192.168.0.{ip}'}
    objects_list_ip.append(data)
    
first_ip = 1
last_ip = 4


while last_ip < 255:
    data = {"name": f"r_192.168.0.{first_ip}-{last_ip}", "ip-address-first": f"192.168.0.{first_ip}", "ip-address-last": f"192.168.0.{last_ip}"}
    objects_list_range.append(data)
    first_ip+=5
    last_ip+=5

data_for_batch = {
  "objects" : [ {
    "type" : "host",
    "list" : objects_list_ip
}, {
    "type" : "address-range",
    "list" : objects_list_range
  }]
}


with APIClient(client_args) as client: 
     login = client.login_with_api_key('3TsbPJ8ZKjaJGvFyoFqHFA==')
     add_objects_batch = client.api_call("add-objects-batch", data_for_batch)
     stop = timeit.default_timer() 
     publish = client.api_call("publish")
     
print(f'Time to execute batch request: {stop - start} seconds')

Uruchomienie tego skryptu w moim środowisku laboratoryjnym zajmuje od 3 do 7 sekund, w zależności od obciążenia serwera zarządzania. Oznacza to, że średnio w 101 obiektach API wywołanie typu wsadowego działa 10 razy szybciej. Na większej liczbie obiektów różnica będzie jeszcze bardziej imponująca.

Zobaczmy teraz, jak z nim pracować zestaw obiektów-partia. Za pomocą tego wywołania API możemy zbiorczo zmienić dowolny parametr. Ustawmy pierwszą połowę adresów z poprzedniego przykładu (do .124 hostów i zakresów także) na kolor sienna, a drugiej połowie adresów przypiszmy kolor khaki.

Zmiana koloru obiektów utworzonych w poprzednim przykładzie

from cpapi import APIClient, APIClientArgs

client_args = APIClientArgs(server="192.168.47.240")

objects_list_ip_first = []
objects_list_range_first = []
objects_list_ip_second = []
objects_list_range_second = []

for ip in range(5,125,5):
    data = {"name": f'h_192.168.0.{ip}', "color": "sienna"}
    objects_list_ip_first.append(data)
    
for ip in range(125,255,5):
    data = {"name": f'h_192.168.0.{ip}', "color": "khaki"}
    objects_list_ip_second.append(data)
    
first_ip = 1
last_ip = 4
while last_ip < 125:
    data = {"name": f"r_192.168.0.{first_ip}-{last_ip}", "color": "sienna"}
    objects_list_range_first.append(data)
    first_ip+=5
    last_ip+=5
    
while last_ip < 255:
    data = {"name": f"r_192.168.0.{first_ip}-{last_ip}", "color": "khaki"}
    objects_list_range_second.append(data)
    first_ip+=5
    last_ip+=5

data_for_batch_first  = {
  "objects" : [ {
    "type" : "host",
    "list" : objects_list_ip_first
}, {
    "type" : "address-range",
    "list" : objects_list_range_first
  }]
}

data_for_batch_second  = {
  "objects" : [ {
    "type" : "host",
    "list" : objects_list_ip_second
}, {
    "type" : "address-range",
    "list" : objects_list_range_second
  }]
}

with APIClient(client_args) as client: 
     login = client.login_with_api_key('3TsbPJ8ZKjaJGvFyoFqHFA==') 
     set_objects_batch_first = client.api_call("set-objects-batch", data_for_batch_first)
     set_objects_batch_second = client.api_call("set-objects-batch", data_for_batch_second)
     publish = client.api_call("publish")

Możesz usunąć wiele obiektów w jednym wywołaniu API, używając usuń-obiekty-partia. Przyjrzyjmy się teraz przykładowi kodu, który usuwa wszystkie hosty utworzone wcześniej przez dodaj-obiekty-partia.

Usuwanie obiektów za pomocą partii usuwania obiektów

from cpapi import APIClient, APIClientArgs

client_args = APIClientArgs(server="192.168.47.240")

objects_list_ip = []
objects_list_range = []

for ip in range(5,255,5):
    data = {"name": f'h_192.168.0.{ip}'}
    objects_list_ip.append(data)

first_ip = 1
last_ip = 4
while last_ip < 255:
    data = {"name": f"r_192.168.0.{first_ip}-{last_ip}"}
    objects_list_range.append(data)
    first_ip+=5
    last_ip+=5

data_for_batch = {
  "objects" : [ {
    "type" : "host",
    "list" : objects_list_ip
}, {
    "type" : "address-range",
    "list" : objects_list_range
  }]
}

with APIClient(client_args) as client: 
     login = client.login_with_api_key('3TsbPJ8ZKjaJGvFyoFqHFA==')
     delete_objects_batch = client.api_call("delete-objects-batch", data_for_batch)
     publish = client.api_call("publish")

print(delete_objects_batch.data)

Wszystkie funkcje pojawiające się w nowych wersjach oprogramowania Check Point natychmiastowo uzyskują wywołania API. Tak więc w wersji R80.40 pojawiły się takie „funkcje”, jak Przywróć wersję i Inteligentne zadanie, i od razu przygotowano dla nich odpowiednie wywołania API. Co więcej, cała funkcjonalność po przejściu ze starszych konsol do trybu ujednoliconych zasad również zyskuje obsługę interfejsu API. Na przykład długo oczekiwaną aktualizacją w wersji oprogramowania R80.40 było przeniesienie polityki HTTPS Inspection z trybu Legacy do trybu Unified Policy i ta funkcjonalność natychmiast otrzymała wywołania API. Oto przykład kodu, który dodaje na najwyższą pozycję zasad kontroli HTTPS regułę, która wyklucza z kontroli 3 kategorie (Zdrowie, Finanse, Usługi rządowe), które są zakazane zgodnie z prawem w wielu krajach.

Dodaj regułę do zasad inspekcji HTTPS

from cpapi import APIClient, APIClientArgs

client_args = APIClientArgs(server="192.168.47.240")

data = {
  "layer" : "Default Layer",
  "position" : "top",
  "name" : "Legal Requirements",
  "action": "bypass",
  "site-category": ["Health", "Government / Military", "Financial Services"]
}

with APIClient(client_args) as client: 
     login = client.login_with_api_key('3TsbPJ8ZKjaJGvFyoFqHFA==')
     add_https_rule = client.api_call("add-https-rule", data)
     publish = client.api_call("publish")

Uruchamianie skryptów Python na serwerze zarządzającym Check Point

Wszystko jest takie samo README.md zawiera informacje o sposobie uruchamiania skryptów Pythona bezpośrednio z serwera sterującego. Może to być wygodne, gdy nie można połączyć się z serwerem API z innego komputera. Nagrałem sześciominutowy film, w którym przyglądam się instalacji modułu cpapi oraz możliwości uruchamiania skryptów Pythona na serwerze sterującym. Przykładowo uruchamiany jest skrypt, który automatyzuje konfigurację nowej bramy na potrzeby zadania takiego jak audyt sieci Kontrola bezpieczeństwa. Wśród funkcji, z którymi miałem do czynienia: funkcja nie pojawiła się jeszcze w Pythonie 2.7 wkład, więc do przetworzenia informacji, które wprowadza użytkownik, wykorzystywana jest funkcja surowe_wejście. W przeciwnym razie kod jest taki sam, jak przy uruchamianiu z innych maszyn, tylko wygodniej jest korzystać z tej funkcji login_jako_root, aby nie podawać ponownie własnej nazwy użytkownika, hasła i adresu IP serwera zarządzającego.

Skrypt do szybkiej konfiguracji sprawdzania zabezpieczeń

from __future__ import print_function
import getpass
import sys, os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from cpapi import APIClient, APIClientArgs

def main():
    with APIClient() as client:
       # if client.check_fingerprint() is False:
       #     print("Could not get the server's fingerprint - Check connectivity with the server.")
       #     exit(1)
        login_res = client.login_as_root()

        if login_res.success is False:
            print("Login failed:n{}".format(login_res.error_message))
            exit(1)

        gw_name = raw_input("Enter the gateway name:")
        gw_ip = raw_input("Enter the gateway IP address:")
        if sys.stdin.isatty():
            sic = getpass.getpass("Enter one-time password for the gateway(SIC): ")
        else:
            print("Attention! Your password will be shown on the screen!")
            sic = raw_input("Enter one-time password for the gateway(SIC): ")
        version = raw_input("Enter the gateway version(like RXX.YY):")
        add_gw = client.api_call("add-simple-gateway", {'name' : gw_name, 'ipv4-address' : gw_ip, 'one-time-password' : sic, 'version': version.capitalize(), 'application-control' : 'true', 'url-filtering' : 'true', 'ips' : 'true', 'anti-bot' : 'true', 'anti-virus' : 'true', 'threat-emulation' : 'true'})
        if add_gw.success and add_gw.data['sic-state'] != "communicating":
            print("Secure connection with the gateway hasn't established!")
            exit(1)
        elif add_gw.success:
            print("The gateway was added successfully.")
            gw_uid = add_gw.data['uid']
            gw_name = add_gw.data['name']
        else:
            print("Failed to add the gateway - {}".format(add_gw.error_message))
            exit(1)

        change_policy = client.api_call("set-access-layer", {"name" : "Network", "applications-and-url-filtering": "true", "content-awareness": "true"})
        if change_policy.success:
            print("The policy has been changed successfully")
        else:
            print("Failed to change the policy- {}".format(change_policy.error_message))
        change_rule = client.api_call("set-access-rule", {"name" : "Cleanup rule", "layer" : "Network", "action": "Accept", "track": {"type": "Detailed Log", "accounting": "true"}})
        if change_rule.success:
            print("The cleanup rule has been changed successfully")
        else:
            print("Failed to change the cleanup rule- {}".format(change_rule.error_message))

        # publish the result
        publish_res = client.api_call("publish", {})
        if publish_res.success:
            print("The changes were published successfully.")
        else:
                print("Failed to publish the changes - {}".format(install_tp_policy.error_message))

        install_access_policy = client.api_call("install-policy", {"policy-package" : "Standard", "access" : 'true',  "threat-prevention" : 'false', "targets" : gw_uid})
        if install_access_policy.success:
            print("The access policy has been installed")
        else:
                print("Failed to install access policy - {}".format(install_tp_policy.error_message))

        install_tp_policy = client.api_call("install-policy", {"policy-package" : "Standard", "access" : 'false',  "threat-prevention" : 'true', "targets" : gw_uid})
        if install_tp_policy.success:
            print("The threat prevention policy has been installed")
        else:
            print("Failed to install threat prevention policy - {}".format(install_tp_policy.error_message))
        
        # add passwords and passphrases to dictionary
        with open('additional_pass.conf') as f:
            line_num = 0
            for line in f:
                line_num += 1
                add_password_dictionary = client.api_call("run-script", {"script-name" : "Add passwords and passphrases", "script" : "printf "{}" >> $FWDIR/conf/additional_pass.conf".format(line), "targets" : gw_name})
                if add_password_dictionary.success:
                    print("The password dictionary line {} was added successfully".format(line_num))
                else:
                    print("Failed to add the dictionary - {}".format(add_password_dictionary.error_message))

main()

Przykładowy plik ze słownikiem haseł extra_pass.conf
{
"passwords" : ["malware","malicious","infected","Infected"],
"phrases" : ["password","Password","Pass","pass","codigo","key","pwd","пароль","Пароль","Ключ","ключ","шифр","Шифр"] }

wniosek

W artykule rozpatrzono jedynie podstawowe możliwości pracy SDK Pythona i moduł cpapi(jak można się domyślić, są to właściwie synonimy), a studiując kod w tym module odkryjesz jeszcze więcej możliwości pracy z nim. Możliwe, że będziesz chciał uzupełnić go o własne klasy, funkcje, metody i zmienne. Zawsze możesz podzielić się swoją pracą i zobaczyć inne skrypty dla Check Point w dziale Centrum kodu w społeczeństwie SprawdźMate, która skupia zarówno twórców produktów, jak i użytkowników.

Miłego kodowania i dzięki za przeczytanie do końca!

Źródło: www.habr.com

Dodaj komentarz