password & keyring cleanup: one password, one truth, no prompts
The Hub, GDM and sudo now share /etc/shadow as the single source of
truth. /var/lib/secrets/{free,root}-password become root-only display
copies, written only by system_password.py and verified against shadow
before being shown. The GNOME login keyring is decoupled from the login
password (blank master password, pam_gnome_keyring off), so nothing
needs re-keying or wiping when the password changes and the keyring
never pops an unlock prompt.
- add app/sovran_systemsos_web/system_password.py: the single module
that verifies / sets / displays the free + root passwords and drives
the legacy-migration onboarding step (same endpoints and UI)
- add modules/password-model.nix: PAM gnome-keyring off, blank
login.keyring seed with a one-time migration of old encrypted
keyrings, first-boot-only password application (no more boot-revert),
LIBCRYPT for the Hub
- server.py: login verifies against shadow and heals stale display
copies; change-password takes the current password; security reset
sets both passwords through the same writer (root is shown as a
password again, not a hash); all keyring wipes removed
- credentials.nix: drop root-password-setup, free-password-setup and
free-password-migration (replaced by password-model.nix) and the
keyring wipe in change-free-password
- configuration.nix: drop enableGnomeKeyring and the keyring tmpfiles
hack (replaced by password-model.nix)
- service-detail.js: "Current password" field; credentials changed
outside the Hub render with a hint instead of a stale value
Installed machines keep their exact passwords: the first-boot services
no-op once an account has a real hash, and the upgrade never writes
/etc/shadow. The legacy-migration onboarding step and "reset all
passwords" keep working.
This commit is contained in:
1 parent
5e56b07465
commit
4a25ef24d1
8 files changed
+430
-437
No files matched your search
@@ -33,9 +33,6 @@ let
|
||||
echo "$NEW_PASS" > "$SECRET_FILE"
|
||||
chmod 600 "$SECRET_FILE"
|
||||
echo "Password for 'free' updated and saved."
|
||||
# Delete the old GNOME Keyring databases so a fresh one is created on next GDM login.
|
||||
rm -f /home/free/.local/share/keyrings/*.keyring
|
||||
echo "GNOME Keyring files cleared — a fresh keyring will be created on next login."
|
||||
'';
|
||||
in
|
||||
{
|
||||
@@ -76,172 +73,4 @@ in
|
||||
command passwd $argv
|
||||
end
|
||||
'';
|
||||
|
||||
# ── 1. Auto-Generate Root Password (Runs once) ─────────────
|
||||
systemd.services.root-password-setup = {
|
||||
description = "Generate and set a random root password";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
path = [ pkgs.shadow pkgs.coreutils ];
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
SECRET_FILE="/var/lib/secrets/root-password"
|
||||
if [ ! -f "$SECRET_FILE" ]; then
|
||||
mkdir -p /var/lib/secrets
|
||||
# Generate a diceware-style passphrase: word-word-word-word-NN
|
||||
WORDS="apple barn brook cabin cedar cloud coral crane delta eagle ember \
|
||||
fern field flame flora flint frost grove haven hedge holly heron \
|
||||
jade juniper kelp larch lemon lilac linden loch lotus maple marsh \
|
||||
meadow mist mossy mount oak ocean olive petal pine pixel plum pond \
|
||||
prism quartz raven ridge river robin rocky rose rowan sage sand \
|
||||
sierra silver slate snow solar spark spruce stone storm summit \
|
||||
swift thorn tide timber torch trout vale vault vine walnut wave \
|
||||
willow wren amber aspen birch blaze bloom bluff coast copper crest \
|
||||
dune elder fjord forge glade glen glow gulf"
|
||||
WORD_ARRAY=($WORDS)
|
||||
COUNT=''${#WORD_ARRAY[@]}
|
||||
W1=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W2=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W3=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W4=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
DIGIT=$(printf '%02d' $((RANDOM % 100)))
|
||||
ROOT_PASS="$W1-$W2-$W3-$W4-$DIGIT"
|
||||
echo "$ROOT_PASS" > "$SECRET_FILE"
|
||||
chmod 600 "$SECRET_FILE"
|
||||
fi
|
||||
# If the file contains a scrypt hash (salt:hash), skip chpasswd — the
|
||||
# password was already set via the Hub security reset endpoint and this
|
||||
# service is only re-running as a manual recovery step.
|
||||
CONTENT="$(cat "$SECRET_FILE")"
|
||||
if echo "$CONTENT" | grep -qE '^[0-9a-f]{32}:[0-9a-f]{64,}$'; then
|
||||
echo "root-password-setup: stored value is already hashed — skipping chpasswd" >&2
|
||||
else
|
||||
echo "root:$CONTENT" | chpasswd
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# ── 1b. Generate random 'free' password on first boot ──────
|
||||
systemd.services.free-password-setup = {
|
||||
description = "Generate and set a random 'free' user password";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "display-manager.service" ];
|
||||
after = [ "systemd-user-sessions.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
path = [ pkgs.shadow pkgs.coreutils ];
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
SECRET_FILE="/var/lib/secrets/free-password"
|
||||
PENDING_FILE="/var/lib/secrets/free-password-migration-pending"
|
||||
|
||||
if [ -f "$SECRET_FILE" ]; then
|
||||
echo "free:$(cat "$SECRET_FILE")" | chpasswd
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SHADOW_HASH=""
|
||||
while IFS=: read -r user hash _; do
|
||||
if [ "$user" = "free" ]; then
|
||||
SHADOW_HASH="$hash"
|
||||
break
|
||||
fi
|
||||
done < /etc/shadow
|
||||
|
||||
HAS_REAL_HASH=0
|
||||
case "$SHADOW_HASH" in
|
||||
""|"!"|"*"|"!!"|"!"*|"*"*)
|
||||
HAS_REAL_HASH=0
|
||||
;;
|
||||
*)
|
||||
HAS_REAL_HASH=1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$HAS_REAL_HASH" -eq 1 ]; then
|
||||
mkdir -p /var/lib/secrets
|
||||
touch "$PENDING_FILE"
|
||||
chmod 600 "$PENDING_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p /var/lib/secrets
|
||||
# Generate a diceware-style passphrase: word-word-word-word-NN
|
||||
WORDS="apple barn brook cabin cedar cloud coral crane delta eagle ember \
|
||||
fern field flame flora flint frost grove haven hedge holly heron \
|
||||
jade juniper kelp larch lemon lilac linden loch lotus maple marsh \
|
||||
meadow mist mossy mount oak ocean olive petal pine pixel plum pond \
|
||||
prism quartz raven ridge river robin rocky rose rowan sage sand \
|
||||
sierra silver slate snow solar spark spruce stone storm summit \
|
||||
swift thorn tide timber torch trout vale vault vine walnut wave \
|
||||
willow wren amber aspen birch blaze bloom bluff coast copper crest \
|
||||
dune elder fjord forge glade glen glow gulf"
|
||||
WORD_ARRAY=($WORDS)
|
||||
COUNT=''${#WORD_ARRAY[@]}
|
||||
W1=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W2=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W3=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W4=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
DIGIT=$(printf '%02d' $((RANDOM % 100)))
|
||||
FREE_PASS="$W1-$W2-$W3-$W4-$DIGIT"
|
||||
echo "$FREE_PASS" > "$SECRET_FILE"
|
||||
chmod 600 "$SECRET_FILE"
|
||||
echo "free:$FREE_PASS" | chpasswd
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.free-password-migration = {
|
||||
description = "Generate and set 'free' password for migrated machines";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "display-manager.service" ];
|
||||
after = [ "systemd-user-sessions.service" "free-password-setup.service" ];
|
||||
requires = [ "free-password-setup.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
path = [ pkgs.shadow pkgs.coreutils ];
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
PENDING_FILE="/var/lib/secrets/free-password-migration-pending"
|
||||
SECRET_FILE="/var/lib/secrets/free-password"
|
||||
NEWPASS_FILE="/var/lib/secrets/free-password-migration-newpass"
|
||||
|
||||
[ -f "$PENDING_FILE" ] || exit 0
|
||||
|
||||
mkdir -p /var/lib/secrets
|
||||
|
||||
WORDS="apple barn brook cabin cedar cloud coral crane delta eagle ember \
|
||||
fern field flame flora flint frost grove haven hedge holly heron \
|
||||
jade juniper kelp larch lemon lilac linden loch lotus maple marsh \
|
||||
meadow mist mossy mount oak ocean olive petal pine pixel plum pond \
|
||||
prism quartz raven ridge river robin rocky rose rowan sage sand \
|
||||
sierra silver slate snow solar spark spruce stone storm summit \
|
||||
swift thorn tide timber torch trout vale vault vine walnut wave \
|
||||
willow wren amber aspen birch blaze bloom bluff coast copper crest \
|
||||
dune elder fjord forge glade glen glow gulf"
|
||||
WORD_ARRAY=($WORDS)
|
||||
COUNT=''${#WORD_ARRAY[@]}
|
||||
W1=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W2=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W3=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
W4=''${WORD_ARRAY[$((RANDOM % COUNT))]}
|
||||
DIGIT=$(printf '%02d' $((RANDOM % 100)))
|
||||
FREE_PASS="$W1-$W2-$W3-$W4-$DIGIT"
|
||||
|
||||
printf '%s\n' "$FREE_PASS" > "$SECRET_FILE"
|
||||
chmod 600 "$SECRET_FILE"
|
||||
|
||||
printf '%s\n' "$FREE_PASS" > "$NEWPASS_FILE"
|
||||
chmod 600 "$NEWPASS_FILE"
|
||||
rm -f "$PENDING_FILE"
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user