Skip to content

Advanced Vars Examples

This guide demonstrates complex, real-world patterns for the vars system. For basic usage, see the Getting Started guide.

Certificate Authority with Intermediate Certificates

This example shows how to create a complete certificate authority with root and intermediate certificates using dependencies.

{
  # Generate root CA (not deployed to machines)
  clan.core.vars.generators.root-ca = {
    files."ca.key" = {
      secret = true;
      deploy = false;  # Keep root key offline
    };
    files."ca.crt".secret = false;
    runtimeInputs = [ pkgs.step-cli ];
    script = ''
      step certificate create "My Root CA" \
        $out/ca.crt $out/ca.key \
        --profile root-ca \
        --no-password \
        --not-after 87600h
    '';
  };

  # Generate intermediate key
  clan.core.vars.generators.intermediate-key = {
    files."intermediate.key" = {
      secret = true;
      deploy = true;
    };
    runtimeInputs = [ pkgs.step-cli ];
    script = ''
      step crypto keypair \
        $out/intermediate.pub \
        $out/intermediate.key \
        --no-password
    '';
  };

  # Generate intermediate certificate signed by root
  clan.core.vars.generators.intermediate-cert = {
    files."intermediate.crt".secret = false;
    dependencies = [
      "root-ca"
      "intermediate-key"
    ];
    runtimeInputs = [ pkgs.step-cli ];
    script = ''
      step certificate create "My Intermediate CA" \
        $out/intermediate.crt \
        $in/intermediate-key/intermediate.key \
        --ca $in/root-ca/ca.crt \
        --ca-key $in/root-ca/ca.key \
        --profile intermediate-ca \
        --not-after 8760h \
        --no-password
    '';
  };

  # Use the certificates in services
  services.nginx.virtualHosts."example.com" = {
    sslCertificate = config.clan.core.vars.generators.intermediate-cert.files."intermediate.crt".value;
    sslCertificateKey = config.clan.core.vars.generators.intermediate-key.files."intermediate.key".path;
  };
}

Multi-Service Secret Sharing

Generate secrets that multiple services can use:

{
  # Generate database credentials
  clan.core.vars.generators.database = {
    share = true;  # Share across machines
    files."password" = { };
    files."connection-string" = { };
    prompts.dbname = {
      description = "Database name";
      type = "line";
    };
    script = ''
      # Generate password
      tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32 > $out/password

      # Create connection string
      echo "postgresql://app:$(cat $out/password)@localhost/$prompts/dbname" \
        > $out/connection-string
    '';
  };

  # PostgreSQL uses the password
  services.postgresql = {
    enable = true;
    initialScript = pkgs.writeText "init.sql" ''
      CREATE USER app WITH PASSWORD '${
        builtins.readFile config.clan.core.vars.generators.database.files."password".path
      }';
    '';
  };

  # Application uses the connection string
  systemd.services.myapp = {
    serviceConfig.EnvironmentFile = 
      config.clan.core.vars.generators.database.files."connection-string".path;
  };
}

SSH Host Keys with Certificates

Generate SSH host keys and sign them with a CA:

{
  # SSH Certificate Authority (shared)
  clan.core.vars.generators.ssh-ca = {
    share = true;
    files."ca" = { secret = true; deploy = false; };
    files."ca.pub" = { secret = false; };
    runtimeInputs = [ pkgs.openssh ];
    script = ''
      ssh-keygen -t ed25519 -N "" -f $out/ca
      mv $out/ca.pub $out/ca.pub
    '';
  };

  # Host-specific SSH keys
  clan.core.vars.generators.ssh-host = {
    files."ssh_host_ed25519_key" = {
      secret = true;
      owner = "root";
      group = "root";
      mode = "0600";
    };
    files."ssh_host_ed25519_key.pub" = { secret = false; };
    files."ssh_host_ed25519_key-cert.pub" = { secret = false; };
    dependencies = [ "ssh-ca" ];
    runtimeInputs = [ pkgs.openssh ];
    script = ''
      # Generate host key
      ssh-keygen -t ed25519 -N "" -f $out/ssh_host_ed25519_key

      # Sign with CA
      ssh-keygen -s $in/ssh-ca/ca \
        -I "host:${config.networking.hostName}" \
        -h \
        -V -5m:+365d \
        $out/ssh_host_ed25519_key.pub
    '';
  };

  # Configure SSH to use the generated keys
  services.openssh = {
    hostKeys = [{
      path = config.clan.core.vars.generators.ssh-host.files."ssh_host_ed25519_key".path;
      type = "ed25519";
    }];
  };
}

