paint-brush
Enrutamiento Ockam: creación de canales seguros de extremo a extremopor@ockam
6,394 lecturas
6,394 lecturas

Enrutamiento Ockam: creación de canales seguros de extremo a extremo

por Ockam24m2023/08/02
Read on Terminal Reader

Demasiado Largo; Para Leer

Una explicación y ejemplos de cómo crear sistemas seguros verdaderamente integrales que le permitan confiar en los datos que envía y/o recibe.
featured image - Enrutamiento Ockam: creación de canales seguros de extremo a extremo
Ockam HackerNoon profile picture
0-item


Ockam es un conjunto de bibliotecas de programación, herramientas de línea de comandos y servicios de nube administrados para orquestar el cifrado de extremo a extremo, la autenticación mutua, la administración de claves, la administración de credenciales y la aplicación de políticas de autorización, todo a escala masiva. Ockam de extremo a extremo canales seguros garantizar la autenticidad, integridad y confidencialidad de todos los datos en movimiento en la capa de aplicación.


Una de las características clave que hacen esto posible es Enrutamiento Ockam . El enrutamiento nos permite crear canales seguros a través de rutas multiprotocolo y de múltiples saltos que pueden abarcar varias topologías de red (servidores detrás de cortafuegos NAT sin puertos externos abiertos, etc.) y protocolos de transporte (TCP, UDP, WebSockets, BLE, etc.).


En esta publicación de blog, exploraremos la API de Ockam Rust y veremos cómo funciona el enrutamiento en Ockam. Trabajaremos con el código de Rust y veremos algunos ejemplos de código que demuestran el caso simple y casos de uso más avanzados.


Descripción general del contenido

  • Riesgo atenuante
  • Nuestro viaje
  • ejemplo sencillo
  • Ejemplo complejo
    • Nodo iniciador
    • Nodo medio
    • Nodo de respuesta
  • Próximos pasos


Riesgo atenuante

Antes de comenzar, analicemos rápidamente los peligros de utilizar los enfoques existentes para proteger las aplicaciones. La seguridad no es algo en lo que la mayoría de nosotros pensemos cuando construimos sistemas y nos enfocamos en hacer que las cosas funcionen y se envíen.


Las implementaciones de comunicaciones seguras tradicionales suelen estar estrechamente vinculadas con los protocolos de transporte de manera que toda su seguridad se limita a la longitud y la duración de una conexión de transporte subyacente.


  1. Por ejemplo, la mayoría de las implementaciones de TLS están estrechamente vinculadas con la conexión TCP subyacente. Si los datos y las solicitudes de su aplicación viajan a través de dos saltos de conexión TCP (TCP → TCP), todas las garantías de TLS se interrumpen en el puente entre las dos redes. Este puente, puerta de enlace o equilibrador de carga se convierte en un punto débil para los datos de la aplicación.


  2. Los protocolos de comunicación seguros tradicionales tampoco pueden proteger los datos de su aplicación si viaja a través de múltiples protocolos de transporte diferentes. No pueden garantizar la autenticidad o la integridad de los datos si la ruta de comunicación de su aplicación es UDP → TCP o BLE → TCP.


En otras palabras, al usar implementaciones de comunicación segura tradicionales, puede estar abriendo las puertas a perder la confianza en los datos en los que trabajan sus aplicaciones. Estos son algunos aspectos de sus aplicaciones que pueden estar en riesgo:


  1. Falta de confianza en los datos que tu aplicación recibe de alguna otra entidad.
    • ¿Quién lo envió a mi aplicación?

    • ¿Son realmente los datos que enviaron a mi aplicación?

    • Autenticación faltante e integridad de datos.


  2. Falta de confianza en los datos que tu aplicación envía a alguna otra entidad.
    • ¿A quién envío los datos?
    • ¿Podrán verlo junto con alguien más?


Nuestro viaje

En esta publicación de blog, crearemos dos ejemplos de nodos de Ockam que se comunican entre sí mediante el enrutamiento de Ockam y los transportes de Ockam. Usaremos la API de Rust para crear estos nodos de Ockam y configurar la orquestación de enrutamiento de Ockam. El enrutamiento y los transportes de Ockam permiten que otros protocolos de Ockam brinden garantías de extremo a extremo como confianza, seguridad, privacidad, entrega confiable y pedidos en la capa de aplicación.


  • Enrutamiento Ockam : es un protocolo simple y liviano basado en mensajes que permite intercambiar mensajes bidireccionalmente en una gran variedad de topologías de comunicación: TCP -> TCP o TCP -> TCP -> TCP o BLE -> UDP -> TCP o BLE -> TCP -> TCP o TCP -> Kafka -> TCP o cualquier otra topología que puedas imaginar.


  • Transportes Ockam : adapte el enrutamiento Ockam a varios protocolos de transporte.


