drop the one-time migration: seed the store from a leftover file once, leave the file
A leftover plaintext client secret is stored once with -cas=0 when the store holds none, so nothing rotates. A store value wins over a different file. The file is no longer read back, compared or removed, and the migration unit is gone.
This commit is contained in:
parent
2fc63d844b
commit
fcc9c8d0ba
1 changed files with 114 additions and 350 deletions
|
|
@ -237,7 +237,6 @@ let
|
|||
publisherCfg.enable
|
||||
&& publisherCfg.baoClientCertFile != null
|
||||
&& publisherCfg.baoClientKeyFile != null;
|
||||
migrateUnit = "${unitName}-client-secrets";
|
||||
forwarderFetchUnit = "swarm-journal-forwarder-oidc";
|
||||
# The publisher's store identity, handed into the container as system
|
||||
# credentials (credential id → host source). The forwarder's fetch presents
|
||||
|
|
@ -580,9 +579,7 @@ let
|
|||
storeRetry = import ./lib/store-retry.nix { };
|
||||
|
||||
# The bridge's own client secret, in the memory-backed runtime directory of
|
||||
# its unit. While a plaintext file from an earlier release exists the bridge
|
||||
# keeps using it, since it is the value the digest was made from; the file
|
||||
# goes once the store holds the same value, and the store's takes over.
|
||||
# its unit, fetched from the store before each start.
|
||||
bridgeSecretFile = "/run/swarm-authelia-bridge/client-secret";
|
||||
bridgeSecretFetch = ''
|
||||
set -euo pipefail
|
||||
|
|
@ -591,12 +588,9 @@ let
|
|||
${storeSeededSecret}
|
||||
${oidcClientSecrets}
|
||||
|
||||
legacy=${lib.escapeShellArg "${clientsDir}/${bridgeClientId}.secret"}
|
||||
store_init
|
||||
store_login
|
||||
if [ -s "$legacy" ]; then
|
||||
value="$(< "$legacy")"
|
||||
elif client_secret_read ${lib.escapeShellArg (clientLeaf bridgeClientId)}; then
|
||||
if client_secret_read ${lib.escapeShellArg (clientLeaf bridgeClientId)}; then
|
||||
value="$CLIENT_SECRET_VALUE"
|
||||
else
|
||||
echo "the store holds no readable secret for ${bridgeClientId}" >&2
|
||||
|
|
@ -1094,7 +1088,6 @@ in
|
|||
++ lib.optionals publishes [
|
||||
"opentelemetry-collector.service"
|
||||
"${forwarderFetchUnit}.service"
|
||||
"${migrateUnit}.service"
|
||||
"${unitName}-secrets.service"
|
||||
"swarm-authelia-bridge.service"
|
||||
];
|
||||
|
|
@ -1133,79 +1126,6 @@ in
|
|||
serviceConfig.LoadCredential = lib.attrNames storeFiles;
|
||||
};
|
||||
|
||||
# Moves the plaintext files an earlier release left in `clientsDir`
|
||||
# into the store and removes each once the store holds the same
|
||||
# value. With no file left it does nothing, store or no store. Nothing
|
||||
# orders authelia after it: authelia starts from its digests.
|
||||
systemd.services.${migrateUnit} = lib.mkIf publishes {
|
||||
description = "move authelia's plaintext OIDC client secrets into the swarm secret store";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "${unitName}-secrets.service" ];
|
||||
path = [
|
||||
pkgs.coreutils
|
||||
pkgs.gnugrep
|
||||
deployCfg.bao.package
|
||||
];
|
||||
startLimitBurst = storeRetry.startLimitBurst;
|
||||
startLimitIntervalSec = storeRetry.startLimitIntervalSec;
|
||||
serviceConfig = storeRetry.serviceConfig // {
|
||||
Type = "oneshot";
|
||||
User = unitName;
|
||||
Group = socketGroup;
|
||||
UMask = "0077";
|
||||
LoadCredential = lib.attrNames storeFiles;
|
||||
TimeoutStartSec = 120;
|
||||
RestartPreventExitStatus = 3;
|
||||
SyslogIdentifier = migrateUnit;
|
||||
};
|
||||
environment =
|
||||
let
|
||||
store = storeIdentityIn migrateUnit;
|
||||
in
|
||||
{
|
||||
BAO_ADDR = store.addr;
|
||||
BAO_CLIENT_CERT = store.clientCertFile;
|
||||
BAO_CLIENT_KEY = store.clientKeyFile;
|
||||
}
|
||||
// lib.optionalAttrs (store.caFile != null) { BAO_CACERT = store.caFile; };
|
||||
script = ''
|
||||
set -uo pipefail
|
||||
|
||||
${storeSeededSecret}
|
||||
${oidcClientSecrets}
|
||||
|
||||
clients=${lib.escapeShellArg clientsDir}
|
||||
known=${lib.escapeShellArg (lib.concatMapStrings (c: " ${c.id}") secretClients + " ")}
|
||||
|
||||
pending=0
|
||||
for f in "$clients"/*.secret; do
|
||||
[ -e "$f" ] || continue
|
||||
id="$(basename "$f" .secret)"
|
||||
case "$known" in
|
||||
*" $id "*) pending=1 ;;
|
||||
*) echo "left $f in place: no client $id is registered here" >&2 ;;
|
||||
esac
|
||||
done
|
||||
if [ "$pending" = 0 ]; then
|
||||
echo "no plaintext client secret files to move"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
store_init
|
||||
store_login
|
||||
|
||||
status=0
|
||||
${lib.concatMapStrings (c: ''
|
||||
rc=0
|
||||
migrate_client_secret ${lib.escapeShellArg c.id} ${lib.escapeShellArg (clientLeaf c.id)} || rc=$?
|
||||
if [ "$rc" != 0 ] && [ "$status" != 1 ]; then
|
||||
status="$rc"
|
||||
fi
|
||||
'') secretClients}
|
||||
exit "$status"
|
||||
'';
|
||||
};
|
||||
|
||||
# The authelia binary itself, so an operator who gets a shell
|
||||
# in here can run `authelia crypto hash generate` to make a
|
||||
# password for the users file. Without it the container runs
|
||||
|
|
@ -1323,8 +1243,7 @@ in
|
|||
after = [
|
||||
"${unitName}-secrets.service"
|
||||
"${unitName}.service"
|
||||
]
|
||||
++ lib.optional publishes "${migrateUnit}.service";
|
||||
];
|
||||
wants = [
|
||||
"${unitName}-secrets.service"
|
||||
"${unitName}.service"
|
||||
|
|
|
|||
Loading…
Reference in a new issue