# The root-side copy of the two cache facts hive-priv trusts: the key a # downloaded closure must be signed by and the netrc the pull token goes out # in. The script runs as root on the hive host under the hive's own store # identity and writes both into `dir`, which only root can read. # # Everything hive-priv decides on is here or in the host's configuration, and # nothing is read from a file hive-c0re (unprivileged) writes: the key and the # token come from the store, the cache's address from # `services.hyperhive.swarm.attic.{domain,cache}`. # # A store that holds no facts yet, or cannot be reached, leaves what is in `dir` # as it is. Nothing here removes a file. # # Pure function — NOT a NixOS module. Call it from a unit's `script`, with # `bao`, `coreutils` and `gnugrep` on its `path` and the `BAO_*` client # environment set: # # script = import ./lib/attic-root-facts.nix { inherit lib; } { # hive = "alpha"; host = "attic.example.org"; dir = "/run/hyperhive-priv/attic"; # }; { lib }: { # The hive's name in the store: facts are read from # `secret/swarm/hives//attic/`. hive, # The cache server's host name, which the netrc line names. host, # Where the two files go. dir, }: '' set -euo pipefail ${import ./store-seeded-secret.nix { }} ${import ./atomic-write-secret.nix { }} ${import ./refresh-consumer.nix { }} dir=${lib.escapeShellArg dir} install -d -m 0700 "$dir" store_init store_login if [ "$STORE_UP" != 1 ]; then echo "could not read the cache facts; $dir stays as it is." >&2 exit 1 fi # . Sets the variable to the leaf's value. A leaf the store # does not hold sets `missing`; any other failure ends the run. missing=0 fetch() { local value if value="$(store_bao kv get -field=value ${lib.escapeShellArg "secret/swarm/hives/${hive}/attic"}/"$1" 2>"$STORE_ERR")"; then printf -v "$2" '%s' "$value" elif grep -qi 'no value found' "$STORE_ERR"; then missing=1 else cat "$STORE_ERR" >&2 echo "could not read the cache fact $1; $dir stays as it is." >&2 exit 1 fi } key="" token="" fetch public-key key fetch pull-token token if [ "$missing" = 1 ]; then echo "the swarm has not given this hive its cache facts yet; $dir stays as it is." exit 0 fi # One token each: both land in a file nix and hive-priv parse by whitespace. if [[ ! "$key" =~ ^[^[:space:]:]+:[^[:space:]]+$ ]] || [[ ! "$token" =~ ^[^[:space:]]+$ ]]; then echo "the stored cache facts are not a : and a single token; $dir stays as it is." >&2 exit 1 fi # Written only when the value changed, so the files keep their mtime between # runs. The owner is the running user, root, and the mode is 0600. if secret_differs "$dir/public-key" "$key"; then atomic_write_secret 0600 "" "$dir/public-key" "$key" fi netrc="machine ${host} password $token" if secret_differs "$dir/netrc" "$netrc"; then atomic_write_secret 0600 "" "$dir/netrc" "$netrc" fi ''