Ultra Tesla: Crear redes distribuidas de servicios, fácil, rápido y seguro

Ultra Tesla es un proyecto de código abierto para crear redes distribuidas de servicios fácil, rápido y seguro, usando el poder de computo de múltiples ordenadores. El proyecto permite unificar los distintos servidores en una única interfaz que es proporcionada para el mismo usuario creando una sensación de transparencia.


Mi primer "Hello World":

Ultra Tesla utiliza servicios, que son básicamente mini-programas que se adhieren a la ejecución del servidor, siguiendo una sintaxis en HTTP como la siguiente: ://///<...>

Donde es 'http' o 'https' según la configuración del servidor; es básicamente la dirección del servidor; es el nombre del servicio, que para este ejemplo será "hello_world" y los demás que son y <...> son básicamente otros mini-programas que se tendrán que usar anteponiendo el nombre del servicio anterior, por ejemplo, ////<...> y así según lo que el administrador haya propuesto.

Código: Python
  1. class Handler:
  2.     async def get(self):
  3.        await self.write('Hello World!')

Un ejemplo real con el servicio nombrado como complements/hello_world.py en una URL se vería como lo siguiente (suponiendo que la dirección del servidor sea localhost): http://localhost:17000/hello_world


Contactando al servidor:

Lo siguiente es un script simple para poder contactarse con el servidor y obtener la salida del servicio 'hello_world'

Código: Python
  1. import asyncio
  2. from modules.Infrastructure import client
  3. async def main():
  4.     UTeslaClient = client.UTeslaClient('')
  5.     await UTeslaClient.set_server_key('')
  6.     await UTeslaClient.set_user_keys('', '')
  7.     cmd = {
  8.         'token' : ''
  9.     }
  10.     Response = await UTeslaClient.fetch(
  11.         'http://localhost:17000/hello_world',
  12.         cmd,
  13.         method='GET'
  14.     )
  15.     dec_body = UTeslaClient.get_message(Response.body)
  16.     print(dec_body)
  17. if __name__ == '__main__':
  18.     asyncio.run(main())

Deberíamos obtener la siguiente respuesta:

Código: Text
  1. Hello World!

Creando un usuario:


El administrador será el encargado de crear los usuarios, aunque perfectamente se podría automatizar como un sistema de registro cualquiera con una interfaz de usuario cualquiera, para este ejemplo se usará el plugin 'add' de UTeslaCLI.

Código: Bash
  1. # Para requerir ayuda
  2. ./UTeslaCLI add --help
  3. # Creamos el usuario
  4. ./UTeslaCLI add -u <Nombre de usuario> -p <Contraseña> -i <Ruta de la clave pública>

Creación del par de claves:

Tanto el servidor como el usuario deben tener sus par de claves para que la comunicación sea satisfactoria. Esto es un proceso inicial que deben hacer antes de hacer cualquier cosa (independientemente de si es un usuario o el administrador del servidor).

En el cliente:

El cliente va a requerir usar el plugin 'generate_keys' para la creación del par de claves

Código: Bash
  1. # Para requerir ayuda
  2. ./UTeslaCLI generate_keys --help
  3. # Generamos el par de claves
  4. ./UTeslaCLI generate_keys -bit_size <Tamaño del par de claves en bits> -out-public-key <Nombre del archivo de la clave pública> -out-private-key <Nombre del archivo de la clave privada>

Si se ejecuta sin parámetros se generará con un tamaño de claves por defecto de 3072 bit's y las claves se mostrarán en la salida. Lo recomendable sería dejar el tamaño de claves pre-determinado y guardar el par de claves en un lugar seguro.

Ahora lo que tendría que hacer el usuario que desea registrarse es enviar la clave pública al administrador del servidor para que éste lo registre satisfactoriamente.


En el servidor:

El proceso para generar el par de claves en el lado del servidor será mucho más simple; se hará automáticamente cuando se ejecute.

Código: Bash
  1. ./UTesla

El tamaño del par de claves estará definido en UTesla.ini, en la sección 'Crypt Limits' y en la clave 'rsa_key_length'.


Lo recomendable es dejar el tamaño de claves pre-determinado tanto del lado del cliente y del servidor, y se debe tener en cuenta que el tamaño de claves debe ser igual o equivalente en las dos partes.

Creación del token de acceso:

UTesla requiere de un token de acceso para realizar la mayoría de acciones, en este caso el cliente deseoso por obtener su token tiene que usar el plugin 'generate_token'

Código: Bash
  1. ./UTeslaCLI generate_token <La URL del servidor> -u <El nombre de usuario> -p <La contraseña del usuario> -s <La clave pública del servidor> -i <La clave pública del usuario> -I <La clave privada del usuario>

Una vez hecho lo anterior y la petición haya sido satisfactoria, se mostrará el token de acceso, el cual debe ser almacenado en un lugar seguro para su posterior uso.

Uso de la distribución de servicios:

