Ułatwiamy pracę z Check Point API za pomocą Python SDK

Ułatwiamy pracę z Check Point API za pomocą Python SDKCała moc interakcji z API ujawnia się przy wspólnym użyciu z kodem programistycznym, gdy pojawiają się możliwości dynamicznego formułowania zapytań API oraz narzędzi do analizy odpowiedzi API. Jednak wciąż pozostaje mało zauważone Python Software Development Kit (dalej — Python SDK) dla Check Point Management API, co jest niesłuszne. Znacząco ułatwia życie programistom i entuzjastom automatyzacji. Python zyskał ogromną popularność w ostatnim czasie i postanowiłem wypełnić lukę, przedstawiając przegląd podstawowych możliwości Check Point API Python Development Kit. Niniejszy artykuł stanowi doskonałe uzupełnienie innego artykułu na Habra Check Point R80.10 API. Zarządzanie przez CLI, skrypty i nie tylko. Rozważymy, jak napisać skrypty przy użyciu Python SDK i skupimy się bardziej na nowym funkcjonalności Management API w wersji 1.6 (obsługiwanej od R80.40). Do zrozumienia artykułu potrzebna będzie podstawowa wiedza na temat pracy z API i Pythonem.

Check Point aktywnie rozwija API i obecnie pojawiły się:

Python SDK obecnie obsługuje interakcję tylko z Management API i Gaia API. Rozważymy najważniejsze klasy, metody i zmienne w tym module.

Ułatwiamy pracę z Check Point API za pomocą Python SDK

Instalacja modułu

Moduł cpapi instalacja jest szybka i prosta z oficjalnego repozytorium Check Point na githubie z pomocą pip. Szczegółowa instrukcja instalacji znajduje się w README.md. Moduł ten jest dostosowany do pracy z wersjami Pythona 2.7 i 3.7. W artykule przykłady będą podane z użyciem Pythona 3.7. Jednak Python SDK można uruchamiać bezpośrednio z serwera zarządzania Check Point (Smart Management), ale na nich obsługiwana jest tylko wersja Python 2.7, dlatego w ostatniej sekcji zostanie podany kod dla wersji 2.7. Tuż po zainstalowaniu modułu zalecam zapoznanie się z przykładami w katalogach examples_python2 i examples_python3.

Rozpoczęcie pracy

Aby umożliwić nam pracę z komponentami modułu cpapi, należy zaimportować je z modułu cpapi co najmniej dwie wymagane klasy:

APIClient i APIClientArgs

from cpapi import APIClient, APIClientArgs

Klasa APIClientArgs odpowiada za parametry połączenia z API serwerem, a klasa APIClient odpowiada za interakcję z API.

Definiujemy parametry połączenia

Aby określić różne parametry połączenia z API, należy utworzyć instancję klasy APIClientArgs. W zasadzie jej parametry są zdefiniowane wcześniej, więc podczas uruchamiania skryptu na serwerze zarządzania nie trzeba ich podawać.

client_args = APIClientArgs()

Jednak podczas uruchamiania na zewnętrznym hoście należy podać co najmniej adres IP lub nazwę hosta serwera API (to ten sam serwer zarządzania). W poniższym przykładzie definiujemy parametr połączenia server i przypisujemy mu w postaci ciągu adres IP serwera zarządzania.

client_args = APIClientArgs(server='192.168.47.241')

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

Argumenty metody __init__ klasy APIClientArgs

class APIClientArgs:
    """
    Ta klasa dostarcza argumenty do konfiguracji APIClient.
    Wszystkie argumenty są skonfigurowane z ich wartościami domyślnymi.
    """

    # port jest ustawiony na None domyślnie, ale zostaje zastąpiony przez 443, jeśli nie jest określony
    # wartości kontekstu - web_api (domyślnie) lub 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
        # odcisk palca serwera zarządzania
        self.fingerprint = fingerprint
        # identyfikator sesji.
        self.sid = sid
        # nazwa serwera zarządzania lub adres IP
        self.server = server
        # poziom debugowania
        self.http_debug_level = http_debug_level
        # tablica ze wszystkimi wywołaniami API (do celów debugowania)
        self.api_calls = api_calls if api_calls else []
        # nazwa pliku debugowania. Jeśli pozostawiony pusty, dane debugowania nie będą zapisywane na dysku.
        self.debug_file = debug_file
        # adres serwera proxy HTTP (bez "http://")
        self.proxy_host = proxy_host
        # port serwera proxy HTTP
        self.proxy_port = proxy_port
        # wersja API serwera zarządzania
        self.api_version = api_version
        # Wskazuje, że klient nie powinien sprawdzać certyfikatu serwera
        self.unsafe = unsafe
        # Wskazuje, że klient powinien automatycznie zaakceptować i zapisać certyfikat serwera
        self.unsafe_auto_accept = unsafe_auto_accept
        # Kontekst użycia klienta - domyślnie web_api
        self.context = context

