Спрашчаем працу з Check Point API з дапамогай Python SDK

Спрашчаем працу з Check Point API з дапамогай Python SDKУся моц узаемадзеяння з API расчыняецца пры сумесным выкарыстанні з праграмным кодам, калі з'яўляюцца магчымасці дынамічна фармаваць API запыты і прылады для аналізу API адказаў. Аднак, малапрыкметным да гэтага часу застаецца Набор для распрацоўкі праграмнага забеспячэння Python (далей – Python SDK) для Check Point Management API, а дарма. Ён адчувальна спрашчае жыццё распрацоўшчыкам і аматарам аўтаматызацыі. Python набыў велізарную папулярнасць у апошні час і я вырашыў ухіліць прабел і зрабіць агляд асноўных магчымасцяў Check Point API Python Development Kit. Дадзены артыкул служыць выдатным дадаткам іншага артыкула на Хабры Check Point R80.10 API. Упраўленне праз CLI, скрыпты і не толькі. Мы ж разгледзім як напісаць скрыпты з выкарыстаннем Python SDK і спынімся падрабязней на новым функцыянале Management API у версіі 1.6 (падтрымліваецца пачынальна з R80.40). Для разумення артыкула спатрэбяцца базавыя веды па працы з API і Python.

Check Point актыўна развівае API і на дадзены момант на свет з'явіліся:

Python SDK на дадзены момант падтрымлівае ўзаемадзеянне толькі з Management API і Gaia API. Мы разгледзім найважнейшыя класы, метады і зменныя ў дадзеным модулі.

Спрашчаем працу з Check Point API з дапамогай Python SDK

Ўстаноўка модуля

модуль cpapi усталёўваецца хутка і проста з афіцыйнага рэпазітара Check Point на github з дапамогай зярнятка. Падрабязная інструкцыя па ўстаноўцы ёсць у README.md. Гэты модуль адаптаваны для працы з версіямі Python 2.7 і 3.7. У дадзеным артыкуле прыклады будуць прыведзены з выкарыстаннем Python 3.7. Аднак, Python SDK можна запускаць прама з сервера кіравання Check Point (Smart Management), але на іх падтрымліваецца толькі версія Python 2.7, таму ў апошняй частцы будзе прыведзены код для версіі 2.7. Адразу пасля ўстаноўкі модуля рэкамендую паглядзець на прыклады ў дырэкторыях examples_python2 и examples_python3.

Пачатак працы

Для таго каб у нас з'явілася магчымасць працаваць з кампанентамі модуля cpapi неабходна імпартаваць з модуля cpapi як мінімум два неабходныя класы:

APIClient и APIClientArgs

from cpapi import APIClient, APIClientArgs

Клас APIClientArgs адказвае за параметры падлучэння да API сервера, а клас APIClient адказвае за ўзаемадзеянне з API.

Вызначаем параметры падключэння

Каб вызначыць розныя параметры падлучэння да API, трэба стварыць асобнік класа APIClientArgs. У прынцыпе яго параметры наканаваны і пры запуску скрыпту на серверы кіравання іх можна не паказваць.

client_args = APIClientArgs()

Але пры запуску на іншым хасце трэба паказаць як мінімум IP адрас або імя хаста API сервера (ён жа сервер кіравання). У прыкладзе ніжэй мы вызначаем параметр падлучэння server і прысвойваем яму ў выглядзе радка IP адрас сервера кіравання.

client_args = APIClientArgs(server='192.168.47.241')

Давайце паглядзім на ўсе параметры і іх значэнні па змаўчанні, якія можна выкарыстоўваць пры падлучэнні да API серверу:

Аргументы метаду __init__ класа 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

Мяркую, што аргументы, якія можна выкарыстоўваць у асобніках класа APIClientArgs, інтуітыўна зразумелыя адміністратарам Check Point і ў дадатковых каментарах не маюць патрэбы.

Падключаемся праз APIClient і менеджэр кантэксту

Клас APIClient зручней за ўсё выкарыстоўваць праз менеджэр кантэксту. Усё, што трэба перадаць асобніку класа APIClient гэта параметры падлучэння, якія былі вызначаны ў мінулым кроку.

with APIClient(client_args) as client:

Мэнэджар кантэксту не стане выконваць аўтаматычна login выклік на API сервер, аднак ён выканае выклік logout пры выхадзе з яго. Калі па нейкіх прычынах logout па заканчэнні працы з API выклікамі не патрабуецца, трэба пачаць працу без выкарыстання мэнэджара кантэксту:

client = APIClient(clieng_args)

Праверка злучэння

Праверыць ці праходзіць злучэнне па зададзеных параметрах прасцей за ўсё з дапамогай метаду check_fingerprint. Калі праверка хэш-сумы sha1 для fingerprint сертыфіката API сервера не прайшла(метад вярнуў фальшывы), то звычайна гэта выклікана праблемамі са злучэннем і мы можам спыніць выкананне праграмы(ці даць карыстачу магчымасць выправіць дадзеныя для падлучэння):

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

Улічыце, што ў далейшым клас APIClient будзе правяраць пры кожным API выкліку (метады api_call и api_query, пра іх гаворка пойдзе крыху далей) sha1 fingerprint сертыфіката на API серверы. А вось калі пры праверцы sha1 fingerprint сертыфіката API сервера будзе выяўлена памылка (сертыфікат невядомы ці быў зменены), метад check_fingerprint прадаставіць магчымасць дадаць/змяніць інфармацыю аб ім на лакальнай машыне ў аўтаматычным рэжыме. Дадзеную праверку можна адключыць зусім (але такое можна рэкамендаваць толькі ў выпадку запуску скрыптоў на самім API серверы, пры падлучэнні да 127.0.0.1), выкарыстаючы аргумент APIClientArgs. unsafe_auto_accept (гл. падрабязней пра APIClientArgs раней у «Вызначаем параметры падлучэння»).

client_args = APIClientArgs(unsafe_auto_accept=True)

Login на API сервер

У APIClient ёсць цэлых 3 метаду лагіна на API сервер, і кожны з іх разумее значэнне SID(session-id), якое выкарыстоўвае аўтаматычна ў кожным наступным API выкліку ў загалоўку (імя ў загалоўку ў дадзенага параметру - X-chkp-sid), так што не трэба дадаткова апрацоўваць дадзены параметр.

Метад login

Варыянт з выкарыстаннем лагіна і пароля (у прыкладзе імя карыстальніка admin і пароль 1q2w3e перададзены як пазіцыйныя аргументы):

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

У метадзе login даступныя таксама дадатковыя апцыянальныя параметры, прыводжу іх імёны і значэнні па змаўчанні:

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

Метад login_with_api_key

Варыянт з выкарыстаннем api ключа(падтрымліваецца пачынальна з версіі мэнэджменту R80.40/Management API v1.6, "3TsbPJ8ZKjaJGvFyoFqHFA==" гэта значэнне ключа API для аднаго з карыстачоў на серверы кіравання з метадам аўтарызацыі API key):

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

У метадзе login_with_api_key даступныя такія ж апцыянальныя параметры як і ў метадзе увайсці.

Метад login_as_root

Варыянт login'а на лакальную машыну з API серверам:

     login = client.login_as_root()

Для дадзенага метаду даступныя ўсяго два апцыянальных параметра:

domain=None, payload=None

І нарэшце самі API выклікі

У нас ёсць два варыянты рабіць API выклікі праз метады api_call и api_query. Давайце разбяромся ў чым паміж імі розніца.

api_call

Дадзены метад дастасоўны для любых выклікаў. Нам трэба перадаць апошнюю частку для api выкліку і payload у целе запыту пры неабходнасці. Калі payload пусты, тое яго можна не перадаваць зусім:

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

Выснова для дадзенага запыту пад катом:

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

Выснова для дадзенага запыту пад катом:

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

Адразу абмоўлюся, што дадзены метад дастасоўны толькі для выклікаў, выснова якіх мяркуе offset(зрух). Такая выснова адбываецца ў тым выпадку, калі ў ім утрымліваецца ці можа ўтрымліваецца вялікая колькасць інфармацыі. Напрыклад, гэта можа быць запыт спісу ўсіх створаных аб'ектаў тыпу хост на сэрвэры кіравання. Для такіх запытаў API вяртае спіс з 50 аб'ектаў па змаўчанні (можна павялічыць ліміт да 500 аб'ектаў у адказе). І для таго, каб не тузаць інфармацыю па некалькі разоў, змяняючы параметр offset у API запыце, ёсць метад api_query, які дадзеную працу прарабляе аўтаматычна. Прыклады выклікаў, дзе патрэбен дадзены метад: 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. Па факце, у імя гэтых API выклікаў мы бачым словы ў множным ліку, так што гэтыя выклікі будзе прасцей апрацоўваць праз api_query

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

Выснова для дадзенага запыту пад катом:

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

Апрацоўка вынікаў API выклікаў

Пасля гэтага можна выкарыстоўваць зменныя і метады класа APIResponse(як унутры мэнэджара кантэксту, так і звонку). У класа APIResponse наканавана 4 метаду і 5 зменных, на самых важных мы спынімся падрабязней.

Спрашчаем працу з Check Point API з дапамогай Python SDK

поспех

Для пачатку было б нядрэнна ўпэўніцца ў тым, што API выклік прайшоў паспяхова і вярнуў вынік. Для гэтага ёсць метад поспех:

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

Вяртае True калі API выклік прайшоў паспяхова(Код адказу - 200) і False калі не паспяхова(любы іншы код адказу). Зручна выкарыстоўваць адразу пасля API выкліку, каб у залежнасці ад кода адказу вывесці розную інфармацыю.

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

statuscode

Вяртае код адказу пасля выканання API выкліку.

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

Магчымыя коды адказаў: 200,400,401,403,404,409,500,501.

set_success_status

Пры гэтым можа быць неабходнасць змяніць значэнне статуту success. Тэхнічна, туды можна змясціць што заўгодна, нават звычайны радок. Але рэальным прыкладам можа быць скід дадзенага параметра ў False пры вызначаных спадарожных умовах. Ніжэй звернеце ўвагу на прыклад, калі ёсць задачы, якія выконваюцца на серверы кіравання, але мы будзем лічыць гэты запыт няўдалым(выставім зменную success у фальшывы, нягледзячы на ​​тое, што API выклік быў паспяховы і вярнуў код 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()

Метад response дазваляе паглядзець слоўнік з кодам адказу (status_code) і з целам адказу (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']}}

gegevens

Дазваляе ўбачыць толькі цела адказу(body) без залішняй інфармацыі.

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

Дадзеная інфармацыя даступная, толькі калі пры апрацоўцы API запыту ўзнікла памылка (код адказу ня 200). Прыклад вываду

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

Карысныя прыклады

Ніжэй пералічаны прыклады, у якіх выкарыстоўваюцца API выклікі, якія былі дададзены ў версію Management API 1.6.

Для пачатку разгледзім працу выклікаў add-host и add-address-range. Дапушчальны, нам трэба стварыць у якасці аб'ектаў тыпу хост усе ip адрасы падсеткі 192.168.0.0/24, апошні актэт якіх роўны 5, а ўсе астатнія ip адрасы запісаць у якасці аб'ектаў тыпу дыяпазон адрасоў. Пры гэтым адрас падсеткі і шырокавяшчальны адрас выключыць.

Такім чынам, ніжэй прадстаўлены скрыпт у якім вырашаецца дадзеная задача і ствараюцца 50 аб'ектаў тыпу хост і 51 аб'ект тыпу дыяпазон адрасоў. На рашэнне задачы патрабуецца 101 API выклік (акрамя фінальнага выкліку publish). Таксама з дапамогай модуля timeit мы падлічваем час на выкананне скрыпту да моманту публікацыі змен.

Скрыпт з выкарыстаннем add-host і 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')

У маім лабараторным асяроддзі на выкананне дадзенага скрыпту сыходзіць ад 30 да 50 секунд у залежнасці ад нагрузкі на сервер кіравання.

А зараз паглядзім як вырашыць гэтую ж задачу з дапамогай API выкліку add-objects-batch, падтрымка якога дададзена ў версію API 1.6. Гэты выклік дазваляе за адзін API запыт стварыць адразу мноства аб'ектаў. Прычым гэта могуць быць аб'екты розных тыпаў (напрыклад хасты, падсеткі і дыяпазоны адрасоў). Такім чынам наша задача можа быць вырашана ў рамках аднаго API выкліку.

Скрыпт з выкарыстаннем 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')

А на выкананне дадзенага скрыпту ў маім лабараторным асяроддзі сыходзіць ад 3 да 7 секунд у залежнасці ад нагрузкі на сервер кіравання. Гэта значыць, у сярэднім, на 101 аб'екце API выклік тыпу batch, адпрацоўвае ў 10 разоў хутчэй. На большай колькасці аб'ектаў розніца будзе яшчэ больш уражлівай.

Цяпер давайце паглядзім як працаваць з set-objects-batch. З дапамогай дадзенага API выкліку мы можам масава змяніць любы параметр. Давайце наладзім першай палове адрасоў з мінулага прыкладу (да .124 хаста, прычым і дыяпазонам таксама) колер sienna, а другой палове адрасоў прызначым колер khaki.

Змяненне колеру аб'ектаў, створаных у папярэднім прыкладзе

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")

Выдаліць мноства аб'ектаў у адным API выкліку можна з дапамогай delete-objects-batch. А зараз паглядзім на прыклад кода, які выдаляе ўсе хасты, створаныя раней праз add-objects-batch.

Выдаленне аб'ектаў з дапамогай 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)

Усе функцыі, якія з'яўляюцца ў новых рэлізах ПЗ Check Point, адразу ж знаходзяць і API выклікі. Так, у R80.40 з'явіліся такія фічы як Revert to revision і Smart Task, і для іх адразу ж падрыхтавалі адпаведныя API выклікі. Больш за тое, увесь функцыянал пры пераходзе з Legacy кансоляў у рэжым Unified Policy таксама абрастае падтрымкай API. Напрыклад, доўгачаканым абнаўленнем у версіі ПЗ R80.40 стаў пераезд палітыкі HTTPS Inspection з Legacy рэжыму ў рэжым Unified Policy, і дадзены функцыянал адразу ж атрымаў API выклікі. Вось прыклад кода, які дадае на верхнюю пазіцыю HTTPS Inspection policy правіла, якое выключае з інспекцыі 3 катэгорыі (Здароўе, Фінансы, Дзяржаўныя паслугі), якія забаронена інспектаваць у адпаведнасці з заканадаўствам у шэрагу краін.

Дадаць правіла ў палітыку 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")

Запуск Python скрыптоў на сэрвэры кіравання Check Point

Усё ў тым жа README.md змяшчаецца інфармацыя як запускаць скрыпты на Python прама з сервера кіравання. Гэта можа быць зручна, калі ў вас няма магчымасці падлучыцца да API серверу з іншай машыны. Я запісаў шасціхвіліннае відэа ў якім разглядаю ўстаноўку модуля cpapi і асаблівасці запуску Python скрыптоў на сэрвэры кіравання. У якасці прыкладу запускаецца скрыпт, які аўтаматызуе канфігурацыю новага шлюза для такой задачы, як аўдыт сеткі Security CheckUp. З асаблівасцяў, з якімі прыйшлося сутыкнуцца: у версіі Python 2.7 яшчэ не з'явілася функцыя ўваход, таму для апрацоўкі інфармацыі, якую ўводзіць карыстальнік, выкарыстоўваецца функцыя raw_input. У астатнім, код такі ж як для запуску з іншых машын, толькі зручней выкарыстоўваць функцыю login_as_root, Каб не паказваць свае ж уласныя username, пароль і IP адрас сервера кіравання яшчэ раз.

Скрыпт для хуткай наладкі Security CheckUp

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()

Прыклад файла са слоўнікам пароляў additional_pass.conf
{
"passwords" : ["malware","malicious","infected","Infected"],
"phrases" : ["password","Password","Pass","pass","codigo","key","pwd","пароль","Пароль","Ключ","ключ","шифр","Шифр"] }

Заключэнне

Дадзены артыкул разглядае толькі асноўныя магчымасці працы Python SDK і модуля cpapi(як вы маглі здагадацца, гэта практычна сінонімы), і вывучыўшы код у дадзеным модулі вы адкрыеце сабе яшчэ больш магчымасцяў у працы з ім. Не выключана, што ў вас з'явіцца жаданне дапоўніць яго сваімі класамі, функцыямі, метадамі і зменнымі. Вы заўсёды можаце дзеліцца сваімі напрацоўкамі і праглядаць іншыя скрыпты для Check Point у раздзеле CodeHub у супольнасці CheckMates, якое аб'ядноўвае ў сабе і распрацоўшчыкаў прадуктаў і карыстальнікаў.

Прыемнага кодынгу і дзякуй, што дачыталі да канца!

Крыніца: habr.com

Дадаць каментар