Un nodo Ockam es cualquier aplicación en ejecución que puede comunicarse con otras aplicaciones utilizando varios protocolos Ockam como enrutamiento, retransmisiones y portales, canales seguros, etc.


Un nodo de Ockam se puede definir como cualquier proceso independiente que proporciona una API compatible con el protocolo de enrutamiento de Ockam. Podemos crear nodos Ockam usando el Interfaz de línea de comandos (CLI) de Ockam (comando ockam ) o usando varias bibliotecas de programación Ockam como nuestras bibliotecas Rust y Elixir. Usaremos la API de Rust en esta publicación de blog.


Cuando un trabajador se inicia en un nodo , se le da una o más direcciones. El nodo mantiene un buzón para cada dirección y cada vez que llega un mensaje para una dirección específica entrega ese mensaje al trabajador registrado correspondiente.


ejemplo sencillo

Para nuestro primer ejemplo, crearemos un nodo Ockam simple que enviará un mensaje a través de algunos saltos (en el mismo nodo) a un trabajador (en el mismo nodo) que simplemente devuelve el mensaje. No hay transportes TCP involucrados y todos los mensajes se pasan de un lado a otro dentro del mismo nodo. Esto nos dará una idea de cómo construir trabajadores y enrutamiento en un nivel básico.


Necesitaremos crear un archivo fuente de Rust con un programa main() y otros dos archivos fuente de Rust con dos trabajadores: Hopper y Echoer . Luego podemos enviar un mensaje de cadena y ver si podemos recuperarlo.


Antes de comenzar, consideremos el enrutamiento. Cuando enviamos un mensaje dentro de un nodo, lleva consigo 2 campos de metadatos, onward_route y return_route , donde una route es simplemente una lista de adresses . Cada trabajador obtiene una address en un nodo.


Entonces, si quisiéramos enviar un mensaje desde la dirección de la app a la dirección echoer , con 3 saltos en el medio, podemos construir una ruta como la siguiente.


 ┌───────────────────────┐ │ Node 1 │ ├───────────────────────┤ │ ┌────────────────┐ │ │ │ Address: │ │ │ │ 'app' │ │ │ └─┬────────────▲─┘ │ │ ┌─▼────────────┴─┐ │ │ │ Address: │ │ │ │ 'hopper1..3' │x3 │ │ └─┬────────────▲─┘ │ │ ┌─▼────────────┴─┐ │ │ │ Address: │ │ │ │ 'echoer' │ │ │ └────────────────┘ │ └───────────────────────┘


Aquí está el código Rust para construir esta ruta.


 /// Send a message to the echoer worker via the "hopper1", "hopper2", and "hopper3" workers. let route = route!["hopper1", "hopper2", "hopper3", "echoer"];


Agreguemos algo de código fuente para que esto suceda a continuación. Lo primero que haremos será agregar una dependencia más a este proyecto hello_ockam vacío. La caja colored nos dará una salida de consola coloreada que hará que la salida de nuestros ejemplos sea mucho más fácil de leer y comprender.


 cargo add colored


Luego agregamos el trabajador echoer (en nuestro proyecto hello_ockam ) creando un nuevo archivo /src/echoer.rs y copiando/pegando el siguiente código en él.


 use colored::Colorize; use ockam::{Context, Result, Routed, Worker}; pub struct Echoer; /// When a worker is started on a node, it is given one or more addresses. The node /// maintains a mailbox for each address and whenever a message arrives for a specific /// address it delivers that message to the corresponding registered worker. /// /// Workers can handle messages from other workers running on the same or a different /// node. In response to a message, an worker can: make local decisions, change its /// internal state, create more workers, or send more messages to other workers running on /// the same or a different node. #[ockam::worker] impl Worker for Echoer { type Context = Context; type Message = String; async fn handle_message(&mut self, ctx: &mut Context, msg: Routed<String>) -> Result<()> { // Echo the message body back on its return_route. let addr_str = ctx.address().to_string(); let msg_str = msg.as_body().to_string(); let new_msg_str = format!("👈 echo back: {}", msg); // Formatting stdout output. let lines = [ format!("📣 'echoer' worker → Address: {}", addr_str.bright_yellow()), format!(" Received: '{}'", msg_str.green()), format!(" Sent: '{}'", new_msg_str.cyan()), ]; lines .iter() .for_each(|line| println!("{}", line.white().on_black())); ctx.send(msg.return_route(), new_msg_str).await } }


