Past few days I have been working on an ARM template to deploy a TailScale VM in Azure. There’s nothing fancy in it as it’s simply an Ubuntu VM that automatically has TailScale installed on it via cloud-init. I do however create a virtual network (vnet), a subnet, a key vault with a key, a disk encryption set to encrypt the disks for the VM, an admin user (named after the VM, with an “admin” suffix), and also firewall rules to block all incoming access to the subnet (except a UDP port for TailScale)… so it saves you a few clicks. Moreover you can’t access the TailScale VM publicly, so it and the Azure network behind it can only be accessed via your TailScale nework… which is nice!
The template auto joins the TailScale VM to your TailScale network by way of a pre-authentication key you should generate from the TailScale admin portal and feed as one of the paramters. It also takes as input subnets which you can route this node – essentially these are your subnets in Azure and so once this VM is deployed you can connect to your Azure subnets from any of your other machines that have TailScale installed. You don’t need to resort to an Azure Site-to-Site or Point-to-Site VPN, or a bastion host, or even a WireGuard VM which you must then hook all your other machines too – TailScale takes care of all that.
What I do is once this VM is up and running in Azure I then do vnet peering from the TailScale vnet to all my other vnets (whose address space is what I pass this VM in the first place to route) and so I can connect to all my Azure resources.
To give an example: say when I deploy this template I give it an address space of 192.168.64.0/24. This is the vnet & subnet address space, in Azure, of the TailScale VM. I can also give it 192.168.64.0/24, 10.16.0.0/16, and 10.17.0.0/16 as subnets to route via this node – the latter two being address spaces of my vnets in Azure. Now all my other TailScale nodes now route traffic to these subnets via this TailScale VM. Neat.
Here’s the GitHub repo with this template: https://github.com/rakheshster/arm-tailscale-ubuntu
Since I have a cloud-init script it needs to be updated and passed on to the ARM template. One could upload the modified cloud-init file somewhere and point to it in the ARM template, but Microsoft has a script (Bash, PowerShell) that creates a storage account, uploads the cloud-init file to that, and passes a link to it to the template when deploying. I didn’t know of this Bash script so I had actually made one of my own and that’s what I have included in this repo. So essentially all one needs to do is clone this repo, modify the
cloud-init.txt and parameters file in the
artifacts folder, and if using Bash type the following:
./deploy.sh -g <resourceGroup> -d artifacts -l <location>
# replace <location> and <resourceGroup> accordingly
# if <resourceGroup> exists then no need to specify <location>
Or if PowerShell:
/Deploy-AzTemplate.ps1 -ResourceGroupName <resourceGroup> -ArtifactStagingDirectory artifacts -Location <location>
The GitHub repo has a bit more info on what parameters need modifying etc. so I won’t repeat that here. Also, you will have to have logged in to Azure already; else the scripts will error out.
Alternatively I made an Azure DevOps pipeline one can use to deploy this. To do that: fork the repo, added it to your Azure DevOps pipeline, and run from there (again, I assume you have connect DevOps to Azure). This gives a nice UI to fill in the required parameters:
Fill them up, click Run, and you are done. It takes about 3 mins and you have the VM deployed to Azure. Another 2 minutes and it will appear in your TailScale network.
In either case once the VM appears in TailScale be sure to authorize the routes and also (optionally) disable key expiry.