Blog de Óscar

El Ingeniero de Sistemas Exóticos

Mas ZeroTier: Las Lunas

En mi artículo anterior hablaba de la potencia de ZeroTier y sobre como podemos montarnos en casa nuestro propio controlador y así evitar posibles problemas que puedan surgir de usar el controlador público. En esta ocasión hablaré sobre otro elemento de ZeroTier que nos permite independizarnos un poco mas de la red pública, las Lunas.

De la Tierra a la Luna

Cuando desplegamos una red ZeroTier la comunicación entre nodos suele ser directa siempre y cuando los nodos sean capaces de establecer circuitos en sus respectivas NAT. Pero existen casos en los cuales la comunicación directa es imposible. En esos casos es necesario realizar un relay de la conexión, es decir, necesitamos que haya un elemento en el medio que sea alcanzable por ambos nodos que haga de intercomunicador entre ellos. ZeroTier soluciona este problema usando una serie de servidores públicos llamados Planetas que, aparte de actuar como una suerte de DNS para indicar como se pueden alcanzar los nodos, hacen de intermediarios entre los mismos. El problema que puede surgir con esto es que, o bien no nos interesa que nuestros datos (aun estando completamente cifrados) pasen por estos servidores públicos, o bien el rendimiento de los mismos no es tan satisfactorio como quisiéramos. Para ello ZeroTier propone una solución, usar las Lunas.

Las Lunas no son mas que nodos que tienen una dirección conocida de antemano. Por ello para montarlas se requieren máquinas con IPs públicas fijas, ya que simplemente lo que se hace es distribuir este conocimiento entre todos los nodos para que puedan alcanzarlas. De esta manera, los nodos preguntarán antes a las Lunas que a los Planetas para saber como llegar a un nodo dado, y, en caso de no poder alcanzarlo, las usarán como relays.

Cariño, para ti, la Luna

Crear una Luna es un proceso sencillo y realmente no requiere una gran potencia en el nodo, simplemente con disponer de una buena conexión de red es suficiente. Podríamos incluso usar una Raspberry Pi para ello. ZeroTier recomienda montar al menos dos Lunas por red para tener alta disponibilidad (si una cae queda la otra), pero si nuestra red es pequeña y no disponemos de dos nodos podemos vivir perfectamente con una sola siendo conscientes de que, si se cae, pasaremos por los Planetas.

Lo primero que tenemos que hacer es crear lo que se llama la definición del mundo que no es otra cosa que una configuración que indica cuales son los identificadores de las Lunas y cómo se alcanzan. Para ello usamos por un lado el fichero identity.public del nodo que va a pasar a ser Luna (que encontraremos en el directorio /var/lib/zerotier-one) y por otro la herramienta zerotier-idtool para generar el fichero. Con esto llamamos al comando zerotier-idtool initmoon <identity.public de uno de los nodos> de la siguiente manera.

zerotier-idtool initmoon /var/lib/zerotier-one/identity.public >> \
 /var/lib/zerotier-one/moon.json

Esto nos generará un fichero moon.json con un contenido similar al siguiente.

{
  "id": "deadbeef00",
  "objtype": "world",
  "roots": [
    {
      "identity": "deadbeef00:0:34031483094...",
      "stableEndpoints": []
    }
  ],
  "signingKey": "b324d84cec708d1b51d5ac03e75afba501a...",
  "signingKey_SECRET": "ffc5dd0b2baf1c9b220d1c9cb39633f9e21...",
  "updatesMustBeSignedBy": "b324d84cec708d1b51d5ac03e75afba501a...",
  "worldType": "moon"
}

¡OJO! Este fichero debemos almacenarlo siempre en lugar seguro ya que contiene información sensible (llaves privadas).

El identificador del mundo (campo ID) es completamente arbitrario y podría ser cualquier valor de 64bit. Por norma general se suele usar algún ID de cualquiera de los nodos que van a actuar como Lunas.

Editamos el fichero e introducimos la información de como se puede alcanzar este nodo en cuestión. Para ello creamos un nuevo campo de tipo array stableEndpoints donde insertaremos tanto la IP como el Puerto. En el siguiente ejemplo podemos ver que hemos metido una IPv4 y una IPv6, ambas con su correspondiente puerto.

{
  "id": "deadbeef00",
  "objtype": "world",
  "roots": [
    {
      "identity": "deadbeef00:0:34031483094...",
      "stableEndpoints": [ "10.0.0.2/9993","2001:abcd:abcd::1/9993" ]
    }
  ],
  "signingKey": "b324d84cec708d1b51d5ac03e75afba501a...",
  "signingKey_SECRET": "ffc5dd0b2baf1c9b220d1c9cb39633f9e21...",
  "updatesMustBeSignedBy": "b324d84cec708d1b51d5ac03e75afba501a...",
  "worldType": "moon"
}

Si quisiéramos meter mas Lunas en nuestra red simplemente en el objeto roots meteríamos la información de los demás nodos, que sería siempre el identity.public y la forma de alcanzarlo (IP y Puerto). Por ejemplo, si introdujésemos un segundo nodo la configuración seria como sigue.

{
  "id": "deadbeef00",
  "objtype": "world",
  "roots": [
    {
      "identity": "deadbeef00:0:34031483094...",
      "stableEndpoints": [ "10.0.0.2/9993","2001:abcd:abcd::1/9993" ]
    },
    {
      "identity": "feedbeef11:0:83588158384...",
      "stableEndpoints": [ "10.0.0.3/9993","2001:abcd:abcd::3/9993" ]
    }
  ],
  "signingKey": "b324d84cec708d1b51d5ac03e75afba501a...",
  "signingKey_SECRET": "ffc5dd0b2baf1c9b220d1c9cb39633f9e21...",
  "updatesMustBeSignedBy": "b324d84cec708d1b51d5ac03e75afba501a...",
  "worldType": "moon"
}

Debemos tener en cuenta que las direcciones IP que introducimos en este fichero deben ser siempre alcanzables por los nodos para que estos actúen ya que si no se llegase a dichas IPs los nodos conectarían a través de los Planetas.

Una vez finalizada la configuración del fichero JSON procederemos a firmarlo con el comando zerotier-idtool genmoon moon.json. Esto nos generará un fichero 000000deadbeef00.moon (en este caso, ya que el ID cambia) que no contiene llaves secretas pero esta firmado por ellas. Este fichero lo meteremos en un directorio moons.d dentro del directorio de ZeroTier (/var/lib/zerotier-one) y reiniciaremos el servicio. En este momento ya tendremos la Luna configurada.

Sputnik

Ahora que ya tenemos la Luna creada simplemente tenemos que orbitarla, esto es añadir la información de la Luna a los nodos para que sepan que existe y puedan usarla. Esto se puede hacer de dos maneras, o bien copiar el fichero moon en el directorio moons.d de los nodos que queremos que la usen, o bien con el comando zerotier-cli orbit de la siguiente manera.

zerotier-cli orbit deadbeef00 deadbeef00

El primer argumento del comando es el identificador del mundo, que como comente antes se suele utilizar el ID de alguno de las Lunas, y el segundo es el identificador de alguna de las Lunas que componen el mundo. Esto contactara con la Luna en cuestión y se traerá la definición del mundo de la misma siempre y cuando pueda alcanzarla.

Si todo ha sido correcto deberíamos de ver que los nodos designados como Lunas deberían aparecer como MOON en lugar de como LEAF al hacer un zerotier-cli listpeers como en el siguiente ejemplo.

zerotier-cli listpeers
200 listpeers <ztaddr> <path> <latency> <version> <role>
200 listpeers 8841408a2e 107.191.46.210/9993;8364;18395 57 1.1.5 PLANET
200 listpeers deadbeef00 10.0.0.2/9993;8364;3324 39 1.2.12 MOON
200 listpeers feedbeef66 10.1.1.8/9993;19;20 24 1.2.8 LEAF

Conclusión

Como se puede ver, tener Lunas en nuestra red puede ser muy interesante si disponemos de algún nodo que sea siempre alcanzable, con IP fija y buen ancho de banda, sobre todo si nuestros nodos no son capaces de alcanzarse entre si de manera directa y tienen que utilizar algún relay. Ya sea simplemente por seguridad (aunque el tráfico es cifrado nunca esta de más meterle una capa mas), o porque el usar un relay nuestro siempre va a estar menos cargado que uno público. Además como no se requiere una máquina potente podríamos utilizar para esto cualquier solución VPS que, por norma general, no suelen ser muy caras.