git.delta.rocks / fleet / refs/heads / trunk

difftreelog

source

docs/features/secrets.adoc8.1 KiBrenderedsourcehistory
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  # Shared - top-level, with expectedOwners29  secrets."wg-psk" = {30    expectedOwners = [ "alpha" "beta" ];31    generator = fleetLib.mkBase64Bytes { count = 32; };32    # Optional: rotate when ownership changes33    regenerateOnOwnerAdded = true;34    regenerateOnOwnerRemoved = true;35  };3637  hosts.alpha.nixos = { ... }: {38    # Per-host - lives only on alpha39    secrets."alpha-api-token".generator = fleetLib.mkPassword { };4041    # Claim of the shared secret declared above42    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    # Random 32-char ASCII password (single encrypted `secret` part)65    db-password = {66      expectedOwners = [ "db" ];67      generator = fleetLib.mkPassword { };68    };6970    # 64-char password71    long-password = {72      expectedOwners = [ "db" ];73      generator = fleetLib.mkPassword { size = 64; };74    };7576    # 32 random bytes, raw/hex/base64 encoded77    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    # Ed25519 keypair, two parts: plaintext `public`, encrypted `secret`91    # `noEmbedPublic` strips the embedded public half, leaving only the 32-byte private scalar92    garage-rpc = {93      expectedOwners = [ "storage" ];94      generator = fleetLib.mkEd25519 { encoding = "base64"; };95    };9697    # X25519 keypair (e.g. WireGuard peer keys) - usually per-host, shown shared here for brevity98    wg-key = {99      expectedOwners = [ "alpha" ];100      generator = fleetLib.mkX25519 { encoding = "base64"; };101    };102103    # RSA keypair, PEM-encoded; default size is 4096104    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    # Single-line input via kdialog128    stripe-api-key = {129      expectedOwners = [ "billing" ];130      generator = fleetLib.mkAskPass {131        prompt = "Stripe live secret key";132      };133    };134135    # Multi-line input opened in Kate; useful for pasted certificates/blobs136    upstream-ca = {137      expectedOwners = [ "edge" ];138      generator = fleetLib.mkAskFile {139        header = "Paste upstream CA bundle (PEM)";140        part = "cert";141      };142    };143144    # Convenience wrapper that pre-populates an env-file template145    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      # Shared secret will be encrypted for those two hosts164      expectedOwners = [ "host1" "host2" ];165      # We can force secret to be regenerated when the owner was added166      regenerateOnOwnerAdded = true;167168      # generator is a function from pkgs extended with helpers, so if you need something special, you can just get169      # it from arguments, fleet will do callPackage for you, and provide you with the packages for the machine170      # that will be generating this secret171      generator = {172        mkImpureSecretGenerator,173        openssl,174      }:175        mkImpureSecretGenerator {176          # Impure secret generator executes arbitrary code on arbitrary host over SSH177          impureOn = "host3";178179          # Secret may produce multiple parts, for example, for RSA keypair it would be secret and public part,180          # where only secret part should be encrypted. Non-encrypted parts are available as nix store path and as181          # an expression, encrypted parts will be only available on owning machines after the deployment.182          parts.secret.encrypted = true;183184          # In impure secret generator, script is a code that thould prepare the target directory structure185          # Target directory should contain one file for every declared part (parts argument in this attrset),186          # and may contain expires_at/created_at files if you want to use it with PKI.187          #188          # Secret parts should be encoded/encrypted to be consumed by fleet, you can use `gh` alias for that,189          # it will be prepared implicitly, and for arguments - look at the `fleet-generator-helper` section of the docs.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----