Uważam, że argumenty, które można wykorzystać w instancjach klasy APIClientArgs, są intuicyjnie zrozumiałe dla administratorów Check Point i nie wymagają dodatkowych komentarzy.

Łączymy się za pomocą APIClient i menedżera kontekstu

Klasa APIClient najwygodniej jest korzystać z menedżera kontekstu. Wszystko, co należy przekazać instancji klasy APIClient, to parametry połączenia, które zostały określone w poprzednim kroku.

with APIClient(client_args) as client:

Menadżer kontekstu nie będzie automatycznie wywoływał login na serwerze API, jednak wykona wywołanie logout po jego zakończeniu. Jeśli z jakichś przyczyn wywołanie logout po pracy z wywołaniami API nie jest wymagane, należy rozpocząć pracę bez użycia menadżera kontekstu:

client = APIClient(client_args)

Sprawdzenie połączenia

Najprościej jest sprawdzić, czy połączenie odbywa się zgodnie z zdefiniowanymi parametrami, używając metody check_fingerprint. Jeśli sprawdzenie sumy kontrolnej sha1 dla certyfikatu fingerprint serwera API nie zakończy się pomyślnie (metoda zwróciła Fałsz), zazwyczaj jest to spowodowane problemami z połączeniem i możemy zatrzymać działanie programu (lub dać użytkownikowi możliwość poprawienia danych do połączenia):

    if client.check_fingerprint() is False:
        print("Nie można uzyskać fingerprintu serwera - Sprawdź łączność z serwerem.")
        exit(1)

Pamiętaj, że w przyszłości klasa APIClient będzie sprawdzać przy każdym wywołaniu API (metody api_call i api_query, o których będzie mowa później) sha1 fingerprint certyfikatu na serwerze API. A jeśli podczas sprawdzania sha1 fingerprint certyfikatu na serwerze API wystąpi błąd (certyfikat jest nieznany lub został zmieniony), metoda check_fingerprint umożliwi dodanie/zmienienie informacji o nim na lokalnej maszynie w trybie automatycznym. Tę kontrolę można całkowicie wyłączyć (jednak zaleca się to tylko w przypadku uruchamiania skryptów na samym serwerze API, podczas łączenia z 127.0.0.1), używając argumentu APIClientArgs — unsafe_auto_accept (szczegóły na temat APIClientArgs wcześniej w „Określenie parametrów połączenia”).

client_args = APIClientArgs(unsafe_auto_accept=True)

Logowanie na serwerze API

U APIClient są trzy metody logowania na serwerze API, a każda z nich przechowuje wartość sid(session-id), która jest automatycznie używana w każdym kolejnym wywołaniu API w nagłówku (nazwa tego parametru w nagłówku to X-chkp-sid), więc nie ma potrzeby dodatkowego przetwarzania tego parametru.

Metoda login

Opcja z użyciem loginu i hasła (w przykładzie nazwa użytkownika admin i hasło 1q2w3e przekazane jako argumenty pozycyjne):

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

W metodzie login dostępne są również dodatkowe opcjonalne parametry, podaję ich nazwy i wartości domyślne:

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

Metoda login_with_api_key