A continuación, agregamos el trabajador hopper (en nuestro proyecto hello_ockam ) creando un nuevo archivo /src/hopper.rs y copiando/pegando el siguiente código en él.


Observe cómo este trabajador manipula los campos onward_route y return_route del mensaje para enviarlo al siguiente salto. De hecho, veremos esto en la salida de la consola cuando ejecutemos este código pronto.


 use colored::Colorize; use ockam::{Any, Context, Result, Routed, Worker}; pub struct Hopper; #[ockam::worker] impl Worker for Hopper { type Context = Context; type Message = Any; /// This handle function takes any incoming message and forwards. it to the next hop /// in it's onward route. async fn handle_message(&mut self, ctx: &mut Context, msg: Routed<Any>) -> Result<()> { // Cast the msg to a Routed<String> let msg: Routed<String> = msg.cast()?; let msg_str = msg.to_string().white().on_bright_black(); let addr_str = ctx.address().to_string().white().on_bright_black(); // Some type conversion. let mut message = msg.into_local_message(); let transport_message = message.transport_mut(); // Remove my address from the onward_route. let removed_address = transport_message.onward_route.step()?; let removed_addr_str = removed_address .to_string() .white() .on_bright_black() .strikethrough(); // Formatting stdout output. let lines = [ format!("🐇 'hopper' worker → Addr: '{}'", addr_str), format!(" Received: '{}'", msg_str), format!(" onward_route -> remove: '{}'", removed_addr_str), format!(" return_route -> prepend: '{}'", addr_str), ]; lines .iter() .for_each(|line| println!("{}", line.black().on_yellow())); // Insert my address at the beginning return_route. transport_message .return_route .modify() .prepend(ctx.address()); // Send the message on its onward_route. ctx.forward(message).await } }


Y finalmente, agreguemos un main() a nuestro proyecto hello_ockam . Este será el punto de entrada para nuestro ejemplo.


Cree un archivo vacío /examples/03-routing-many.hops.rs (tenga en cuenta que esto está en la carpeta examples/ y no en la carpeta src/ como los trabajadores anteriores).


 use colored::Colorize; use hello_ockam::{Echoer, Hopper}; use ockam::{node, route, Context, Result}; #[rustfmt::skip] const HELP_TEXT: &str =r#" ┌───────────────────────┐ │ Node 1 │ ├───────────────────────┤ │ ┌────────────────┐ │ │ │ Address: │ │ │ │ 'app' │ │ │ └─┬────────────▲─┘ │ │ ┌─▼────────────┴─┐ │ │ │ Address: │ │ │ │ 'hopper1..3' │x3 │ │ └─┬────────────▲─┘ │ │ ┌─▼────────────┴─┐ │ │ │ Address: │ │ │ │ 'echoer' │ │ │ └────────────────┘ │ └───────────────────────┘ "#; /// This node routes a message through many hops. #[ockam::node] async fn main(ctx: Context) -> Result<()> { println!("{}", HELP_TEXT.green()); print_title(vec![ "Run a node w/ 'app', 'echoer' and 'hopper1', 'hopper2', 'hopper3' workers", "then send a message over 3 hops", "finally stop the node", ]); // Create a node with default implementations. let mut node = node(ctx); // Start an Echoer worker at address "echoer". node.start_worker("echoer", Echoer).await?; // Start 3 hop workers at addresses "hopper1", "hopper2" and "hopper3". node.start_worker("hopper1", Hopper).await?; node.start_worker("hopper2", Hopper).await?; node.start_worker("hopper3", Hopper).await?; // Send a message to the echoer worker via the "hopper1", "hopper2", and "hopper3" workers. let route = route!["hopper1", "hopper2", "hopper3", "echoer"]; let route_msg = format!("{:?}", route); let msg = "Hello Ockam!"; node.send(route, msg.to_string()).await?; // Wait to receive a reply and print it. let reply = node.receive::<String>().await?; // Formatting stdout output. let lines = [ "🏃 Node 1 →".to_string(), format!(" sending: {}", msg.green()), format!(" over route: {}", route_msg.blue()), format!(" and receiving: '{}'", reply.purple()), // Should print "👈 echo back: Hello Ockam!" format!(" then {}", "stopping".bold().red()), ]; lines .iter() .for_each(|line| println!("{}", line.black().on_white())); // Stop all workers, stop the node, cleanup and return. node.stop().await } fn print_title(title: Vec<&str>) { let line = format!("🚀 {}", title.join("\n → ").white()); println!("{}", line.black().on_bright_black()) }


