host-identity-cli 1.1.0

Command-line interface for host-identity: print a stable host UUID across platforms, clouds, and Kubernetes
Documentation

host-identity — a CLI for host-identity

Resolve a stable, collision-resistant host UUID across platforms, container runtimes, cloud providers, and Kubernetes. This crate ships the host-identity binary as a thin wrapper over the host-identity library; use the library directly if you need to embed the same logic in another program.

Install

cargo install host-identity-cli

This gives you the host-identity executable on your PATH. The binary is called host-identity to avoid colliding with coreutils hostid(1), which ships on Linux and the BSDs. The crate name (host-identity-cli) differs from the binary name (host-identity) and from the library crate name (host-identity) — cargo install host-identity has no binary and will not do what you want; always use the -cli suffix.

Default features enable both local (machine-id, DMI, container) and network (cloud metadata, Kubernetes) sources. To build a strictly local binary:

cargo install host-identity-cli --no-default-features --features container

Usage

# Print the host UUID (default chain, local sources only).
host-identity

# Same, but include cloud-metadata and Kubernetes sources.
host-identity resolve --network

# Walk every source without short-circuiting — useful for diagnostics.
host-identity audit

# List every source identifier compiled into this binary.
host-identity sources

# Build a custom chain from source identifiers.
host-identity resolve --sources env-override,machine-id,dmi

# Machine-readable output.
host-identity resolve --format json
host-identity audit --format json

Both JSON outputs are wrapped in an envelope that records the active --wrap strategy, so saved output is self-describing:

// resolve --format json
{
  "wrap": "v5",
  "host_id": { "uuid": "", "source": "machine-id", "in_container": false }
}

// audit --format json
{
  "wrap": "v5",
  "entries": [
    { "source": "", "status": "found", "uuid": "", "error": null, "in_container": false }
  ]
}

sources --json is unchanged (an array of {id, description}) — it lists static source metadata and has no wrap dependency.

Flags

Flag Values Default Notes
--format plain, summary, json plain summary prints source:uuid; plain prints only UUID.
--wrap v5, v3, passthrough v5 How the raw ID becomes a UUID — see Wrap strategies.
--sources <ids> comma-separated source IDs (unset) Build a custom chain; see host-identity sources.
--network (flag) off Adds cloud / k8s sources (requires network feature).
--app-id <APP_ID> UTF-8 byte string (unset) Wrap every source with an HMAC-SHA256 per-app derivation — see App-specific derivation.

Wrap strategies

--wrap controls how the raw identifier returned by the winning source is turned into a UUID. Every strategy is deterministic: the same raw input always produces the same UUID.

Value Behaviour When to pick it
v5 UUID v5 (SHA-1) under this crate's private namespace Default. Rehashes even pre-UUID sources (DMI, IOPlatformUUID, MachineGuid) so two tools sharing the same raw source cannot collide.
v3 UUID v3 (MD5) under the nil namespace Wire-compat with legacy Go tooling that used uuid.NewMD5(uuid.Nil, raw). Interop only — RFC 9562 recommends v5 over v3.
passthrough Parse the raw value directly as a UUID, with no hashing You want the source's own UUID (e.g. product_uuid, pod UID) to survive unchanged so it matches another agent on the same host. Errors if the raw value isn't a parseable UUID.

Pick v5 unless you have a concrete interop requirement. The library API (Resolver::with_wrap) also exposes UuidV5With(ns) for callers who need v5 hashing under a caller-supplied namespace — the CLI does not expose that variant because it takes a non-stringly-typed namespace UUID.

App-specific derivation

--app-id <APP_ID> wraps every source in the chain with an HMAC-SHA256 per-app derivation keyed on the inner source value. Two apps on the same host with different APP_IDs get uncorrelatable UUIDs; the raw inner value (machine-id, DMI UUID, hostid, …) never leaves the process.

host-identity resolve --app-id com.example.telemetry
host-identity resolve --app-id com.example.telemetry --format json

Source labels in the output become app-specific:<inner> (e.g. app-specific:machine-id). APP_ID is not secret — privacy comes from not leaking the inner raw value, not from APP_ID being hidden; reverse-DNS identifiers are idiomatic. Non-UTF-8 APP_ID values must go through the library API.

--wrap composes: --wrap passthrough emits the byte-exact AppSpecific UUID; the default --wrap v5 additionally re-hashes it under this crate's private namespace. Wrapping a source whose raw value is already public (cloud instance IDs, Kubernetes pod UIDs) adds no privacy — the input was not secret. See docs/developer-guide.md → "App-specific derivation" for the algorithm and privacy caveats.

Subcommands

Subcommand Purpose
resolve Resolve and print the host identity (default when omitted).
audit Walk every source in the chain and report each outcome.
sources List every source identifier compiled into this binary.

Features

Feature Default Pulls in
container yes host-identity/container
network yes ureq + every cloud feature of host-identity + host-identity/k8s

Without network, --network at runtime produces an error directing the user to rebuild with the feature.

Packaging

A man page is committed at man/host-identity.1 (plus one page per subcommand) at the workspace root. Packagers should install it to $PREFIX/share/man/man1/host-identity.1. See the top-level README.md for the full install recipe. The pages are regenerated from the clap metadata with cargo xtask.

See also

License

Dual-licensed under Apache-2.0 or MIT at your option.