Writing Custom Vars Generators

Declare a vars generator, generate a hashed root password, deploy it to a machine, change as needed.

This guide covers the full clan vars workflow:

  1. Declare a generator in the machine's NixOS configuration.
  2. Inspect the status of variables using the Clan CLI.
  3. Generate variables interactively.
  4. Observe the changes made to your repository.
  5. Update the machine configuration.
  6. Change the root password when needed.

For a detailed API reference, see the vars module documentation.

Declare the generator

In this example, a vars generator is used to:

  • prompt the user for the password
  • run the required mkpasswd command to generate the hash
  • store the hash in a file
  • expose the file path to the NixOS configuration

Create a new Nix file root-password.nix with the following content and import it into your configuration.nix

{ config, pkgs, ... }:
{

  clan.core.vars.generators.root-password = {
    # prompt the user for a password
    # (`password-input` being an arbitrary name)
    prompts.password-input.description = "the root user's password";
    prompts.password-input.type = "hidden";
    # don't store the prompted password itself
    prompts.password-input.persist = false;
    # define an output file for storing the hash
    files.password-hash.secret = true;
    # define the logic for generating the hash
    script = ''
      cat $prompts/password-input | mkpasswd > $out/password-hash
    '';
    # the tools required by the script
    runtimeInputs = [ pkgs.mkpasswd ];
  };

  # ensure users are immutable (otherwise the following config might be ignored)
  users.mutableUsers = false;
  # set the root password to the file containing the hash
  users.users.root.hashedPasswordFile =
    # clan will make sure, this path exists
    config.clan.core.vars.generators.root-password.files.password-hash.path;
}

Inspect the status

Executing clan vars list, you should see the following:

$ clan vars list my-machine
root-password/password-hash: <not set>

...indicating that the value password-hash for the generator root-password is not set yet.

Generate the values

This step is not strictly necessary, as deploying the machine via clan machines update would trigger the generator as well.

To run the generator, execute clan vars generate for your machine

$ clan vars generate my-machine
Enter the value for root-password/password-input (hidden):

After entering the value, the updated status is reported:

Updated var root-password/password-hash
  old: <not set>
  new: $6$RMats/YMeypFtcYX$DUi...

Observe the changes

With the last step, a new file was created in your repository: vars/per-machine/my-machine/root-password/password-hash/value

If the repository is a git repository, a commit was created automatically:

$ git log -n1
commit ... (HEAD -> main)
Author: ...
Date:   ...

    vars: update via generator root-password (machine: my-machine)

Update the machine

clan machines update my-machine

Change the root password

Changing the password can be done via this command. Replace my-machine with your machine.

$ clan vars generate my-machine --generator root-password --regenerate
...
Enter the value for root-password/password-input (hidden):
Input received. Processing...
...
Updated var root-password/password-hash
  old: $6$tb27m6EOdff.X9TM$19N...

  new: $6$OyoQtDVzeemgh8EQ$zRK...

Export and import vars

The clan vars export and clan vars import commands allow creating a full unencrypted dump of all variables (public and secret) and restoring them. This is useful for:

  • Migrating between secret backends (e.g. from sops to age)
  • Creating backups of all variables

Export

Export all vars for all machines to a folder:

$ clan vars export /tmp/vars-dump

The output folder must not already exist. The folder structure groups variables by their placement (per-machine, shared across machines, or — for upcoming flake-level generators — per export key). Within each placement bucket there is one directory per generator and one file per variable:

/tmp/vars-dump/
  per-machine/
    machine1/
      root-password/password-hash
      root-password/.validation-hash
      ssh-keys/pubkey
      ssh-keys/privkey
    machine2/
      root-password/password-hash
      ...
  shared/
    wifi/psk
  per-export/
    <exports-key>/
      <generator>/<file>

Each generator directory also carries its .validation-hash, so that vars restored by clan vars import are not considered outdated and regenerated by the next clan vars generate.

!!! warning The exported files contain unencrypted secrets. The dump is created with owner-only permissions (0700 directories, 0600 files), but it is still plaintext: handle the export folder with care and delete it after use.

Import

Import vars from a previously exported folder:

$ clan vars import /tmp/vars-dump

Each variable is set through the currently configured secret backend. This means if you changed the backend configuration between export and import, the vars will be re-encrypted with the new backend.

Vars present in the store but missing from the dump are left untouched, and the previous backend's encrypted copies are not removed — delete them manually after verifying the migration.

Migrating between secret backends

To migrate all vars from one secret backend to another:

# 1. Export all vars (decrypted)
$ clan vars export /tmp/vars-dump

# 2. Change the secret backend in your NixOS configuration
#    e.g. set clan.core.vars.settings.secretStore = "age"

# 3. Import vars into the new backend
$ clan vars import /tmp/vars-dump

# 4. Clean up the unencrypted dump
$ rm -rf /tmp/vars-dump