Blog de Óscar

El Ingeniero de Sistemas Exóticos

ZeroTier

Recientemente gracias a unos comentarios vertidos en el canal de Telegram de Madrid DevOps he conocido ZeroTier, un software de VPN que va un paso mas allá en cuanto a sencillez y potencia se refiere.

El empezar a usar este software no puede ser mas trivial. Nos bajamos el binario, creamos una red en el controlador público, lanzamos el demonio, y nos unimos a la red con el comando zerotier-cli join <network>. Si este proceso lo realizamos en dos o mas equipos automáticamente tenderemos operativa una red privada entre ellos, sin requerir de nada mas, ni apertura de puertos, ni tediosas configuraciones de cortafuegos, nada, con disponer de conexión a Internet es suficiente. Y además todo esto es software libre. ¡Un chollo!

Cuando todo lo que reluce no es oro

Pese a que, como he citado en el párrafo anterior, estamos ante una solución de software libre, que sea libre no quiere decir que sea gratis. Y es que tenemos una limitación en el controlador público de manera que no podemos tener mas de 100 dispositivos conectados en una red.

Para el común de los mortales, esta limitación es grande. No tenemos tantos dispositivos en casa. Yo, que me considero una persona bastante tecnológica, en estos momentos no llego a los 10 conectados, por lo que la verdad es que el límite es bastante alto. Pero, aún así, hay un tema que me hacía rondar la mosca detrás de la oreja. No se trata del precio, si el producto es bueno, se paga gustosamente, además, $29 al mes no me parece algo excesivo para el trabajo que tiene detrás la solución. No, para mi el problema era ¿Y que pasa si el día de mañana esta gente decide cerrar completamente el controlador? Si adopto la solución me gusta disponer de alternativas. Y como tal de eso voy a hablaros, de como montarte tú tu propio controlador en tu casa. Porque ya sabemos que el futuro siempre es incierto.

Pasos previos

Lo primero que tenemos que saber es que el binario de zerotier-one puede hacer tanto de controlador como de cliente, por lo que realmente no se necesita de nada mas para montar el sistema.

Una vez arrancado el demonio, lo primero que necesitamos saber es nuestro ID, para ello podemos usar el CLI con el comando zerotier-cli info.

zerotier-cli info
200 info ad1e0ac0b9 1.2.12 ONLINE

Como podemos ver, el identificador en este caso es ad1e0ac0b9. Las direcciones de red ZeroTier tienen un formato de 64bit donde los primeros 40bit (10 dígitos hexadecimales) identifican al controlador de red y los 24bit (6 dígitos hexadecimales) restantes identifican a la red dentro del propio controlador. Un controlador puede tener dadas de alta un número grande de redes (nada mas y nada menos que 24bit), pero se aconseja que sea una máquina dedicada. Si sois amigos de Docker, se puede perfectamente montar un controlador dentro de un contenedor.

Para montar y modificar redes se debe hacer por medio de peticiones a la API del del controlador. Como todas las peticiones deben ser autenticadas, necesitamos el valor del authtoken.secret que hay en /var/lib/zerotier-one/ y que debemos enviar como cabecera X-ZT1-Auth.

Para ver que efectivamente esta operativo podemos lanzar la siguiente petición.

curl -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 "http://localhost:9993/controller"

A la cual nos responderá con algo similar a esto.

{
 "controller": true,
 "apiVersion": 4,
 "clock": 1554468086166,
 "databaseReady": true
}

Lo que nos indica que el controlador esta listo para ser utilizado.

Crear tu red

Para crear tu red lanzamos la siguiente petición.

CONTROLLER_ID=$(zerotier-cli info | cut -d' ' -f 3)
curl -X POST \
 -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 -d '{"name":"love death and robots"}' \
 "http://localhost:9993/controller/network/${CONTROLLER_ID}______"

Como vemos se le pasa el parámetro nombre a la red en un JSON. Esto es opcional, se le podría pasar un JSON vacío {}, pero es aconsejable ponerle etiqueta a todas las redes que se creen para poder identificarlas de manera sencilla. A su vez en la sección del identificador de la red le estamos pasando ______. Esto es para que nos genere un identificador aleatorio que no colisione con otro que ya pueda existir. Si quisiéramos podríamos indicarle de manera manual nosotros el identificador (6 dígitos hexadecimales) para crear una red con un ID conocido. En cualquier caso en el retorno del POST siempre nos vendrá el ID, como podemos ver a continuación.

{
 "authTokens": [
  null
 ],
 "capabilities": [],
 "creationTime": 1554193849768,
 "enableBroadcast": true,
 "id": "ad1e0ac0b9a43574",
 "ipAssignmentPools": [],
 "mtu": 2800,
 "multicastLimit": 32,
 "name": "love death and robots",
 "nwid": "ad1e0ac0b9a43574",
 "objtype": "network",
 "private": true,
 "remoteTraceLevel": 0,
 "remoteTraceTarget": null,
 "revision": 1,
 "routes": [],
 "rules": [
  {
   "not": false,
   "or": false,
   "type": "ACTION_ACCEPT"
  }
 ],
 "tags": [],
 "v4AssignMode": {
  "zt": false
 },
 "v6AssignMode": {
  "6plane": false,
  "rfc4193": false,
  "zt": false
 }
}

Una ver que disponemos del ID (en este ejemplo ad1e0ac0b9a43574), todas las peticiones que se realicen para modificar la red deben incluir dicho identificador.

Si quisiéramos listar todas las redes que tenemos montadas usamos la siguiente petición.

curl -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 "http://localhost:9993/controller/network"

Lo cual nos retorna una lista de IDs.

["ad1e0ac0b9a43574"]

Para ver de nuevo los parámetros de la red, usamos el endpoint /controller/network/<network ID>.

curl -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574"

Modificar tu red

Una vez creada la red podemos modificarla enviando POST a su endpoint /controller/network/<network ID>, con los JSON de lo que queremos modificar. Hay un par de parámetros que resultan interesantes. El primero es para establecer el rango de IPs de la misma.

curl -X POST \
 -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 -d '{"ipAssignmentPools":[{"ipRangeStart":"192.168.69.1","ipRangeEnd":"192.168.69.254"}]}' \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574"

Y el segundo para establecer la ruta lan de dicha red (a la cual no se le asigna via puesto que es conexión directa).

curl -X POST \
 -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 -d '{"routes":[{"target": "192.168.69.0/24", "via":""}]}' \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574"

Cada petición POST que realizamos nos retorna el JSON completo con la configuración que tiene la red, debemos ver que efectivamente se están aplicando los cambios.

Añadir miembros a la red

Una vez creada la red, podemos unirnos a ella con el cli haciendo join.

zerotier-cli join ad1e0ac0b9a43574

Por defecto las redes son privadas, esto quiere decir que para que un miembro pueda entrar tiene que ser autorizado. Para poder autorizarlo obtenemos primero la lista de miembros atacando al endpoint /controller/network/<network ID>/member.

curl -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574/member"

Esto nos tiene que devolver una lista de identificadores.

{"ad1e0ac0b9":1}

Una vez que tenemos el identificador del miembro podemos tanto ver sus parámetros como realizar cambios en el endpoint /controller/network/<network ID>/member/<address>. Para ver los parámetros.

curl -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574/member/ad1e0ac0b9"

Lo cual nos retorna.

{
 "activeBridge": false,
 "address": "ad1e0ac0b9",
 "authorized": false,
 "capabilities": [],
 "creationTime": 1554195123254,
 "id": "ad1e0ac0b9",
 "identity": "identificadorabsurdamentelargo",
 "ipAssignments": [],
 "lastAuthorizedCredential": null,
 "lastAuthorizedCredentialType": null,
 "lastAuthorizedTime": 0,
 "lastDeauthorizedTime": 0,
 "noAutoAssignIps": false,
 "nwid": "ad1e0ac0b9a43574",
 "objtype": "member",
 "remoteTraceLevel": 0,
 "remoteTraceTarget": null,
 "revision": 1,
 "tags": [],
 "vMajor": -1,
 "vMinor": -1,
 "vProto": -1,
 "vRev": -1
}

Para autorizarlo.

curl -X POST \
 -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 -d '{"authorized":true}' \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574/member/ad1e0ac0b9"

Esto funciona igual que la modificación de la red. Cada petición POST nos retorna el estado completo.

Otra cosa interesante que se le puede configurar al miembro es su IP o IPs asignadas.

curl -X POST \
 -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" \
 -d '{"ipAssignments":["192.168.69.69"]}' \
 "http://localhost:9993/controller/network/ad1e0ac0b9a43574/member/ad1e0ac0b9"

Conclusión

Como podemos ver, no es necesario utilizar el controlador público de ZeroTier si no queremos ya que es bastante sencillo montarnos nuestra propia fiesta en casa. Aunque también debemos tener en cuenta la comodidad que ofrece el usar dicho controlador.

Por último comentar que existe una documentación bastante parca de la API en el proyecto de GitHub. Es a todas luces muy básica, pero espero que con lo que os he comentado y con unas cuantas pruebas de ensayo y error os sirva para poder llegar al objetivo que buscáis.