In a previous post I wrote about using ZeroTier for my homelab and mentioned I ended up writing two scripts:
one for joining a network and authorizing the new device
another for creating DNS entries in DNSMASQ for DNS lookup
This first part will focus on how I join my new servers to my ZeroTier labnetwork. For more information about ZeroTier in general go read my other post that go in much more detail about that. Part two about DNS for ZeroTier will soon be available.
Lets get started!
joinnetwork
This script will automatically join a new device (node/member) to a ZeroTier network. It can be used standalone or with any provisioning, configuration management, or deployment tools. The Network ID must be specified to join the network. If an API Token is specified the script will also authorize the member. The script can also autorize an existing member that already have joined but still haven’t been autorized by a network owner/admin. The script depends on curl, jq and zerotier-one to be installed for it to work, though it will check for these to be installed at runtime.
The whole idea is to automatically join and authorize a new member to a network so it makes absolute most sense to run it with the --api option. Just running it with --network is the same as just junning zerotier-cli join directly from the shell.
When runnig the script it will right of the bat check if the prequsites a taken care of and preform a simple syntax check for <API-TOKEN> and <NETWORK-ID>. If anything is wrong or missing it will inform you. Next the script will check if the the device (Node ID) is already a member or not. New devices will via zerotier-cli join be joined and if already a member the script will then exit and tell if the member is authorized or not (outputting assigned IP if authorized). If you have specified <API-TOKEN> the script will not just join a member but via curl call the API of the network controller to authorize the member. A existing network member will just be authorized when <API-TOKEN> is specified. Common for both senarios is that the script will exit and output the assigned ZeroTier IP address for the network. NOTE: The script tests via the local zerotier-cli utility when authorization have registered on the client before proceeding. It would be much faster to run these tasks asynchronous, but as I need to use the assigned ZeroTier IP right after the script is done, I wrote it so I could trust the network to be available for the subsequent tasks.
Usage: To join and authorize a device to a network just run:
Runtime options can be set in whatever order you prefer. They can be listed by running joinnetwork --help:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-a=, --api= Specifies the ZeroTier API Token (account) to authorize the new device member.
-u=, --url= URL to a standalone ZeroTier network controller API. Default value is https://my.zerotier.com/api as this is the public network controller hosted by ZeroTier. NOTE: This argument is only for those who run a standalone ZeroTier network controller. -n=, --network= The ZeroTier network (Network ID) to join.
-m=, --member= Set the device member shortname for the member on the ZeroTier network. If not set the unique device Node ID (10-digit alphanumeric) is configured as member shortname.
-d=, --description= Set the device member description field for this client.
Alternatively just edit the script variables in the section at line 78 to avoid the need for any runtime parameters.
NETWORK ID is the Network ID you wish to join and must be provided by an admin or existing member. Existing members can see the desired Network ID on the my.zerotier.com Network page or via the zeroctier-cli listnetworks command.
APIKEY is your API Access Token from the my.zerotier.com Account page. When specified this token will be used to authorize the new member.
It’s possible to check if the member is authorized via the API:
1 2 3 4
# First get your NodeID (some OS require sudo here) $ MYID=$(zerotier-cli info | cut -d " " -f 3) #Then call the API $ curl -s -H "Authorization: Bearer <API-TOKEN>" https://my.zerotier.com/api /network/<NETWORK-ID>/member/$MYID | jq '.config.authorized'
A new device wil be joinded to a network and given a proper name and description
A existing member will be Authorized to get proper access and IP assigned.
Cloud-init and the gang I prefer to not overcomplicate tings and for VMs I use cloud-init for initial run conifguration and Ansible for everytning after. As I tend to spin up workloads in diffrent places I very much rely on ZeroTier to even be able to manage or connect these workloads. So it is paramount that the VM is automatically connected to my ZeroTier labnetwork before anything else. I won’t share my entire user-data cloud-config, but here’s a validated example that will install everything needed (zerotier, curl, jq) and then download and execute joinnetwork:
#cloud-config #Remember to validate your YAML config via users: - name:username sudo:ALL=(ALL)NOPASSWD:ALL groups:users,admin,sudo ssh-import-id:gh:UserName shell:/bin/bash apt: primary: - arches:[default] uri:http://mirrors.dotsrc.org/ubuntu/ sources: zerotier.list: # Creates a file in /etc/apt/sources.list.d/ for the sources list entry source:"deb http://download.zerotier.com/debian/bionic bionic main" key:| # Key from https://github.com/zerotier/ZeroTierOne/blob/master/doc/contact%40zerotier.com.gpg -----BEGIN PGP PUBLIC KEY BLOCK----- Comment:GPGTools-https://gpgtools.org
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 =JgAv -----ENDPGPPUBLICKEYBLOCK----- # Install packages on first boot packages: -curl -jq -zerotier-one # run commands. runcmd only runs during the first boot runcmd: -mkdir-p/run/zerotier -curl-shttps://raw.githubusercontent.com/KimTholstorf/zerotier-scripts/master/joinnetwork-o,/run/zerotier/joinnetwork -chmod+x/run/zerotier/joinnetwork -bash/run/zerotier/joinnetwork--api=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX--network=NNNNNNNNNNNNNNNN--member="short-name" final_message:"The system is ready and prepped (took $UPTIME seconds)"
NOTE: If you install the cloud-init package on your system you can validate your YAML config via:
My scripts for ZeriTier is available on github here. If you find a bug or have a feature request please submit a gitbub issue.
I think perhaps that is enough for now :) In my next blog article I’ll go through the getnetworkmembers script that pull all networkmembers in a ZeroTier network and create DNS records in DNSMASQ.