API

Uno de los módulos principales que constituyen FWCloud es su API REST. A través de esta es posible llevar a cabo todas las acciones (gestionar firewalls, administrar reglas, gestionar objetos IP, compilar/instalar política, gestionar VPNs, etc.) que FWCloud permite. Además, cualquier acción llevada a cabo utilizando el API se verá reflejada de inmediato al utilizar la interfaz de usuario.

FWCloud-API es de una utilidad enorme, dado que permite independizarse totalmente de la interfaz de usuario FWCloud-UI y hacer cosas tales como:

Nuestra propia interfaz de usuario

Crear nuestra propia interfaz de usuario totalmente independiente de FWCloud-UI.

Reglas dinámicas

Crear reglas mediante llamadas al API. Por ejemplo, para bloquear IPs de forma automática.

Estado

Obtener información de estado como, por ejemplo, las conexiones VPN activas sobre un firewall.

Gestión dinámica de nodos

Añadir/eliminar de forma dinámica nodos a un cluster de firewalls. Imaginemos una granja de frontales web que crece/decrece de forma dinámica en función de la carga, cuya política de seguridad es gestionada desde FWCloud. Es posible añadir/eliminar nodos del cluster a través de FWCloud-API e instalar la última política de seguridad al nodo recién añadido.

Para la programación del API hemos utilizado Node.js, un entorno JavaScript del lado del servidor, basado en eventos, que ejecuta código de forma asíncrona.

Entre los múltiples paquetes de Node.js que hemos utilizado cabe destacar Express, un framework que facilita de forma considerable el desarrollo de un API REST como la que hemos creado para el proyecto FWCloud, además de proporcionar las herramientas necesarias para hacer que la aplicación sea más robusta y segura.

Entre otras muchas características de Express podemos resaltar las siguientes:

Permite crear de forma sencilla APIs RESTful.

Definición de tablas de rutas basadas en el método y la URL de la petición HTTP para ejecutar el código asociado a una petición concreta al API

Permite definir código middleware, es decir, código que va a ser ejecutado para todas las peticiones HTTP enviadas al API. Esto es de una enorme utilidad ya que facilita tareas tales como la autenticación, validación de datos, control de acceso, etc.

Como utilizar FWCloud-API.

Una vez tenemos FWCloud-API instalado y funcionando tal y como se explica en la sección de instalación, ya podemos empezar a comunicar con esta utilizando protocolo HTTP/HTTPS del mismo modo que se hace con cualquier API REST.

Para ello lo único que necesitamos saber es el conjunto de llamadas al API disponibles y los parámetros que acepta cada llamada.

Una llamada a FWCloud-API está formada por los siguientes elementos:

MÉTODO

Método HTTP utilizado (POST, GET, PUT, DELETE, etc.).

URL

(Uniform Resource Locator): También conocido de forma coloquial como dirección web. Se trata de una referencia a un recurso web que indica la localización del mismo en una red de ordenadores, así como el protocolo de comunicación a utilizar para obtener dicho recurso.

PARÁMETROS

Conjunto de parámetros necesarios para que el servidor FWCloud sea capaz de procesar la llamada al API. Para simplificar FWCloud-API únicamente acepta parámetros en el body de la petición y estos tienen que venir en formato JSON. Esto es muy útil dado que simplifica enormemente el proceso de validación de datos y control de acceso. Por contra tiene el inconveniente que no es posible utilizar métodos GET y DELETE en algunas llamadas al API que precisan de parámetros, dado que estos no admiten parámetros en el body de la petición, pero esto no es un gran inconveniente como veremos más adelante.

Para entender mejor como interactuar con FWCloud-API vamos a ver unos ejemplos sencillos.

Lo  primero que necesitamos es saber la IP o nombre de dominio y el puerto en el cual está escuchando nuestra instalación FWCloud-API, es decir, la URL de acceso al API. Por defecto, se utiliza el puerto TCP 3000 en todas las IPs del servidor. Si no se está utilizando la configuración por defecto, en el fichero .env del directorio raíz de instalación podemos ver las siguientes opciones de configuración que definen esta configuración.

LISTEN_IP=0.0.0.0
LISTEN_PORT=3000

Vamos a suponer que nuestro servidor FWCloud-API tiene la configuración por defecto y que estamos accediendo al API desde el propio servidor. Además, lo vamos a hacer utilizando el protocolo HTTPS. Tal y como se explica en la sección de instalación, es muy importante utilizar siempre protocolo HTTPS a la hora de comunicar con el API para garantizar la confidencialidad de las comunicaciones con esta. Por lo tanto, todas las URLs de acceso a nuestra instalación FWCloud-API van empezar del siguiente modo:

https://localhost:3000/

Además de esto, necesitamos saber un origen válido. Los orígenes válidos están definidos dentro del fichero .env en la variable de entorno:

CORS_WHITELIST="https://ui.fwcloud.net, http://ui.fwcloud.net"

Como se explica en la documentación de instalación, estos orígenes válidos dependerán de cada instalación, aquí ponemos unos de ejemplo. Normalmente hacen referencia a la URL utilizada para el acceso a FWCloud-UI.

Por último necesitamos un código de cliente, usuario y contraseña para poder iniciar sesión en el API. Los datos de acceso para una nueva instalación FWCloud-API son los siguientes:

Código de cliente: 1
Usuario: fwcadmin
Contraseña: fwcadmin

Ahora que ya tenemos toda la información necesaria, vayamos pues con el primer ejemplo que va a consistir en utilizar la llamada al API para iniciar sesión. Este es un paso previo necesario antes de poder utilizar cualquier otra de las llamadas disponibles en FWClous-API. Para poder iniciar sesión tenemos que utilizar la URL http://localhost:3000/user/login con el método POST, un origen válido (cabecera Origin) y los parámetros pasados en el body de la petición como un objeto JSON.

Utilizando el comando curl, esta sería la llamada que tendríamos que utilizar para iniciar sesión.

curl --insecure -X POST \
  https://localhost:3000/user/login \
  -H 'Content-Type: application/json' \
  -H 'Origin: https://ui.fwcloud.net' \
  -d '{
    "customer": 1,
    "username": "fwcadmin",
    "password": "fwcadmin"
}'

Como respuesta a esta llamada al API se nos devolverá un código 200 indicando que todo ha ido bien y un objeto JSON del siguiente tipo:

{
"user": 1,
"role": 1
}

Además de una cookie de sesión que tendremos que utilizar en posteriores comunicaciones con el API para solicitar otros servicios a través de otras llamadas al API.

Set-Cookie:FWCloud.net-cookie=s%3AWVEKxBqVTa1txYz2FlxqXiCCj6PHluKT.Ofh7vD3WoJdkB7IvZwbryDV9mGSnuBEybXNWRTGEfBc; Path=/; Expires=Wed, 05 Jun 2019 16:17:42 GMT

Veamos un ejemplo más utilizando la llamada al API para crear una nueva FWCloud.

curl --insecure -X POST \
  https://localhost:3000/fwcloud \
  -H 'Content-Type: application/json' \
  -H 'Origin: https://ui.fwcloud.net' \
  -H 'cookie: FWCloud.net-cookie=s%3AWVEKxBqVTa1txYz2FlxqXiCCj6PHluKT.Ofh7vD3WoJdkB7IvZwbryDV9mGSnuBEybXNWRTGEfBc' \
  -b FWCloud.net-cookie=s%3AWVEKxBqVTa1txYz2FlxqXiCCj6PHluKT.Ofh7vD3WoJdkB7IvZwbryDV9mGSnuBEybXNWRTGEfBc \
  -d '{
    "name": "My First FWCloud",
    "image": "",
    "comment": ""
}'

Dado que es una llamada al API para modificar contenido, recibiremos una respuesta del siguiente tipo en la cual se nos indica un token de confirmación que tendremos que mandar enviando de nuevo la petición al API pero incluyendo esta vez la cabecera  X-FWC-Confirm-Token con el token recibido:

{
"fwc_confirm_token": "WVEKxBqVTa1txYz2FlxqXiCCj6PHluKT_OnTImiV44SK5OirRuoCW"
}

Esta es una medida que sirve para mejorar la seguridad, dado que se requiere de un token de confirmación para llevar a cabo cualquier acción que requiera un cambio de datos.

Por lo tanto, tenemos que repetir la llamada al API, pero incluyendo el token de confirmación esta vez:

curl --insecure -X POST \
  https://localhost:3000/fwcloud \
  -H 'Content-Type: application/json' \
  -H 'Origin: https://ui.fwcloud.net' \
  -H 'X-FWC-Confirm-Token: WVEKxBqVTa1txYz2FlxqXiCCj6PHluKT_OnTImiV44SK5OirRuoCW' \
  -H 'cookie: FWCloud.net-cookie=s%3AWVEKxBqVTa1txYz2FlxqXiCCj6PHluKT.Ofh7vD3WoJdkB7IvZwbryDV9mGSnuBEybXNWRTGEfBc' \
  -b FWCloud.net-cookie=s%3AWVEKxBqVTa1txYz2FlxqXiCCj6PHluKT.Ofh7vD3WoJdkB7IvZwbryDV9mGSnuBEybXNWRTGEfBc \
  -d '{
    "name": "My First FWCloud",
    "image": "",
    "comment": ""
}'

Obtendremos como respuesta un código 200 indicando que todo ha ido bien y un objeto JSON como el siguiente en el que se nos devuelve el ID de la fwcloud recién creada.

{
    "insertId": 1
}

Llamadas disponibles

FWCloud es una aplicación con múltiples funcionalidades, las cuales hacen uso en mayor o menor medida de los servicios disponibles a través de FWCloud-API. Es decir, cualquier acción llevada a cabo por un usuario utilizando el front-end (FWCloud-UI), se lleva a cabo enviando una o más peticiones al back-end (FWCloud-API).

Esto da lugar a que existan una gran cantidad de llamadas al API para poder cubrir todas estas funcionalidades. Es más, cada que vez que se van añadiendo más funcionalidades lo habitual es que se precisen de nuevas llamadas al API.

Para organizar de modo sencillo todas las llamadas al API lo que hemos hecho es agruparlas según el tipo de recurso para el cual son utilizadas, utilizando el mecanismos de rutas del paquete Express:

app.use('/user', user);
app.use('/customer', customer);
app.use('/fwcloud', fwcloud);
app.use('/cluster', cluster);
app.use('/firewall', firewall);
app.use('/policy/rule', policy_rule);
app.use('/policy/compile', policy_compile);
app.use('/policy/install', policy_install);
app.use('/policy/ipobj', policy_ipobj);
app.use('/policy/interface', policy_interface);
app.use('/policy/group', policy_group);
app.use('/policy/types', policy_types);
app.use('/policy/positions', policy_positions);
app.use('/policy/openvpn', policy_openvpn);
app.use('/policy/prefix', policy_prefix);
app.use('/interface', interface);
app.use('/ipobj', ipobj);
app.use('/ipobj/group', ipobj_group);
app.use('/ipobj/types', ipobj_types);
app.use('/ipobj/positions', ipobj_positions);
app.use('/ipobj/mark', ipobj_mark);
app.use('/tree', tree);
app.use('/tree/folder', tree_folder);
app.use('/tree/repair', tree_repair);
app.use('/vpn/pki/ca', vpn_pki_ca);
app.use('/vpn/pki/crt', vpn_pki_crt);
app.use('/vpn/pki/prefix', vpn_pki_prefix);
app.use('/vpn/openvpn', vpn_openvpn);
app.use('/vpn/openvpn/prefix', vpn_openvpn_prefix);

Por ejemplo, todas las llamadas al API que empiezan con /user son utilizadas para gestionar los usuarios que van a tener acceso al API. Las que empiezan con /customer para gestionar los clientes, /fwcloud para las FWClouds, /firewall para los firewalls, /policy para la política de seguridad, /vpn para las conexiones VPN, etc. Además se utilizan los métodos de forma consistente, POST para crear nuevos recursos (clientes, usuarios, firewalls, VPNs, etc); PUT para modificarlos, etc.

La documentación de referencia para cada una de las llamadas al API la estamos generando utilizando la herramienta APIDOC, la cual nos permite generar documentación a partir de comentarios incluidos dentro del código fuente. Si utilizamos un navegador y abrimos el fichero index.html existente dentro de la carpeta apidoc del directorio de instalación de FWCloud-API tendremos acceso a la última versión del manual de referencia del API.

Estamos utilizando Postman como herramienta para probar el API y para la automatización de tests del software. Esta herramienta permite generar una documentación detallada de todos los tests utilizados, lo cual es muy útil como documentación adicional para entender el funcionamiento del API. Dicha documentación está públicamente accesible a través de la URL: https://documenter.getpostman.com/view/6531497/S1TYUvym

Dentro de la carpeta postman existente en el directorio raíz de instalación de FWCloud-API podemos obtener la última versión de la colección de tests utilizados para verificar el correcto funcionamiento del API.

Llamadas al API sin documentar.

A pesar de nuestros esfuerzos, existen aún muchas llamadas a FWCloud-API que están pendientes de documentar y seguimos trabajando intensamente para terminar esta tarea. No obstante, esto no debe de suponer ningún problema puesto que es posible averiguar cómo funciona cualquier llamada accediendo al código fuente del proyecto.

Por ejemplo, imaginemos que queremos averiguar cómo funciona la llamada al API para crear una nueva FWCloud. Lo primero que tenemos que hacer es identificar la URL y el método HTTP que tenemos que utilizar.

En el directorio raíz donde hemos instalado FWCloud-API, veremos el directorio routes están definidas todas las llamadas al API. En este caso queremos averiguar como crear una nueva FWCloud, así que tendremos que acceder al directorio routes/fwcloud.

En el mismo, el fichero fwcloud.js contiene todas las llamadas al API para gestionar el recurso fwcloud. En la sección router.post tendremos una ruta para la creación de una nueva FWCloud, la cual nos da pie a descubrir la URL necesaria, en este caso: https://localhost:3000/fwcloud

Por último, necesitamos saber los parámetros necesarios para hacer el post. Esta información la tenemos en el middleware utilizado para filtrar y validar la entrada de datos, que se sirve del paquete JOI para estas funciones. En el fichero middleware/input_validation.js podemos ver como para /fwcloud nos indica que usará un fichero del directorio middleware/joi_schemas, concretamente fwcloud.js, el cual define los parámetros que necesita cada una de las llamadas al API para la gestión del recurso fwcloud.

Así, si vemos que alguna llamada al API no está documentada, podemos utilizar este tipo de procedimiento para averiguar cómo utilizarla. Además, podéis contactar con nosotros a través de nuestro formulario de contacto o utilizar el foro de la web para plantear cualquier duda que pueda surgir en el uso o instalación de FWCloud.