keep the cache's key and pull token for hive-priv in a root-only directory
This commit is contained in:
parent
d241e64ab1
commit
b845630023
1 changed files with 519 additions and 22 deletions
87
nix/host-modules/lib/attic-root-facts.nix
Normal file
87
nix/host-modules/lib/attic-root-facts.nix
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# 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/<hive>/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
|
||||
|
||||
# <leaf> <variable>. 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 <name>:<key> 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
|
||||
''
|
||||
Loading…
Reference in a new issue