1= Fleet Secrets Management System2:order: 134== Overview56Secret management system is a built-in way to deploy secrets to remote hosts, similar to agenix and other systems.78Secrets are encrypted using system's host ssh key (/etc/ssh/ssh_host_ed25519_key), which is not required to build the9remote system/add secret to fleet configuration, fleet users are encrypting secrets using received public key instead,10they don't need the root access to receive the public encryption key.1112== Per-host and shared secrets1314Secrets come in two flavours; both are declared with the same `secrets.<name>` syntax, but in different15scopes:1617Per-host:: declared inside a host's `nixos` block. Generated and encrypted only for that one host.18 Use for things like a machine-specific tokens, or per-peer WireGuard keys.19Shared:: declared at the top-level fleet config with `expectedOwners = [...]`. The same value is20 encrypted independently for every owner. Each owning host must claim it with21 `secrets.<name>.generator = "shared"` in its `nixos` block (the assertion at22 link:../../modules/nixos/secrets.nix[modules/nixos/secrets.nix] enforces this).2324[source,nix]25----26{ config, fleetLib, ... }:27{28 29 secrets."wg-psk" = {30 expectedOwners = [ "alpha" "beta" ];31 generator = fleetLib.mkBase64Bytes { count = 32; };32 33 regenerateOnOwnerAdded = true;34 regenerateOnOwnerRemoved = true;35 };3637 hosts.alpha.nixos = { ... }: {38 39 secrets."alpha-api-token".generator = fleetLib.mkPassword { };4041 42 secrets."wg-psk".generator = "shared";43 };4445 hosts.beta.nixos = { ... }: {46 secrets."wg-psk".generator = "shared";47 };48}49----5051See link:../examples/wireguard.adoc[the WireGuard example] for a fuller example combining both forms.5253== Built-in secret generators5455Fleet ships a set of generators in link:../../lib/default.nix[`fleetLib`] covering the common cases.56Pass them directly as `generator` (shown here as shared secrets; the same calls work in a per-host57`nixos.secrets.<name>.generator` block - just drop `expectedOwners`):5859[source,nix]60----61{ config, lib, fleetLib, ... }:62{63 secrets = {64 65 db-password = {66 expectedOwners = [ "db" ];67 generator = fleetLib.mkPassword { };68 };6970 71 long-password = {72 expectedOwners = [ "db" ];73 generator = fleetLib.mkPassword { size = 64; };74 };7576 77 api-token = {78 expectedOwners = [ "api" ];79 generator = fleetLib.mkBytes { count = 32; encoding = "base64"; };80 };81 session-key = {82 expectedOwners = [ "api" ];83 generator = fleetLib.mkHexBytes { count = 32; };84 };85 wg-psk = {86 expectedOwners = [ "alpha" "beta" ];87 generator = fleetLib.mkBase64Bytes { count = 32; };88 };8990 91 92 garage-rpc = {93 expectedOwners = [ "storage" ];94 generator = fleetLib.mkEd25519 { encoding = "base64"; };95 };9697 98 wg-key = {99 expectedOwners = [ "alpha" ];100 generator = fleetLib.mkX25519 { encoding = "base64"; };101 };102103 104 tls-key = {105 expectedOwners = [ "edge" ];106 generator = fleetLib.mkRsa { size = 2048; };107 };108 };109}110----111112=== Interactive generators113114These prompt the operator on the host running `fleet` and are useful for secrets that can't be generated115algorithmically (vendor API keys, manually-issued certificates, etc.). They are impure - the value you type116is what gets encrypted.117118Note that they also require GUI environment on the machine where the systems are built first time. This is intentional,119because fleet console optput is quite cluttered during the deployment, and it is hard to properly show it.120If this constraint bothers you - feel free to implement those however you like, all of those generators are not handled121in a special way on fleet level: link:../../lib/default.nix[lib/default.nix].122123[source,nix]124----125{126 secrets = {127 128 stripe-api-key = {129 expectedOwners = [ "billing" ];130 generator = fleetLib.mkAskPass {131 prompt = "Stripe live secret key";132 };133 };134135 136 upstream-ca = {137 expectedOwners = [ "edge" ];138 generator = fleetLib.mkAskFile {139 header = "Paste upstream CA bundle (PEM)";140 part = "cert";141 };142 };143144 145 service-env = {146 expectedOwners = [ "app" ];147 generator = fleetLib.mkAskEnv {148 header = "Fill in upstream credentials";149 variables = [ "DATABASE_URL" "API_KEY" "SECRET_TOKEN" ];150 };151 };152 };153}154----155156== Custom secret generator example157158[source,nix]159----160{161 secrets = {162 "my-secret" = {163 164 expectedOwners = [ "host1" "host2" ];165 166 regenerateOnOwnerAdded = true;167168 169 170 171 generator = {172 mkImpureSecretGenerator,173 openssl,174 }:175 mkImpureSecretGenerator {176 177 impureOn = "host3";178179 180 181 182 parts.secret.encrypted = true;183184 185 186 187 188 189 190 script = ''191 mkdir $out192 ${getExe openssl} rand -base64 16 | gh private -o $out/secret193 '';194 };195 };196 }197}198----199200== fleet-generator-helper201202[source]203----204Usage: fleet-generator-helper <COMMAND>205206Commands:207 public Encode public part from stdin208 private Encrypt private part from stdin209 help Print this message or the help of the given subcommand(s)210211Options:212 -h, --help Print help213----214215[source]216----217Encode public part from stdin218219Usage: fleet-generator-helper public [OPTIONS] --output <OUTPUT>220221Options:222 -o, --output <OUTPUT>223224 -e, --encoding <ENCODING>225 Possible values:226 - raw: Do not encode data, store as is227 - base64: Encode as base64 (with padding)228 - hex: Encode as hex (without leading 0x)229 230 [default: raw]231232 -h, --help233 Print help (see a summary with '-h')234----235236[source]237----238Encrypt private part from stdin239240Usage: fleet-generator-helper private [OPTIONS] --output <OUTPUT>241242Options:243 -o, --output <OUTPUT>244245 -e, --encoding <ENCODING>246 Possible values:247 - raw: Do not encode data, store as is248 - base64: Encode as base64 (with padding)249 - hex: Encode as hex (without leading 0x)250 251 [default: raw]252253 -h, --help254 Print help (see a summary with '-h')255----