¡Ahora es el momento de ejecutar nuestro programa para ver qué hace! 🎉


En su aplicación de terminal, ejecute el siguiente comando. Tenga en cuenta que OCKAM_LOG=none se usa para deshabilitar la salida de registro de la biblioteca Ockam. Esto se hace para que la salida del ejemplo sea más fácil de leer.


 OCKAM_LOG=none cargo run --example 03-routing-many-hops


Y deberías ver algo como lo siguiente. Nuestro programa de ejemplo crea varios trabajadores de salto (tres trabajadores hopper ) entre la app y el echoer y enruta nuestro mensaje a través de ellos 🚀.


Resultado de ejecutar 03-routing-many-hops


Ejemplo complejo

En este ejemplo, introduciremos Transportes TCP entre los saltos. En lugar de pasar mensajes entre trabajadores en el mismo nodo, generaremos múltiples nodos. Luego tendremos algunos transportes TCP (cliente de socket TCP y combos de escucha) que conectarán los nodos.


Un transporte Ockam es un complemento para el enrutamiento Ockam. Mueve los mensajes de enrutamiento de Ockam utilizando un protocolo de transporte específico como TCP, UDP, WebSockets, Bluetooth, etc.


Tendremos tres nodos:


  1. node_initiator : el primer nodo inicia el envío del mensaje a través de TCP al nodo intermedio (puerto 3000 ).


  2. node_middle : luego, el nodo medio simplemente reenvía este mensaje al último nodo a través de TCP nuevamente (puerto 4000 esta vez).


  3. node_responder : y finalmente, el nodo respondedor recibe el mensaje y envía una respuesta al nodo iniciador.


El siguiente diagrama muestra lo que construiremos a continuación. En este ejemplo, todos estos nodos están en la misma máquina, pero fácilmente pueden ser solo nodos en diferentes máquinas.


 ┌──────────────────────┐ │node_initiator │ ├──────────────────────┤ │ ┌──────────────────┐ │ │ │Address: │ │ ┌───────────────────────────┐ │ │'app' │ │ │node_middle │ │ └──┬────────────▲──┘ │ ├───────────────────────────┤ │ ┌──▼────────────┴──┐ │ │ ┌──────────────────┐ │ │ │TCP transport └─┼─────┼─►TCP transport │ │ │ │connect to 3000 ◄─┼─────┼─┐listening on 3000 │ │ │ └──────────────────┘ │ │ └──┬────────────▲──┘ │ └──────────────────────┘ │ ┌──▼────────────┴───────┐ │ │ │Address: │ │ ┌──────────────────────┐ │ │'forward_to_responder' │ │ │node_responder │ │ └──┬────────────▲───────┘ │ ├──────────────────────┤ │ ┌──▼────────────┴──┐ │ │ ┌──────────────────┐ │ │ │TCP transport └──────┼───┼─►TCP transport │ │ │ │connect to 4000 ◄──────┼───┼─┐listening on 4000 │ │ │ └──────────────────┘ │ │ └──┬────────────▲──┘ │ └───────────────────────────┘ │ ┌──▼────────────┴──┐ │ │ │Address: │ │ │ │'echoer' │ │ │ └──────────────────┘ │ └──────────────────────┘


Comencemos creando un nuevo archivo /examples/04-routing-over-two-transport-hops.rs (en la carpeta /examples/ y no en la carpeta /src/ ). Luego copie/pegue el siguiente código en ese archivo.


 use colored::Colorize; use hello_ockam::{Echoer, Forwarder}; use ockam::{ node, route, AsyncTryClone, Context, Result, TcpConnectionOptions, TcpListenerOptions, TcpTransportExtension, }; #[rustfmt::skip] const HELP_TEXT: &str =r#" ┌──────────────────────┐ │node_initiator │ ├──────────────────────┤ │ ┌──────────────────┐ │ │ │Address: │ │ ┌───────────────────────────┐ │ │'app' │ │ │node_middle │ │ └──┬────────────▲──┘ │ ├───────────────────────────┤ │ ┌──▼────────────┴──┐ │ │ ┌──────────────────┐ │ │ │TCP transport └─┼─────┼─►TCP transport │ │ │ │connect to 3000 ◄─┼─────┼─┐listening on 3000 │ │ │ └──────────────────┘ │ │ └──┬────────────▲──┘ │ └──────────────────────┘ │ ┌──▼────────────┴───────┐ │ │ │Address: │ │ ┌──────────────────────┐ │ │'forward_to_responder' │ │ │node_responder │ │ └──┬────────────▲───────┘ │ ├──────────────────────┤ │ ┌──▼────────────┴──┐ │ │ ┌──────────────────┐ │ │ │TCP transport └──────┼───┼─►TCP transport │ │ │ │connect to 4000 ◄──────┼───┼─┐listening on 4000 │ │ │ └──────────────────┘ │ │ └──┬────────────▲──┘ │ └───────────────────────────┘ │ ┌──▼────────────┴──┐ │ │ │Address: │ │ │ │'echoer' │ │ │ └──────────────────┘ │ └──────────────────────┘ "#; #[ockam::node] async fn main(ctx: Context) -> Result<()> { println!("{}", HELP_TEXT.green()); let ctx_clone = ctx.async_try_clone().await?; let ctx_clone_2 = ctx.async_try_clone().await?; let mut node_responder = create_responder_node(ctx).await.unwrap(); let mut node_middle = create_middle_node(ctx_clone).await.unwrap(); create_initiator_node(ctx_clone_2).await.unwrap(); node_responder.stop().await.ok(); node_middle.stop().await.ok(); println!( "{}", "App finished, stopping node_responder & node_middle".red() ); Ok(()) } fn print_title(title: Vec<&str>) { let line = format!("🚀 {}", title.join("\n → ").white()); println!("{}", line.black().on_bright_black()) }



Este código en realidad no se compilará, ya que faltan 3 funciones en este archivo fuente. Solo estamos agregando este archivo primero para organizar el resto del código que escribiremos a continuación.

Esta función main() crea los tres nodos como vemos en el diagrama anterior, y también los detiene una vez que el ejemplo termina de ejecutarse.


Nodo iniciador

Entonces, primero escribamos la función que crea el nodo iniciador. Copie lo siguiente en el archivo fuente que creamos anteriormente ( /examples/04-routing-over-two-transport-hops.rs ) y péguelo debajo del código existente allí:


 /// This node routes a message, to a worker on a different node, over two TCP transport /// hops. async fn create_initiator_node(ctx: Context) -> Result<()> { print_title(vec![ "Create node_initiator that routes a message, over 2 TCP transport hops, to 'echoer' worker on node_responder", "stop", ]); // Create a node with default implementations. let mut node = node(ctx); // Initialize the TCP transport. let tcp_transport = node.create_tcp_transport().await?; // Create a TCP connection to the middle node. let connection_to_middle_node = tcp_transport .connect("localhost:3000", TcpConnectionOptions::new()) .await?; // Send a message to the "echoer" worker, on a different node, over two TCP hops. Wait // to receive a reply and print it. let route = route![connection_to_middle_node, "forward_to_responder", "echoer"]; let route_str = format!("{:?}", route); let msg = "Hello Ockam!"; let reply = node .send_and_receive::<String>(route, msg.to_string()) .await?; // Formatting stdout output. let lines = [ "🏃 node_initiator →".to_string(), format!(" sending: {}", msg.green()), format!(" over route: '{}'", route_str.blue()), format!(" and received: '{}'", reply.purple()), // Should print "👈 echo back: Hello Ockam!" format!(" then {}", "stopping".bold().red()), ]; lines .iter() .for_each(|line| println!("{}", line.black().on_white())); // Stop all workers, stop the node, cleanup and return. node.stop().await }


Este nodo (iniciador) enviará un mensaje al respondedor utilizando la siguiente ruta.


 let route = route![connection_to_middle_node, "forward_to_responder", "echoer"];


Nodo medio

Vamos a crear el nodo medio a continuación, que ejecutará el Worker Forwarder en esta dirección: forward_to_responder .


Copie y pegue lo siguiente en el archivo fuente que creamos anteriormente ( /examples/04-routing-over-two-transport-hops.rs ).


  • Este nodo intermedio simplemente reenvía todo lo que entra en su escucha TCP (en 3000 ) al puerto 4000 .

  • Este nodo tiene un trabajador Forwarder en la dirección forward_to_responder , así es como el iniciador puede llegar a la dirección especificada en su ruta al comienzo de este ejemplo.


 /// - Starts a TCP listener at 127.0.0.1:3000. /// - This node creates a TCP connection to a node at 127.0.0.1:4000. /// - Starts a forwarder worker to forward messages to 127.0.0.1:4000. /// - Then runs forever waiting to route messages. async fn create_middle_node(ctx: Context) -> Result<ockam::Node> { print_title(vec![ "Create node_middle that listens on 3000 and forwards to 4000", "wait for messages until stopped", ]); // Create a node with default implementations. let node = node(ctx); // Initialize the TCP transport. let tcp_transport = node.create_tcp_transport().await?; // Create a TCP connection to the responder node. let connection_to_responder = tcp_transport .connect("127.0.0.1:4000", TcpConnectionOptions::new()) .await?; // Create a Forwarder worker. node.start_worker( "forward_to_responder", Forwarder { address: connection_to_responder.into(), }, ) .await?; // Create a TCP listener and wait for incoming connections. let listener = tcp_transport .listen("127.0.0.1:3000", TcpListenerOptions::new()) .await?; // Allow access to the Forwarder via TCP connections from the TCP listener. node.flow_controls() .add_consumer("forward_to_responder", listener.flow_control_id()); // Don't call node.stop() here so this node runs forever. Ok(node) }


Nodo de respuesta

Finalmente, crearemos el nodo respondedor. Este nodo ejecutará el echoer del trabajador que en realidad devuelve el mensaje al iniciador. Copie y pegue lo siguiente en el archivo fuente anterior ( /examples/04-routing-over-two-transport-hops.rs ).


  • Este nodo tiene un trabajador Echoer en la dirección echoer , así es como el iniciador puede llegar a la dirección especificada en su ruta al comienzo de este ejemplo.


 /// This node starts a TCP listener and an echoer worker. It then runs forever waiting for /// messages. async fn create_responder_node(ctx: Context) -> Result<ockam::Node> { print_title(vec![ "Create node_responder that runs tcp listener on 4000 and 'echoer' worker", "wait for messages until stopped", ]); // Create a node with default implementations. let node = node(ctx); // Initialize the TCP transport. let tcp_transport = node.create_tcp_transport().await?; // Create an echoer worker. node.start_worker("echoer", Echoer).await?; // Create a TCP listener and wait for incoming connections. let listener = tcp_transport .listen("127.0.0.1:4000", TcpListenerOptions::new()) .await?; // Allow access to the Echoer via TCP connections from the TCP listener. node.flow_controls() .add_consumer("echoer", listener.flow_control_id()); Ok(node) }


Ejecutemos este ejemplo para ver qué hace 🎉.


En su aplicación de terminal, ejecute el siguiente comando. Tenga en cuenta que OCKAM_LOG=none se usa para deshabilitar la salida de registro de la biblioteca Ockam. Esto se hace para que la salida del ejemplo sea más fácil de leer.


 cargo run --example 04-routing-over-two-transport-hops


Esto debería producir una salida similar a la siguiente. Nuestro programa de ejemplo crea una ruta que atraviesa múltiples nodos y transportes TCP desde la app hasta el echoer y enruta nuestro mensaje a través de ellos 🚀.



Resultado de ejecutar 04-routing-over-two-transport-hops

Próximos pasos

El enrutamiento y los transportes de Ockam son extremadamente potentes y flexibles. Son una de las características clave que permiten implementar los canales seguros de Ockam. Al superponer los canales seguros de Ockam y otros protocolos sobre el enrutamiento de Ockam, podemos proporcionar garantías de extremo a extremo sobre topologías de transporte arbitrarias que abarcan muchas redes y nubes.


En una publicación de blog futura, cubriremos los canales seguros de Ockam y cómo se pueden usar para proporcionar garantías de extremo a extremo sobre topologías de transporte arbitrarias. ¡Así que estad atentos!


Mientras tanto, aquí hay algunos buenos puntos de partida para aprender más sobre Ockam:



También publicado aquí.