Opcja z użyciem klucza API (wspierana od wersji zarządzania R80.40/Management API v1.6, „3TsbPJ8ZKjaJGvFyoFqHFA==” to jest 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ą takie same opcjonalne parametry jak w metodzie login.

Metoda login_as_root

Opcja logowania na lokalną maszynę z serwerem API:

     login = client.login_as_root()

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

domain=None, payload=None

I w końcu same wywołania API

Mamy dwie opcje wykonywania wywołań API przez metody api_call i api_query. Zobaczmy, na czym polega różnica.

api_call

Ta metoda jest stosowalna dla każdego wywołania. Musimy przekazać ostatnią część do wywołania API i payload w ciele żądania w razie potrzeby. Jeśli payload jest pusty, nie trzeba go w ogóle przekazywać:

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

Wynik dla tego zapytania poniżej:

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'})

Wynik dla tego zapytania poniżej:

W [25]: show_host                                                              
Out[25]: 
APIResponse({
    "data": {
        "color": "czarny",
        "comments": "",
        "domain": {
            "domain-type": "domena",
            "name": "Użytkownik SMC",
            "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": "odblokowane",
            "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": "czarny",
            "comments": "",
            "domain": {
                "domain-type": "domena",
                "name": "Użytkownik SMC",
                "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": "odblokowane",
                "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 zaznaczam, że ta metoda dotyczy wywołań, których rezultaty zakładają offset (przesunięcie). Taki rezultat następuje, gdy zawiera lub może zawierać dużą ilość informacji. Na przykład może to być zapytanie o listę wszystkich utworzonych obiektów typu host na serwerze zarządzania. Dla takich zapytań API zwraca domyślnie listę 50 obiektów (limit można zwiększyć do 500 obiektów w odpowiedzi). I aby nie pobierać informacji kilka razy, zmieniając parametr offset w zapytaniu API, istnieje metoda api_query, która wykonuje tę pracę automatycznie. Przykłady wywołań, w których potrzeba tej metody: show-sessions, show-hosts, show-networks, show-wildcards, show-groups, show-address-ranges, show-simple-gateways, show-simple-clusters, show-access-roles, show-trusted-clients, show-packages. W rzeczywistości w nazwach tych wywołań API widzimy słowa w liczbie mnogiej, więc te wywołania będzie łatwiej przetwarzać przez api_query

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

Wynik dla tego zapytania poniżej:

W [21]: pokaz_hosty                                                             
Out[21]: 
APIResponse({
    "data": [
        {
            "domain": {
                "domain-type": "domain",
                "name": "Użytkownik SMC",
                "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": "Użytkownik SMC",
                "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": "Użytkownik SMC",
                        "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": "Użytkownik SMC",
                        "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

Po tym można używać zmiennych i metod klasy APIResponse(zarówno wewnątrz menedżera kontekstu, jak i na zewnątrz). Klasa APIResponse ma zdefiniowane 4 metody i 5 zmiennych, na najważniejszych zatrzymamy się dokładniej.

Ułatwiamy pracę z Check Point API za pomocą Python SDK

success

Na początek byłoby dobrze upewnić się, że wywołanie API zakończyło się sukcesem i zwróciło wynik. W tym celu dostępna jest metoda success:

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

Zwraca True, jeśli wywołanie API zakończyło się sukcesem (Kod odpowiedzi — 200) i False, jeśli nie udało się (jakikolwiek inny kod odpowiedzi). Łatwo używać od razu po wywołaniu API, aby w zależności od kodu odpowiedzi wyświetlić różne informacje.

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

statuscode

Zwraca kod odpowiedzi po wykonaniu wywołania API.

W [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 być konieczne zmienienie wartości statusu success. Technicznie można tam umieścić cokolwiek, nawet zwykły ciąg. Przykładem może być zresetowanie tego parametru do False w określonych warunkach towarzyszących. Zobacz poniżej przykład, gdy są zadania wykonywane na serwerze zarządzania, ale uznamy ten żądanie za nieudane (ustawimy zmienną success na Fałsz, mimo że wywołanie API było udane 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

response()

Metoda response pozwala zobaczyć słownik z kodem odpowiedzi (status_code) oraz z ciałem 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']}}

data

Pozwala zobaczyć tylko ciało odpowiedzi (body) 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']}

error_message

Ta informacja jest dostępna tylko wtedy, gdy podczas przetwarzania żądania API wystąpił błąd (kod odpowiedzi nie 200). Przykład wyniku

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

Przykłady użycia

Poniżej przedstawiono przykłady, w których używane są wywołania API, które zostały dodane w wersji Management API 1.6.

Na początek przyjrzyjmy się pracy wywołań add-host i add-address-range. Załóżmy, że musimy utworzyć jako obiekty typu host wszystkie adresy IP w podsieci 192.168.0.0/24, których ostatni oktet wynosi 5, a wszystkie pozostałe adresy IP zapisać jako obiekty typu zakres adresów. Przy tym należy wykluczyć adres podsieci i adres rozgłoszeniowy.

Zatem poniżej przedstawiony jest skrypt, który rozwiązuje to zadanie i tworzy 50 obiektów typu host oraz 51 obiekt typu zakres adresów. Na rozwiązanie zadania potrzeba 101 wywołań API (nie licząc końcowego wywołania publish). Ponadto za pomocą modułu timeit obliczamy czas realizacji skryptu do momentu opublikowania zmian.

Skrypt z użyciem 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ądzającego.

A teraz przyjrzyjmy się, jak rozwiązać ten sam problem za pomocą wywołania API. add-objects-batch, którego wsparcie dodano w wersji API 1.6. To wywołanie pozwala na utworzenie wielu obiektów w jednym zapytaniu API. Mogą to być obiekty różnych typów (np. hosty, podsieci i zakresy adresów). Dzięki temu nasza kwestia może być rozwiązana w ramach jednego wywołania API.

Skrypt z użyciem 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')

A wykonanie tego skryptu w moim środowisku laboratoryjnym zajmuje od 3 do 7 sekund, w zależności od obciążenia serwera zarządzającego. Oznacza to, że w średnim przypadku wywołanie API typu batch dla 101 obiektów działa 10 razy szybciej. Przy większej liczbie obiektów różnica będzie jeszcze bardziej imponująca.

Teraz przyjrzyjmy się, jak pracować z set-objects-batch. Dzięki temu wywołaniu API możemy masowo zmienić dowolny parametr. Skonfigurujmy dla pierwszej połowy adresów z poprzedniego przykładu (do .124 hosta, a także zakresów) kolor sienna, a drugiej połowie adresów przypiszmy kolor khaki.

Zmiana koloru obiektów stworzonych 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")

Usuwanie wielu obiektów w jednym wywołaniu API można osiągnąć za pomocą delete-objects-batch. A teraz spójrzmy na przykład kodu, który usuwa wszystkie hosty utworzone wcześniej przez add-objects-batch.

Usuwanie obiektów za pomocą delete-objects-batch

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, które pojawiają się w nowych wydaniach oprogramowania Check Point, natychmiast zyskują również wywołania API. W wersji R80.40 pojawiły się takie funkcje jak Revert to revision i Smart Task, dla których od razu przygotowano odpowiednie wywołania API. Co więcej, cała funkcjonalność przy przejściu z konsol Legacy do trybu Unified Policy również otrzymuje wsparcie API. Na przykład, długo oczekiwaną aktualizacją w wersji R80.40 był transfer polityki HTTPS Inspection z trybu Legacy do trybu Unified Policy, a ta funkcjonalność natychmiast uzyskała wywołania API. Oto przykład kodu, który dodaje na górną pozycję polityki HTTPS Inspection regułę, która wyłącza z inspekcji 3 kategorie (Zdrowie, Finanse, Usługi Publiczne), które są zabronione do inspekcji zgodnie z prawodawstwem w wielu krajach.

Dodaj regułę do polityki HTTPS Inspection

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ądzania Check Point

Wszystko to samo README.md zawiera informacje, jak uruchamiać skrypty w Pythonie bezpośrednio z serwera zarządzania. Może to być wygodne, gdy nie masz możliwości połączenia z serwerem API z innej maszyny. Nagrałem sześcio-minutowe wideo, w którym omawiam instalację modułu cpapi i cechy uruchamiania skryptów Python na serwerze zarządzania. Jako przykład uruchamiany jest skrypt, który automatyzuje konfigurację nowego bramy dla zadania, takiego jak audyt sieci Security CheckUp. Z ciekawostek, z którymi przyszło się zmierzyć: w wersji Pythona 2.7 jeszcze nie pojawiła się funkcja input, dlatego do przetwarzania informacji, które wprowadza użytkownik, używana jest funkcja raw_input. W pozostałym zakresie, kod jest taki sam jak dla uruchamiania z innych maszyn, tylko wygodniej jest używać funkcji login_as_root, aby nie podawać ponownie własnych nazwy użytkownika, hasła i adresu IP serwera zarządzania.

Odtwarzaj wideo

Skrypt do szybkiej konfiguracji Security CheckUp

z __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("Nie można uzyskać odcisku palca serwera - Sprawdź łączność z serwerem.")
       #     exit(1)
        login_res = client.login_as_root()

        if login_res.success is False:
            print("Logowanie nie powiodło się:n{}".format(login_res.error_message))
            exit(1)

        gw_name = raw_input("Wprowadź nazwę bramy:")
        gw_ip = raw_input("Wprowadź adres IP bramy:")
        if sys.stdin.isatty():
            sic = getpass.getpass("Wprowadź jednorazowe hasło dla bramy (SIC): ")
        else:
            print("Uwaga! Twoje hasło będzie wyświetlane na ekranie!")
            sic = raw_input("Wprowadź jednorazowe hasło dla bramy (SIC): ")
        version = raw_input("Wprowadź wersję bramy (np. 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("Bezpieczne połączenie z bramą nie zostało nawiązane!")
            exit(1)
        elif add_gw.success:
            print("Bramę dodano pomyślnie.")
            gw_uid = add_gw.data['uid']
            gw_name = add_gw.data['name']
        else:
            print("Nie udało się dodać bramy - {}".format(add_gw.error_message))
            exit(1)

        change_policy = client.api_call("set-access-layer", {"name" : "Sieć", "applications-and-url-filtering": "true", "content-awareness": "true"})
        if change_policy.success:
            print("Polityka została pomyślnie zmieniona")
        else:
            print("Nie udało się zmienić polityki- {}".format(change_policy.error_message))
        change_rule = client.api_call("set-access-rule", {"name" : "Reguła czyszczenia", "layer" : "Sieć", "action": "Akceptuj", "track": {"type": "Szczegółowy log", "accounting": "true"}})
        if change_rule.success:
            print("Reguła czyszczenia została pomyślnie zmieniona")
        else:
            print("Nie udało się zmienić reguły czyszczenia- {}".format(change_rule.error_message))

        # publikuj wynik
        publish_res = client.api_call("publish", {})
        if publish_res.success:
            print("Zmiany zostały pomyślnie opublikowane.")
        else:
                print("Nie udało się opublikować zmian - {}".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("Polityka dostępu została zainstalowana")
        else:
                print("Nie udało się zainstalować polityki dostępu - {}".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("Polityka zapobiegania zagrożeniom została zainstalowana")
        else:
            print("Nie udało się zainstalować polityki zapobiegania zagrożeniom - {}".format(install_tp_policy.error_message))
        
        # dodaj hasła i frazy zabezpieczające do słownika
        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" : "Dodaj hasła i frazy zabezpieczające", "script" : "printf "{}" >> $FWDIR/conf/additional_pass.conf".format(line), "targets" : gw_name})
                if add_password_dictionary.success:
                    print("Linia słownika haseł {} została pomyślnie dodana".format(line_num))
                else:
                    print("Nie udało się dodać słownika - {}".format(add_password_dictionary.error_message))

main()

Przykład pliku z słownikiem haseł additional_pass.conf
{
"passwords" : ["złośliwe oprogramowanie","malicious","zainfekowane","Zainfekowane"],
"phrases" : ["hasło","Hasło","Pass","pass","kod","klucz","pwd","пароль","Пароль","Ключ","ключ","шифр","Шифр"]
}

Podsumowanie

Ten artykuł omawia tylko podstawowe możliwości pracy Python SDK i modułu cpapi(jak mogłeś się domyślić, to w zasadzie synonimy), a analizując kod w tym module odkryjesz jeszcze więcej możliwości pracy z nim. Nie ma wątpliwości, że możesz zapragnąć wzbogacić go o własne klasy, funkcje, metody i zmienne. Zawsze możesz dzielić się swoimi osiągnięciami i przeglądać inne skrypty dla Check Point w sekcji CodeHub w społeczności CheckMates, która łączy zarówno twórców produktów, jak i użytkowników.

Miłej pracy z kodem i dziękujemy, że dotarłeś do końca!

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster