Simplificamos el trabajo con la API de Check Point utilizando Python SDK

Simplificamos el trabajo con la API de Check Point utilizando Python SDKToda la potencia de la interacción con la API se revela al utilizarla junto con código, cuando surgen oportunidades para formar dinámicamente solicitudes API y herramientas para analizar respuestas API. Sin embargo, todavía se pasa por alto Kit de Desarrollo de Software de Python (en adelante, Python SDK) para API de Gestión de Check Point, y es un error. Facilita notablemente la vida a los desarrolladores y a los entusiastas de la automatización. Python ha ganado una enorme popularidad recientemente, y decidí cerrar la brecha y hacer una revisión de las principales funciones Kit de Desarrollo de Python para API de Check Point. Este artículo es un excelente complemento para otro artículo en Habr Check Point R80.10 API. Administración a través de CLI, scripts y más. Vamos a examinar cómo escribir scripts utilizando Python SDK y nos enfocaremos más detalladamente en la nueva funcionalidad de Management API en la versión 1.6 (compatible desde R80.40). Para entender el artículo se requiere un conocimiento básico sobre el trabajo con API y Python.

Check Point está desarrollando activamente la API y hasta ahora ha lanzado:

El SDK de Python actualmente solo soporta la interacción con Management API y API de Gaia. Vamos a revisar las clases, métodos y variables más importantes en este módulo.

Simplificamos el trabajo con la API de Check Point utilizando Python SDK

Instalación del módulo

Módulo cpapi se instala rápida y fácilmente desde el repositorio oficial de Check Point en github usando pip. Hay instrucciones detalladas de instalación en README.md. Este módulo está adaptado para trabajar con versiones de Python 2.7 y 3.7. En este artículo, los ejemplos se darán utilizando Python 3.7. Sin embargo, Python SDK se puede ejecutar directamente desde el servidor de gestión de Check Point (Smart Management), pero solo es compatible con la versión Python 2.7, por lo que en la última sección se dará el código para la versión 2.7. Justo después de instalar el módulo, recomiendo revisar los ejemplos en los directorios examples_python2 y examples_python3.

Inicio

Para que podamos trabajar con los componentes del módulo cpapi, es necesario importar del módulo cpapi al menos dos clases necesarias:

APIClient y APIClientArgs

from cpapi import APIClient, APIClientArgs

Clase APIClientArgs se encarga de los parámetros de conexión al servidor API, mientras que la clase APIClient se encarga de la interacción con el API.

Definimos los parámetros de conexión

Para definir los diferentes parámetros de conexión al API, hay que crear una instancia de la clase APIClientArgs. En principio, sus parámetros están predefinidos y al ejecutar el script en el servidor de gestión, no es necesario especificarlos.

client_args = APIClientArgs()

Pero al ejecutarlo en un host externo, es necesario especificar al menos la dirección IP o el nombre del host del servidor API (también el servidor de gestión). En el siguiente ejemplo, definimos el parámetro de conexión server y le asignamos como cadena la dirección IP del servidor de gestión.

client_args = APIClientArgs(server='192.168.47.241')

Veamos todos los parámetros y sus valores por defecto que se pueden usar al conectarse al servidor API:

Argumentos del método __init__ de la clase APIClientArgs

class APIClientArgs:
    """
    Esta clase proporciona argumentos para la configuración de APIClient.
    Todos los argumentos están configurados con sus valores por defecto.
    """

    # el puerto se establece en None de forma predeterminada, pero se reemplaza por 443 si no se especifica
    # valores posibles del contexto - web_api (predeterminado) o 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
        # huella digital del servidor de gestión
        self.fingerprint = fingerprint
        # id de sesión.
        self.sid = sid
        # nombre del servidor de gestión o dirección IP
        self.server = server
        # nivel de depuración
        self.http_debug_level = http_debug_level
        # un array con todas las llamadas a la API (para fines de depuración)
        self.api_calls = api_calls if api_calls else []
        # nombre del archivo de depuración. Si se deja vacío, los datos de depuración no se guardarán en disco.
        self.debug_file = debug_file
        # dirección del servidor proxy HTTP (sin "http://")
        self.proxy_host = proxy_host
        # puerto del proxy HTTP
        self.proxy_port = proxy_port
        # versión de API del servidor de gestión
        self.api_version = api_version
        # Indica que el cliente no debe verificar el certificado del servidor
        self.unsafe = unsafe
        # Indica que el cliente debe aceptar y guardar automáticamente el certificado del servidor
        self.unsafe_auto_accept = unsafe_auto_accept
        # El contexto del uso del cliente - predeterminado a web_api
        self.context = context

