attic-init: replace the stored public key with the one the cache reports
a re-created cache signs with a new key; the fact was only created once, so every hive then rejected the swarm's closures. the cache's grant gains update on that one leaf, and a store that refuses it leaves the key as it was. Closes #6181
This commit is contained in:
parent
485e2e86ca
commit
b0f6ccaa64
3 changed files with 159 additions and 75 deletions
|
|
@ -1,7 +1,8 @@
|
|||
# The shell for the in-swarm cache's first start: what its two host units run
|
||||
# after they log in to the secret store under the cache's own certificate.
|
||||
# Each secret is created only while the store holds none, so a second run reads
|
||||
# what the first one stored and mints nothing.
|
||||
# what the first one stored and mints nothing. The cache's public key is the
|
||||
# exception: the store is brought to the key the cache reports.
|
||||
#
|
||||
# Pure function — NOT a NixOS module. Call it from a module's `let`:
|
||||
#
|
||||
|
|
@ -21,9 +22,10 @@
|
|||
jwtPath,
|
||||
pullPath,
|
||||
pushPath,
|
||||
# The cache's public facts, created only while absent: the server's address
|
||||
# (scheme included), the cache's name, and the key its narinfo are signed
|
||||
# with. Hives pull with them.
|
||||
# The cache's public facts: the server's address (scheme included), the
|
||||
# cache's name, and the key its narinfo are signed with. Hives pull with
|
||||
# them. The address and the name are created only while absent; the key is
|
||||
# replaced whenever the cache reports another.
|
||||
urlPath,
|
||||
cachePath,
|
||||
publicKeyPath,
|
||||
|
|
@ -187,6 +189,31 @@ in
|
|||
}
|
||||
ensure_secret ${q urlPath} mint_url >/dev/null || exit 1
|
||||
ensure_secret ${q cachePath} mint_cache >/dev/null || exit 1
|
||||
ensure_secret ${q publicKeyPath} mint_public_key >/dev/null || exit 1
|
||||
stored_key="$(ensure_secret ${q publicKeyPath} mint_public_key)" || exit 1
|
||||
|
||||
# A cache created again has a new signing key, so the stored key is
|
||||
# replaced by the one the cache reports. Only the cache's own grant on this
|
||||
# path allows an update; a store whose policy lacks it refuses, and the
|
||||
# stored key stays.
|
||||
live_key="$(mint_public_key)"
|
||||
if [ -z "$live_key" ]; then
|
||||
echo "the cache ${cache} reported no public key." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$stored_key" != "$live_key" ]; then
|
||||
if printf '%s' "$live_key" | bao kv put ${q publicKeyPath} value=- >/dev/null 2>"$err"; then
|
||||
echo "replaced the stored public key with the one the cache ${cache} reports."
|
||||
else
|
||||
case "$(cat "$err")" in
|
||||
*"permission denied"*)
|
||||
echo "the store refuses to update ${publicKeyPath}; the stored key is not the cache's." >&2
|
||||
;;
|
||||
*)
|
||||
cat "$err" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
# ./swarm-grafana.nix gives its admin password. One creates the key atticd signs
|
||||
# tokens with, if the store holds none, and hands it to the container. The other
|
||||
# creates the cache, the push and pull tokens, and the facts hives pull with
|
||||
# (its address, name and public key), each only while absent
|
||||
# (./lib/attic-init.nix). Neither needs a manual step.
|
||||
# (its address and name, created only while absent, and its public key, which
|
||||
# follows what the cache reports; ./lib/attic-init.nix). Neither needs a manual
|
||||
# step.
|
||||
#
|
||||
# The container has a network namespace of its own on the hive bridge. atticd
|
||||
# listens on that namespace's loopback only, because it cannot listen on a unix
|
||||
|
|
|
|||
|
|
@ -1307,11 +1307,11 @@ let
|
|||
}
|
||||
];
|
||||
|
||||
# The in-swarm cache's six secrets, create and read and nothing more: its
|
||||
# host units create each one only while it is absent, so none needs `update`,
|
||||
# and a rewrite of a signing key or a token an operator holds is refused. The
|
||||
# cache container's journal forwarder reads its client secret under the same
|
||||
# leaf.
|
||||
# The in-swarm cache's six secrets: create and read, so a rewrite of a signing
|
||||
# key or a token an operator holds is refused. The public key also gets
|
||||
# `update`: the cache's host unit replaces it when a re-created cache signs
|
||||
# with another. The cache container's journal forwarder reads its client
|
||||
# secret under the same leaf.
|
||||
atticWriters = [
|
||||
{
|
||||
name = "swarm-attic";
|
||||
|
|
@ -1328,8 +1328,13 @@ let
|
|||
atticJwtLeaf
|
||||
atticPushTokenLeaf
|
||||
]
|
||||
++ atticFactLeaves
|
||||
++ lib.remove atticPublicKeyLeaf atticFactLeaves
|
||||
)
|
||||
+ ''
|
||||
path "${credentialMountPath}/data/${atticPublicKeyLeaf}" {
|
||||
capabilities = ["create", "read", "update"]
|
||||
}
|
||||
''
|
||||
+ readStanza "${credentialMountPath}/data/swarm/services/${hyperhiveCfg.swarm.attic.otel.clientId}/oidc/client";
|
||||
}
|
||||
];
|
||||
|
|
@ -2592,7 +2597,8 @@ in
|
|||
Subject the store's `swarm-attic` cert-auth role accepts: the identity
|
||||
the in-swarm cache's host units present. Its grant is create and read on
|
||||
six paths under `swarm/services/attic/`, `jwt-secret`, `push-token`,
|
||||
`pull-token`, `url`, `cache` and `public-key`, and nothing else.
|
||||
`pull-token`, `url`, `cache` and `public-key`, plus `update` on
|
||||
`public-key`, and nothing else.
|
||||
|
||||
⚠️ Reserved as a hive name by ./swarm.nix, like its siblings.
|
||||
'';
|
||||
|
|
|
|||
Loading…
Reference in a new issue