WireGuard Mesh Network

Create a WireGuard configuration with pre-shared keys:

{
  # Generate WireGuard keys for this host
  clan.core.vars.generators.wireguard = {
    files."privatekey" = {
      secret = true;
      owner = "systemd-network";
      mode = "0400";
    };
    files."publickey" = { secret = false; };
    files."preshared" = { secret = true; };
    runtimeInputs = [ pkgs.wireguard-tools ];
    script = ''
      # Generate key pair
      wg genkey > $out/privatekey
      wg pubkey < $out/privatekey > $out/publickey

      # Generate pre-shared key
      wg genpsk > $out/preshared
    '';
  };

  # Configure WireGuard
  networking.wireguard.interfaces.wg0 = {
    privateKeyFile = config.clan.core.vars.generators.wireguard.files."privatekey".path;

    peers = [{
      publicKey = "peer-public-key-here";
      presharedKeyFile = config.clan.core.vars.generators.wireguard.files."preshared".path;
      allowedIPs = [ "10.0.0.2/32" ];
    }];
  };
}

Conditional Generation Based on Machine Role

Generate different secrets based on machine configuration:

{
  clan.core.vars.generators = lib.mkMerge [
    # All machines get basic auth
    {
      basic-auth = {
        files."htpasswd" = { };
        prompts.username = {
          description = "Username for basic auth";
          type = "line";
        };
        prompts.password = {
          description = "Password for basic auth";
          type = "hidden";
        };
        runtimeInputs = [ pkgs.apacheHttpd ];
        script = ''
          htpasswd -nbB "$prompts/username" "$prompts/password" > $out/htpasswd
        '';
      };
    }

    # Only servers get API tokens
    (lib.mkIf config.services.myapi.enable {
      api-tokens = {
        files."admin-token" = { };
        files."readonly-token" = { };
        runtimeInputs = [ pkgs.openssl ];
        script = ''
          openssl rand -hex 32 > $out/admin-token
          openssl rand -hex 16 > $out/readonly-token
        '';
      };
    })
  ];
}

Backup Encryption Keys

Generate and manage backup encryption keys:

{
  clan.core.vars.generators.backup = {
    share = true;  # Same key for all backup sources
    files."encryption.key" = {
      secret = true;
      deploy = true;
    };
    files."encryption.pub" = { secret = false; };
    runtimeInputs = [ pkgs.age ];
    script = ''
      # Generate age key pair
      age-keygen -o $out/encryption.key 2>/dev/null

      # Extract public key
      grep "public key:" $out/encryption.key | cut -d: -f2 | tr -d ' ' \
        > $out/encryption.pub
    '';
  };

  # Use in backup service
  services.borgbackup.jobs.system = {
    encryption = {
      mode = "repokey-blake2";
      passCommand = "cat ${config.clan.core.vars.generators.backup.files."encryption.key".path}";
    };
  };
}

Tips and Best Practices

  1. Use dependencies to build complex multi-stage generations
  2. Share generators when the same secret is needed across machines
  3. Set appropriate permissions for service-specific secrets
  4. Use prompts for user-specific values that shouldn't be generated
  5. Combine secret and non-secret files in the same generator when they're related
  6. Use conditional generation with lib.mkIf for role-specific secrets