Add vmtests that boot pairs of gokrazy VMs whose tailscale and tailscaled are minimal builds and check that IP traffic flows between them over WireGuard, so we notice if a minimal build stops doing its one job: build_dist.sh --extra-small (direct path through NATs), that minus NAT traversal (DERP across NATs, direct on a shared LAN), and DERP-only. They found that "tailscale up" built with ts_omit_ipnbus returned before calling Start or EditPrefs, making it a no-op. Fix that, and have it wait for the Running state by polling tailscaled's status instead of watching the IPN bus, so scripts can rely on it as with normal builds. The extra-small feature list moves to featuretags.ExtraSmall so build_dist.sh (via a new "featuretags --extra-small") and vmtest share it. The gokrazy builder gains --output and --go-build-tags flags to build the variant images, and natlabprep --gokrazy prebuilds them all for CI. Updates #13038 Updates #12614 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I0caa2c7b3adf2399da09b6d07a942f1dc34e8486
Tailscale Appliance Gokrazy Image
This is (as of 2024-06-02) a WORK IN PROGRESS (pre-alpha) experiment to package Tailscale as a Gokrazy appliance image for use on both VMs (AWS, GCP, Azure, Proxmox, ...) and Rasperry Pis.
See https://github.com/tailscale/tailscale/issues/1866
Overview
It makes a ~70MB image (about the same size as
tailscale-setup-full-1.66.4.exe and smaller than the combined
Tailscale Android APK) that combines the Linux kernel and Tailscale
and that's it. Nothing written in C. (except optional busybox for
debugging) So no operating system to maintain. Gokrazy has three
partitions: two read-only ones (one active at a time, the other for
updates for the next boot) and one optional stateful, writable
partition that survives upgrades (/perm/)
Initial bootstrap configuration of this appliance will be over either serial or configuration files (auth keys, subnet routes, etc) baked into the image (for Raspberry Pis) or in cloud-init/user-data (for AWS, etc). As of 2024-06-02, AWS user-data config files work.
Quick start
Install dependencies:
$ brew install qemu e2fsprogs
Build + launch:
$ make qemu
That puts serial on stdio. To exit the serial console and escape to
the qemu monitor, type Ctrl-a c. Then type quit in the monitor to
quit.
Building
make image to build just the image (tsapp.img), without uploading it.
UTM
You can also use UTM, but the qemu path above is easier. For UTM, see the UTM instructions.
AWS
Build an AMI
go run build.go --bucket=your-S3-temp-bucket to build an AMI.
Credentials come from the AWS SDK's default chain, so authenticate any way it
recognizes: aws sso login, aws configure, an AWS_PROFILE,
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY env vars, or
aws-vault exec <profile> -- go run build.go --bucket=... (aws-vault injects
temporary credentials as env vars). If no credentials are found the build stops
with a message telling you how to log in.
Creating an instance
When creating an instance, you need a Nitro machine type to get a
virtual serial console. Notably, that means the t2.* instance types
that AWS pushes as a free option are not new enough. Use t3.* at least.
As of 2024-06-02 this builder tool only supports x86_64 (arm64 should be trivial and will come soon), so don't use a Graviton machine type.
To connect to the serial console, you can either use the web console, or use the CLI like:
$ aws ec2-instance-connect send-serial-console-ssh-public-key --instance-id i-0b4a0eabc43629f13 --serial-port 0 --ssh-public-key file:///your/home/.ssh/id_ed25519.pub --region us-west-2
{
"RequestId": "a93b0ea3-9ff9-45d5-b8ed-b1e70ccc0410",
"Success": true
}
$ ssh i-0b4a0eabc43629f13.port0@serial-console.ec2-instance-connect.us-west-2.aws
Configuring the appliance
The appliance's tailscaled runs with -config=optional:vm:user-data, so a
single AMI supports two ways of joining a tailnet:
-
Declarative (user-data): put a Tailscale config (the
alpha0HuJSON format) in the instance's user-data and the node configures itself on first boot. The minimal config is just an auth key:{ "Version": "alpha0", "AuthKey": "tskey-auth-..." }A config present in user-data locks the CLI (
tailscale set/upare rejected) unless it sets"Locked": false. Add"RemoteConfig": trueto hand full remote management of the node to the tailnet admin (seePrefs.RemoteConfig) — appropriate for admin-owned fleet devices. -
Interactive (serial console): launch the AMI with no user-data. The
optional:prefix means the missing config is not an error, sotailscaledboots unconfigured and you can enroll it over the serial console (connect as above, then runtailscale upand open the printed login URL).
To require config instead (fail to boot if none is present), build an image
whose tailscaled uses -config=vm:user-data without the optional: prefix.