Supongamos que en el mundo haya dos servidores y los administradores se conozcan, uno de éstos contiene uno o más servicios que otro no tiene, pero un cliente que requiera el uso de ese servicio usando la URL del primer servidor (por ejemplo) no tendría ningún inconveniente, ya que si el servicio deseado no se encuentra en el primer servidor, éste hará una búsqueda en la red y determinará qué servidor es el que contiene ese servicio, posteriormente obtendría una respuesta como si fuera el mismo cliente y luego la redirige hacia el cliente mismo, por lo que todo sería transparente.

Lo anterior es muy útil si se desea separar ciertos servicios entre servidores, por cuestiones económicas, de recursos, una mejoría en la implementación o cualquier cosa que se desee, al fin y al cabo, el usuario es el que lo decide.

Para estos ejemplos el primer servidor será 'http://localhost:17000' y el segundo 'http://localhost:17001'. El segundo tiene un servicio llamado 'hello_friend', pero nosotros "los clientes" vamos a creer que el servicio está en el primer servidor, por lo cual lo usaremos para interactuar con éste.


complements/hello_friend.py:

Código: Python
  1. class handler:
  2.     async def get(self):
  3.         await self.write('hello friend!')

Por diseño, el administrador del segundo servidor debe crear un usuario como si fuera cualquier otro. Por lo que debe saber cómo crearlo, cosa que ya se hablo en anteriores secciones. En este caso nosotros lo llamaremos 'utesla'.

Además, como ya se aclaró en anteriores secciones, la mayoría de operaciones requieren de un token de acceso, por lo se va a suponer que se tiene hecho este paso para el nuevo usuario utesla.

Una vez aclarado todo lo que se tiene que hacer, vamos un paso más allá y obtengamos los servicios del segundo servidor (http://localhost:17001) para el primer servidor (http://localhost:17000)

Código: Bash
  1. ./UTeslaCLI add_network http://localhost:17001 -s <Clave pública del segundo servidor> -p keys/key.pub -P keys/key.priv -u utesla -t <Token de acceso>

Como esto es un ejemplo, se usan las claves que por defecto se almacenan en la carpeta 'keys' del primer servidor; se usa el usuario 'utesla' que ya debe estar creado en el segundo servidor y nos contactamos con el servidor 'http://localhost:17001' para obtener sus servicios.

Como paso final, el cliente desea obtener el servicio 'hello_friend' y si todo ha salido bien, obtendrá su posterior salida, aunque lo peculiar de todo esto es que el cliente hará una petición al primer servidor en vez de al segundo.

Lo siguiente será muy parecido a lo que se observó en anteriores secciones, pero lo único que cambió es el nombre del servicio:

Código: Python
  1. import asyncio
  2. from modules.Infrastructure import client
  3. async def main():
  4.     UTeslaClient = client.UTeslaClient('')
  5.     await UTeslaClient.set_server_key('')
  6.     await UTeslaClient.set_user_keys('', '')
  7.     cmd = {
  8.         'token' : ''
  9.     }
  10.     Response = await UTeslaClient.fetch(
  11.         'http://localhost:17000/hello_friend',
  12.         cmd,
  13.         method='GET'
  14.     )
  15.     dec_body = UTeslaClient.get_message(Response.body)
  16.     print(dec_body)
  17. if __name__ == '__main__':
  18.     asyncio.run(main())

Deberíamos obtener la siguiente respuesta:

Código: Text
  1. Hello Friend!

Como se puede apreciar, es un proceso muy sencillo y lo mejor, es transparente para el usuario.

Dependencias:

Arch Linux:

  • mariadb
Debian:
  • mariadb-server
  • libmariadb-dev
  • python3-dev
Red Hat Enterprise Linux 8.2:
  • python3-devel
  • gcc
  • mariadb
  • mariadb-server
  • mariadb-devel
Instalación:

Código: Bash
  1. git clone --recursive https://github.com/UltraTesla/UTesla.git
  2. cd UTesla

Arch Linux:

Código: Bash
  1. sudo pacman -S mariadb

Debian:

Código: Bash
  1. sudo apt-get install mariadb-server libmariadb-dev python3-dev

Red Hat Enterprise Linux 8.2:

Código: Bash
  1. sudo yum install python3-devel gcc mariadb mariadb-server mariadb-devel

General:

Código: Bash
  1. sudo systemctl start mariadb.server
  2. python3 -m pip install -r requirements.txt
  3. ./UTesla

Es recomendable configurar primero antes de iniciar UTesla (como el nombre de usuario y la contraseña en MySQL)

Contribuyendo:

Al igual que cada proyecto nuevo creado, soy imperfecto y puedo equivocarme, pero con todo el gusto del mundo aceptaré tu contribución, ya sea por código o no, porque hay que recordar que se trata de abarcar muchos idiomas de distintas regiones del mundo y en éso puede haber múltiples defectos.

Notas:

  • El proyecto fue probado en Red Hat Enterprise Linux 8.2, Debian y Arch Linux
  • No se ha probado en Windows u otro sistema operativo
  • El proyecto usa un protocolo propio y no uno estándar
  • El proyecto no está definido, de eso se encarga el mismo usuario
  • Todo el proyecto fue probado en la versión 3.8.2 y 3.7.3 de python
Contribución gracias a ~DtxdF de Underc0de

Comentarios