Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ci-runner: keep the registration token on the host's /run, not in the container's root

swarm-bao-ci-runner still reads the token from bao under the runner's own
ci-runner leaf, but now writes it to /run/swarm-ci-runner on the host
(tmpfs), which the container bind-mounts read-only for the register
unit's LoadCredential. Before, it wrote the token to
/var/lib/nixos-containers/swarm-ci-runner/var/lib/swarm-ci-runner/registration-token
on persistent disk, where a superseded token stayed after rotation and
went into backups of the container root. The container's tmpfiles now
remove that old file.

Rotation is unchanged: the ten-minute timer rewrites the file when the
value differs and refresh_consumer restarts the runner. After a reboot
the token is fetched again; until the store answers, a runner that is
already registered keeps running and only a new registration waits.

Part of #4998 (slice 1).
This commit is contained in:
atlas 2026-10-15 20:30:05 +02:00 • committed by mara
commit 23807c5d0c
4 changed files with 54 additions and 16 deletions

View file

@ -63,13 +63,16 @@ let
# it, which is the spelling a step run as root (`+`) can follow.
runnerFile = "/var/lib/gitea-runner/${instance}/.runner";
# Inside the container, root-only. The token file holds the bare token and
# is a `LoadCredential=` of the register unit alone; the host unit below
# writes it through the container's root, at `hostTokenFile`.
stateDir = "/var/lib/swarm-ci-runner";
tokenFile = "${stateDir}/registration-token";
# Root-only, on tmpfs: the token never reaches persistent disk, and after a
# reboot the host unit below fetches it again. The host unit writes it at
# `hostTokenFile`; the container sees the directory read-only at `tokenDir`,
# where the token file is a `LoadCredential=` of the register unit alone.
hostTokenDir = "/run/${machine}";
hostTokenFile = "${hostTokenDir}/registration-token";
tokenDir = "/run/${machine}";
tokenFile = "${tokenDir}/registration-token";
tokenCredential = "registration-token";
hostTokenFile = "/var/lib/nixos-containers/${machine}${tokenFile}";
# The epoch second the daemon last started. The precond reads the daemon's
# journal from there.
daemonStartedFile = "${stateDir}/daemon-started";
@ -223,6 +226,12 @@ in
${atomicWriteSecret}
${refreshConsumer}
# The container's bind source, so it starts even when the store does not
# answer; tmpfiles creates it too, but unordered with the container on
# a switch. Root-owned: systemd reads a `LoadCredential=` source as
# root, before the runner drops to its dynamic user.
install -d -m 0700 ${lib.escapeShellArg hostTokenDir}
err="$(mktemp)"
trap 'rm -f "$err"' EXIT
@ -253,9 +262,6 @@ in
exit 1
fi
# Root-owned: systemd reads a `LoadCredential=` source as root, before
# the runner drops to its dynamic user.
install -d -m 0700 ${lib.escapeShellArg (builtins.dirOf hostTokenFile)}
if secret_differs ${lib.escapeShellArg hostTokenFile} "$token"; then
atomic_write_secret 0600 "" ${lib.escapeShellArg hostTokenFile} "$token"
fi
@ -270,6 +276,14 @@ in
systemd.services."container@${machine}" = caTrust.containerOrdering;
systemd.tmpfiles.rules = [
# The bind source must exist when the container starts.
"d ${hostTokenDir} 0700 root root -"
# `LoadCredential=` fails the unit when the file is missing; an empty
# one lets the register unit report the missing token.
"f ${hostTokenFile} 0600 root root -"
];
containers.${machine} = {
autoStart = true;
ephemeral = false;
@ -287,6 +301,10 @@ in
hostPath = "/nix/var/nix/daemon-socket";
isReadOnly = false;
};
${tokenDir} = {
hostPath = hostTokenDir;
isReadOnly = true;
};
}
// caTrust.bindMount;
@ -355,11 +373,10 @@ in
systemd.tmpfiles.rules = [
"d ${stateDir} 0700 root root -"
# `LoadCredential=` fails the unit when the file is missing; an
# empty one lets the register unit report the missing token.
"f ${tokenFile} 0600 root root -"
# Unused: nothing in this module writes or reads them. The first
# holds a token; the others are upstream's re-registration markers.
# two hold a token; the others are upstream's re-registration
# markers.
"r ${stateDir}/registration-token"
"r ${stateDir}/registration-token.env"
"r /var/lib/private/gitea-runner/${instance}/.token-hash"
"r /var/lib/private/gitea-runner/${instance}/.labels"