soanm
is a dead-simple tool for easily configuring new UNIX machines, with
almost zero prerequisites on the target machine. All it needs is curl
.
Right now it works on MacOS and Linux on both aarch64 and x86_64, and OpenBSD on x86_64. These are the systems I typically use and can easily build on, but porting it to new platforms is as simple as compiling a new static Rust binary and adding it to the release on Github. If you want support for a new platform, add an issue and I'll be happy to get it ported.
When you install a new operating system on some machine, whether it's a server, a laptop, a desktop, or a VM, it can be a hassle to get to the point of feeling comfortable on that machine: You use dozens of tools that need to be installed, and many of these need to be configured. You need to set up Tailscale, and SSH keys, and API keys.
Wouldn't it be great if you could just do this all at once, in a totally custom way? Well, now you can!
You'll need two computers: One "sponsor", which is equipped with any resources needed for provisioning the other machine (the "enrollee"). For example, if you want your new machines to have access to GitHub, your sponsor computer should have the ability to add ssh keys to GitHub.
To configure soanm
, you'll also want a directory that describes the configuration
phases: It should have a subdirectory enroll
, with programs that will be run
on the enrollee, a subdirectory sponsor
with programs that will be run on the
sponsor, and a subdirectory results
, where output from the enrollee will be
stored. There must be the same number of programs in the sponsor
and enroll
directories, and these all must be set as executable.
Once you have created this configuration directory, the provisioning process is
begun by running soanm sponsor [conf_directory]
. This will print a
corresponding command for you to run on the enrollee (this command will include
a secret used to securely connect the computers to one another).
The program pairs will be run in order, sorted by filename. For each pair, the
sponsor
program is run first, and its output is sent over a Magic
Wormhole. That output is
then used as the input to the corresponding enroll
program. The enroll
output, in turn, is sent back to the sponsor and saved in the results
directory, where it can be used by subsequent sponsor
programs.
Note that on the sponsor machine, the stdin of the configuration programs is inherited from the top-level programs, allowing for user input. And on both sponsor and enrollee machines, stderr is printed to the corresponding terminal.
The sponsor machine needs a relatively recent rust version, and a directory
with a subdirectory for the sponsor
programs, one for the enroll
programs,
and an empty one called results
.
cargo install soanm
soanm sponsor config_dir
This will print out a command, which should be run on the enrollee.
Under some assumptions, it should be relatively safe to use this tool to pass secrets around.
You obviously have to trust that the release binaries provided here are not malicious. I hereby stake my reputation on the claim that I built them myself from the sources contained in this repository, which (of course) does not contain malicious code. But if you don't trust me, or the tree of dependencies I used to build these binaries, you should verify that the release binaries look safe. This also requires trusting GitHub to faithfully serve binaries that have been uploaded, as well as trusting that no one has unauthorized access to my Github account. For obvious reasons I try hard to protect my Github account, and I promise that I will never hand control of this repository to anyone else.
You also need to trust the magic-wormhole
protocol. We use the default
magic-wormhole rendezvous server (ws://relay.magic-wormhole.io:4000/v1
) to
establish a secure peer-to-peer connection, over which files are transmitted.
We default to using a 128-bit passphrase (16 words) for the initial rendezvous,
though this is configurable on the sponsor command line. We have chosen to use
very long passphrases by default, since we want an extremely low probability of
being man-in-the-middled, and since the usual scenario is that you're
copy/paste-ing the passphrase from one shell to another.
There are lots of tools that could be used for parts of this task. Foremost
among them is Nix. If you only use Linux, MacOS, or
maybe FreeBSD, Nix can do everything you need: Just write a quick script that
installs nix, grabs your nix configuration, and instantiates it into your
profile, and then you can curl -L [myscript] | bash
to magically set
everything up. But if you use any other platforms, like (say) OpenBSD, Nix
isn't currently viable.
Other possibilities:
- You could write a script that uses SCP to send your files and configuration scripts to the remote host, and then runs them. This would work fine, but it requires that you have SSH access to the new host, which isn't typically the case by default on a new laptop, for example.
- You could use Ansible, or Puppet, or Terraform. But then you need to have the
tool installed on the host, and of course you need to learn how to use these
systems, which can be complicated.
soanm
doesn't require anything fancier than shell scripting, and lets you write code in any language you want as long as you ensure it's installed properly by an earlier stage. With most of these other tools, you'll likely need an additional tool for managing your secrets, while withsoanm
you can pipe them safely to the new host from the old one. - You could use a dotfiles manager, like
chezmoi
. These typically won't install packages for you, or run arbitrary code, though.
You can easily combine soanm
with any of these other methods, if that's what
you'd like to do.
There are probably a thousand ways to do this kind of task. I couldn't find one I liked, so I wrote one that I do. Maybe you'll like it too.