Supongo que los argumentos que se pueden usar en las instancias de la clase APIClientArgs son intuitivamente comprensibles para los administradores de Check Point y no requieren comentarios adicionales.

Conectamos a través de APIClient y el administrador de contexto

Clase APIClient es más conveniente utilizarlo a través del gestor de contexto. Todo lo que necesita pasar a la instancia de la clase APIClient son los parámetros de conexión que se definieron en el paso anterior.

with APIClient(client_args) as client:

El gestor de contexto no ejecutará automáticamente la llamada a login en el servidor API, pero sí ejecutará la llamada a logout al salir de él. Si por alguna razón no se requiere la llamada a logout al final de trabajar con las llamadas a la API, se debe comenzar a trabajar sin usar el gestor de contexto:

client = APIClient(client_args)

Verificación de conexión

Es más fácil verificar si la conexión pasa con los parámetros dados utilizando el método check_fingerprint. Si la verificación del hash sha1 para el fingerprint del certificado del servidor API no pasó (el método devolvió False), normalmente esto se debe a problemas de conexión y podemos detener la ejecución del programa (o dar la opción al usuario para corregir los datos de conexión):

    if client.check_fingerprint() is False:
        print("No se pudo obtener el fingerprint del servidor - Verifique la conectividad con el servidor.")
        exit(1)

Tenga en cuenta que en el futuro, la clase APIClient verificará en cada llamada a la API (los métodos api_call y api_query, de los que hablaremos un poco más adelante) el fingerprint sha1 del certificado en el servidor API. Pero si durante la verificación del fingerprint sha1 del certificado del servidor API se detecta un error (el certificado es desconocido o ha sido modificado), el método check_fingerprint ofrecerá la posibilidad de agregar/cambiar la información sobre él en la máquina local de manera automática. Esta verificación se puede desactivar por completo (pero esto solo se recomienda en caso de ejecutar scripts en el mismo servidor API, al conectarse a 127.0.0.1), utilizando el argumento APIClientArgs — unsafe_auto_accept (ver más sobre APIClientArgs anteriormente en “Definiendo los parámetros de conexión”).

client_args = APIClientArgs(unsafe_auto_accept=True)

Inicio de sesión en el servidor API

En APIClient hay en total 3 métodos de inicio de sesión en el servidor API, y cada uno de ellos memoriza el valor sid(session-id), que se utiliza automáticamente en cada llamada a la API posterior en el encabezado (el nombre en el encabezado de este parámetro es X-chkp-sid), por lo que no es necesario procesar adicionalmente este parámetro.

Método de inicio de sesión

Opción con el uso de nombre de usuario y contraseña (en el ejemplo, el nombre de usuario admin y la contraseña 1q2w3e se pasaron como argumentos posicionales):

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

En el método de inicio de sesión también están disponibles parámetros opcionales adicionales, aquí están sus nombres y valores por defecto:

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

Método login_with_api_key

Opción que utiliza la clave API (compatible a partir de la versión de gestión R80.40/Management API v1.6, «3TsbPJ8ZKjaJGvFyoFqHFA==» este es el valor de la clave API para uno de los usuarios en el servidor de gestión con el método de autorización de clave API):

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

En el método login_with_api_key se encuentran los mismos parámetros opcionales que en el método login.

Método login_as_root

Opción de login en la máquina local con el servidor API:

     login = client.login_as_root()

Para este método hay disponibles solo dos parámetros opcionales:

domain=None, payload=None

Y finalmente, las llamadas a la API

Tenemos dos opciones para realizar llamadas a la API a través de los métodos api_call y api_query. Vamos a analizar cuál es la diferencia entre ellas.

api_call

Este método es aplicable para cualquier llamada. Necesitamos pasar la última parte para la llamada a la API y el payload en el cuerpo de la solicitud si es necesario. Si el payload está vacío, no es necesario pasarlo en absoluto:

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

La salida para esta solicitud está debajo:

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

La salida para esta solicitud está debajo:

En [25]: show_host                                                              
Out[25]: 
APIResponse({
    "data": {
        "color": "negro",
        "comments": "",
        "domain": {
            "domain-type": "dominio",
            "name": "Usuario 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": "desbloqueado",
            "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": "negro",
            "comments": "",
            "domain": {
                "domain-type": "dominio",
                "name": "Usuario 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": "desbloqueado",
                "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

Cabe mencionar que este método solo es aplicable para llamadas cuyos resultados implican un offset. Tal salida ocurre cuando contiene o puede contener una gran cantidad de información. Por ejemplo, esto puede ser una solicitud de la lista de todos los objetos creados del tipo host en el servidor de gestión. Para tales solicitudes, la API devuelve por defecto una lista de 50 objetos (se puede aumentar el límite a 500 objetos en la respuesta). Y para evitar obtener la información varias veces cambiando el parámetro offset en la solicitud de API, existe el método api_query, que realiza esta tarea automáticamente. Ejemplos de llamadas donde se necesita este método: 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. De hecho, en el nombre de estas llamadas API vemos palabras en plural, por lo que será más fácil procesar estas llamadas a través de api_query

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

La salida para esta solicitud está debajo:

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

Procesando los resultados de las llamadas a la API

Después de esto, se pueden usar las variables y métodos de la clase APIResponse(tanto dentro del administrador de contexto como fuera). En la clase APIResponse están predefinidos 4 métodos y 5 variables, nos detendremos más en los más importantes.

Simplificamos el trabajo con la API de Check Point utilizando Python SDK

success

Para empezar, sería bueno asegurarse de que la llamada a la API fue exitosa y devolvió un resultado. Para esto, existe el método success:

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

Devuelve True si la llamada a la API fue exitosa (Código de respuesta — 200) y False si no fue exitosa (cualquier otro código de respuesta). Es conveniente usarlo justo después de la llamada a la API para mostrar información diferente según el código de respuesta.

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

statuscode

Devuelve el código de respuesta después de la ejecución de la llamada a la API.

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

Códigos de respuesta posibles: 200,400,401,403,404,409,500,501.

set_success_status

Sin embargo, puede ser necesario cambiar el valor del estado de éxito. Técnicamente, se puede colocar cualquier cosa allí, incluso una cadena normal. Pero un ejemplo real podría ser restablecer este parámetro a False bajo ciertas condiciones. A continuación, preste atención a un ejemplo en el que hay tareas que se realizan en el servidor de administración, pero consideraremos esta solicitud fallida (estableceremos la variable success en False, a pesar de que la llamada a la API fue exitosa y devolvió el código 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()

El método response permite ver un diccionario con el código de respuesta (status_code) y con el cuerpo de la respuesta (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

Permite ver solo el cuerpo de la respuesta (body) sin información adicional.

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

Esta información está disponible solo cuando ocurre un error al procesar la solicitud de la API (código de respuesta no 200). Ejemplo de salida

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

Ejemplos útiles

A continuación se enumeran ejemplos en los que se utilizan llamadas a la API que fueron agregadas en la versión 1.6 de la API de administración.

Para comenzar, examinemos cómo funcionan las llamadas add-host y add-address-range. Supongamos que necesitamos crear como objetos de tipo host todas las direcciones IP de la subred 192.168.0.0/24, cuyo último octeto es 5, y que todas las demás direcciones IP se registren como objetos de tipo rango de direcciones. Además, debe excluirse la dirección de la subred y la dirección de difusión.

Así que a continuación se presenta un script que aborda esta tarea y crea 50 objetos de tipo host y 51 objetos de tipo rango de direcciones. Para resolver la tarea, se necesitan 101 llamadas a la API (sin contar la llamada final de publicar). También, utilizando el módulo timeit, contabilizamos el tiempo de ejecución del script hasta el momento de publicar los cambios.

Script utilizando add-host y 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'Tiempo para ejecutar la solicitud por lotes: {stop - start} segundos')

En mi entorno de laboratorio, la ejecución de este script toma de 30 a 50 segundos, dependiendo de la carga en el servidor de gestión.

Ahora veamos cómo resolver la misma tarea utilizando una llamada a la API add-objects-batch, cuya compatibilidad fue añadida en la versión 1.6 de la API. Esta llamada permite crear múltiples objetos en una sola solicitud a la API. Además, pueden ser objetos de diferentes tipos (por ejemplo, hosts, subredes y rangos de direcciones). Así, nuestra tarea puede ser resuelta en una sola llamada a la API.

Script utilizando 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'Tiempo para ejecutar la solicitud por lotes: {stop - start} segundos')

La ejecución de este script en mi entorno de laboratorio toma de 3 a 7 segundos, dependiendo de la carga en el servidor de gestión. Es decir, en promedio, en 101 objetos, la llamada a la API de tipo por lotes se ejecuta 10 veces más rápido. Con un mayor número de objetos, la diferencia será aún más impresionante.

Ahora veamos cómo trabajar con set-objects-batch. Con esta llamada a la API, podemos modificar masivamente cualquier parámetro. Vamos a configurar la primera mitad de las direcciones del ejemplo anterior (hasta el .124 del host, incluidos también los rangos) en color sienna, y la segunda mitad en color khaki.

Cambio de color de los objetos creados en el ejemplo anterior

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

Eliminar múltiples objetos en una sola llamada a la API se puede hacer con delete-objects-batch. Ahora veamos un ejemplo de código que elimina todos los hosts creados anteriormente a través de add-objects-batch.

Eliminación de objetos utilizando 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)

Todas las funciones que se introducen en las nuevas versiones del software Check Point también reciben inmediatamente llamadas a la API. Así, en R80.40 aparecieron características como Revert to revision y Smart Task, y se prepararon de inmediato las correspondientes llamadas a la API. Además, toda la funcionalidad al pasar de las consolas Legacy al modo Unified Policy también obtiene soporte para la API. Por ejemplo, una de las actualizaciones más esperadas en la versión R80.40 fue el traslado de la política de Inspección HTTPS del modo Legacy al modo Unified Policy, y esta funcionalidad recibió de inmediato llamadas a la API. Aquí hay un ejemplo de código que añade en la parte superior de la política de Inspección HTTPS una regla que excluye de la inspección 3 categorías (Salud, Finanzas, Servicios Públicos), que está prohibido inspeccionar de acuerdo con la legislación en varios países.

Agregar regla a la política de Inspección HTTPS

from cpapi import APIClient, APIClientArgs

client_args = APIClientArgs(server="192.168.47.240")

data = {
  "layer" : "Capa Default",
  "position" : "top",
  "name" : "Requisitos Legales",
  "action": "bypass",
  "site-category": ["Salud", "Gobierno / Militar", "Servicios Financieros"]
}

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

Ejecutar scripts de Python en el servidor de gestión de Check Point

Todo en lo mismo README.md contiene información sobre cómo ejecutar scripts en Python directamente desde el servidor de gestión. Esto puede ser útil cuando no puedes conectarte al servidor API desde otra máquina. Grabé un video de seis minutos en el que discuto la instalación del módulo cpapi y las características de ejecución de scripts de Python en el servidor de gestión. Como ejemplo, se ejecuta un script que automatiza la configuración de una nueva puerta de enlace para una tarea como la auditoría de la red. Security CheckUp. Entre las características con las que tuve que lidiar: en la versión de Python 2.7 aún no existe la función input, por lo que para manejar la información que ingresa el usuario, se utiliza la función raw_input. En el resto, el código es igual que el de la ejecución desde otras máquinas, solo que es más conveniente utilizar la función login_as_root, para no tener que volver a especificar tu propio nombre de usuario, contraseña e IP del servidor de gestión.

Reproducir video

Script para la configuración rápida de Security CheckUp

de __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:
       # si client.check_fingerprint() es False:
       #     print("No se pudo obtener la huella digital del servidor - Verifica la conectividad con el servidor.")
       #     exit(1)
        login_res = client.login_as_root()

        if login_res.success es False:
            print("Error en el inicio de sesión:n{}".format(login_res.error_message))
            exit(1)

        gw_name = raw_input("Ingresa el nombre del gateway:")
        gw_ip = raw_input("Ingresa la dirección IP del gateway:")
        if sys.stdin.isatty():
            sic = getpass.getpass("Ingresa la contraseña de un solo uso para el gateway (SIC): ")
        else:
            print("¡Atención! Tu contraseña se mostrará en la pantalla!")
            sic = raw_input("Ingresa la contraseña de un solo uso para el gateway (SIC): ")
        version = raw_input("Ingresa la versión del gateway (como 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("¡La conexión segura con el gateway no se ha establecido!")
            exit(1)
        elif add_gw.success:
            print("El gateway se agregó exitosamente.")
            gw_uid = add_gw.data['uid']
            gw_name = add_gw.data['name']
        else:
            print("Error al agregar el gateway - {}".format(add_gw.error_message))
            exit(1)

        change_policy = client.api_call("set-access-layer", {"name" : "Red", "applications-and-url-filtering": "true", "content-awareness": "true"})
        if change_policy.success:
            print("La política ha sido cambiada exitosamente")
        else:
            print("Error al cambiar la política- {}".format(change_policy.error_message))
        change_rule = client.api_call("set-access-rule", {"name" : "Regla de limpieza", "layer" : "Red", "action": "Accept", "track": {"type": "Detailed Log", "accounting": "true"}})
        if change_rule.success:
            print("La regla de limpieza ha sido cambiada exitosamente")
        else:
            print("Error al cambiar la regla de limpieza- {}".format(change_rule.error_message))

        # publicar el resultado
        publish_res = client.api_call("publish", {})
        if publish_res.success:
            print("Los cambios se publicaron exitosamente.")
        else:
                print("Error al publicar los cambios - {}".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("La política de acceso ha sido instalada")
        else:
                print("Error al instalar la política de acceso - {}".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("La política de prevención de amenazas ha sido instalada")
        else:
            print("Error al instalar la política de prevención de amenazas - {}".format(install_tp_policy.error_message))
        
        # agregar contraseñas y frases de paso al diccionario
        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" : "Agregar contraseñas y frases de paso", "script" : "printf "{}" >> $FWDIR/conf/additional_pass.conf".format(line), "targets" : gw_name})
                if add_password_dictionary.success:
                    print("La línea del diccionario de contraseñas {} fue agregada exitosamente".format(line_num))
                else:
                    print("Error al agregar el diccionario - {}".format(add_password_dictionary.error_message))

main()

Ejemplo de archivo con el diccionario de contraseñas additional_pass.conf
{
"passwords" : ["malware","malicioso","infectado","Infectado"],
"phrases" : ["contraseña","Contraseña","Pass","pass","código","clave","pwd","пароль","Пароль","Ключ","ключ","шифр","Шифр"]
}

Conclusión

Este artículo aborda solo las opciones básicas de trabajo Python SDK y del módulo cpapi(como habrás adivinado, estos son en realidad sinónimos), y al estudiar el código de este módulo descubrirás aún más posibilidades en su uso. No es imposible que sientas el deseo de complementarlo con tus propias clases, funciones, métodos y variables. Siempre puedes compartir tus trabajos y revisar otros scripts para Check Point en la sección CodeHub dentro de la comunidad CheckMates, que reúne tanto a desarrolladores de productos como a usuarios.

¡Feliz codificación y gracias por leer hasta el final!

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster