scope the cache access to hive-core: client-side nix copy, daemon trusts only the key
This commit is contained in:
parent
ecd4445680
commit
dab7768869
1 changed files with 365 additions and 271 deletions
|
|
@ -1,18 +1,22 @@
|
|||
# The root-side copy of the cache facts the host's nix daemon and hive-priv
|
||||
# trust: 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, and
|
||||
# a nix.conf fragment at `confFile` that the host's nix.conf includes.
|
||||
# The root-side copy of the cache facts the host's nix daemon, hive-priv and
|
||||
# hive-c0re use: 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:
|
||||
#
|
||||
# What the daemon and hive-priv decide 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}`. The fragment holds no secret
|
||||
# (the key is public, the netrc stays in `dir`) and hive-c0re can read it: it
|
||||
# takes the cache's address from there.
|
||||
# - the key and the netrc into `dir`, which only root can read (hive-priv's
|
||||
# check of the key);
|
||||
# - a nix.conf fragment at `confFile` that the host's nix.conf includes, with
|
||||
# `extra-trusted-public-keys` and nothing else: no trusted substituter and no
|
||||
# netrc, so no other client of the daemon can fetch from the cache or send
|
||||
# the token;
|
||||
# - a second copy of the netrc at `clientNetrc`, `root:<clientGroup> 0640`,
|
||||
# that hive-c0re passes to its own `nix copy --from` as a client setting.
|
||||
#
|
||||
# A store that holds no facts yet, or cannot be reached, leaves what is in `dir`
|
||||
# and `confFile` as they are. Nothing here removes a file.
|
||||
# Nothing is read from a file hive-c0re (unprivileged) writes: the key and the
|
||||
# token come from the store. The fragment holds no secret.
|
||||
#
|
||||
# A store that holds no facts yet, or cannot be reached, leaves what is in
|
||||
# `dir`, `confFile` and `clientNetrc` as they are. Nothing here removes a file.
|
||||
#
|
||||
# Pure function — NOT a NixOS module. Call it from a unit's `script`, with
|
||||
# `bao`, `coreutils`, `gnugrep` and `systemd` on its `path` and the `BAO_*`
|
||||
|
|
@ -20,7 +24,8 @@
|
|||
#
|
||||
# script = import ./lib/attic-root-facts.nix { inherit lib; } {
|
||||
# hive = "alpha"; host = "attic.example.org"; dir = "/run/hyperhive-priv/attic";
|
||||
# url = "https://attic.example.org/swarm"; confFile = "/run/hyperhive-nix/cache.conf";
|
||||
# confFile = "/run/hyperhive-nix/cache.conf"; clientNetrc = "/run/hyperhive-nix/netrc";
|
||||
# clientGroup = "hive-core";
|
||||
# };
|
||||
{ lib }:
|
||||
{
|
||||
|
|
@ -31,10 +36,11 @@
|
|||
host,
|
||||
# Where the key and the netrc go.
|
||||
dir,
|
||||
# The cache's address as the daemon lists it in `trusted-substituters`.
|
||||
url,
|
||||
# Where the nix.conf fragment goes; its directory is root's and readable.
|
||||
confFile,
|
||||
# Where the netrc copy for the client goes, and the group that may read it.
|
||||
clientNetrc,
|
||||
clientGroup,
|
||||
}:
|
||||
''
|
||||
set -euo pipefail
|
||||
|
|
@ -44,8 +50,9 @@
|
|||
|
||||
dir=${lib.escapeShellArg dir}
|
||||
conf=${lib.escapeShellArg confFile}
|
||||
client_netrc=${lib.escapeShellArg clientNetrc}
|
||||
install -d -m 0700 "$dir"
|
||||
install -d -m 0755 "$(dirname -- "$conf")"
|
||||
install -d -m 0755 "$(dirname -- "$conf")" "$(dirname -- "$client_netrc")"
|
||||
|
||||
store_init
|
||||
store_login
|
||||
|
|
@ -95,14 +102,17 @@
|
|||
atomic_write_secret 0600 "" "$dir/netrc" "$netrc"
|
||||
fi
|
||||
|
||||
# Last, so a daemon that reads the fragment finds the netrc in place. The
|
||||
# address is the one hive-c0re may name as the substituter. The mtime moves
|
||||
# only with the content. Lix re-reads nix.conf for every connection, CppNix
|
||||
# only at start, so a daemon that started before this write is restarted.
|
||||
printf -v fragment '%s\n%s\n%s' \
|
||||
${lib.escapeShellArg "extra-trusted-substituters = ${url}"} \
|
||||
"extra-trusted-public-keys = $key" \
|
||||
"netrc-file = $dir/netrc"
|
||||
# The client's copy: readable by the group, which is a deliberate grant of the
|
||||
# pull token to hive-c0re's user. Written before the fragment, so a host with
|
||||
# the key has the netrc.
|
||||
if secret_differs "$client_netrc" "$netrc"; then
|
||||
atomic_write_secret 0640 ":${clientGroup}" "$client_netrc" "$netrc"
|
||||
fi
|
||||
|
||||
# Last. The mtime moves only with the content. Lix re-reads nix.conf for every
|
||||
# connection, CppNix only at start, so a daemon that started before this write
|
||||
# is restarted.
|
||||
fragment="extra-trusted-public-keys = $key"
|
||||
if secret_differs "$conf" "$fragment"; then
|
||||
atomic_write_secret 0644 "" "$conf" "$fragment"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in a new issue