Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 36s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
189 lines
6.1 KiB
Bash
Executable File
189 lines
6.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Local-only check/apply helper for 110 SSH publickey authentication stalls.
|
|
#
|
|
# Run on host 110 from a trusted local console or an already working root shell.
|
|
# It never prints authorized_keys contents. Apply only fixes metadata permissions
|
|
# on the target user's home/.ssh/authorized_keys path and runs sshd syntax checks.
|
|
|
|
set -euo pipefail
|
|
|
|
TARGET_USER="${TARGET_USER:-wooo}"
|
|
APPLY=0
|
|
RELOAD_SSH="${RELOAD_SSH:-0}"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: scripts/reboot-recovery/repair-110-ssh-publickey-auth-local.sh [--check|--apply]
|
|
|
|
Options:
|
|
--check Read-only checks. Default.
|
|
--apply Fix ownership/permissions for TARGET_USER home/.ssh/authorized_keys.
|
|
|
|
Environment:
|
|
TARGET_USER=wooo Account to inspect/fix.
|
|
RELOAD_SSH=0 Set to 1 to run `systemctl reload ssh` after apply.
|
|
|
|
This script does not print authorized_keys contents and does not create keys.
|
|
USAGE
|
|
}
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--check)
|
|
APPLY=0
|
|
;;
|
|
--apply)
|
|
APPLY=1
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 64
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
require_110_or_explicit() {
|
|
if [ "${ALLOW_NON_110:-0}" = "1" ]; then
|
|
return
|
|
fi
|
|
if hostname -I 2>/dev/null | tr ' ' '\n' | grep -qx '192.168.0.110'; then
|
|
return
|
|
fi
|
|
echo "BLOCKED not running on 192.168.0.110; set ALLOW_NON_110=1 only for syntax tests" >&2
|
|
exit 65
|
|
}
|
|
|
|
stat_path() {
|
|
local path="$1"
|
|
if [ -e "$path" ]; then
|
|
stat -c 'PATH_STATUS path=%n mode=%a owner=%U group=%G type=%F' "$path"
|
|
else
|
|
echo "PATH_STATUS path=$path missing=1"
|
|
fi
|
|
}
|
|
|
|
check_user() {
|
|
local user="$1"
|
|
local home_dir shell passwd_status account_locked shell_exists shell_executable
|
|
home_dir="$(getent passwd "$user" | awk -F: '{print $6}')"
|
|
if [ -z "$home_dir" ]; then
|
|
echo "USER_STATUS user=$user exists=0"
|
|
return 1
|
|
fi
|
|
|
|
shell="$(getent passwd "$user" | awk -F: '{print $7}')"
|
|
passwd_status="$(passwd -S "$user" 2>/dev/null | awk '{print $2}' || true)"
|
|
account_locked=false
|
|
case "$passwd_status" in
|
|
L|LK) account_locked=true ;;
|
|
esac
|
|
shell_exists=false
|
|
shell_executable=false
|
|
[ -n "$shell" ] && [ -e "$shell" ] && shell_exists=true
|
|
[ -n "$shell" ] && [ -x "$shell" ] && shell_executable=true
|
|
|
|
echo "USER_STATUS user=$user exists=1 home=$home_dir"
|
|
echo "ACCOUNT_METADATA user=$user passwd_status=${passwd_status:-unknown} account_locked=${account_locked} shell=${shell:-unknown} shell_exists=${shell_exists} shell_executable=${shell_executable}"
|
|
stat_path "$home_dir"
|
|
stat_path "$home_dir/.ssh"
|
|
stat_path "$home_dir/.ssh/authorized_keys"
|
|
if [ -f "$home_dir/.ssh/authorized_keys" ]; then
|
|
echo "AUTHORIZED_KEYS_STATUS path=$home_dir/.ssh/authorized_keys exists=1 bytes=$(wc -c < "$home_dir/.ssh/authorized_keys" | tr -d ' ') lines=$(wc -l < "$home_dir/.ssh/authorized_keys" | tr -d ' ')"
|
|
else
|
|
echo "AUTHORIZED_KEYS_STATUS path=$home_dir/.ssh/authorized_keys exists=0"
|
|
fi
|
|
}
|
|
|
|
check_sshd_effective_config() {
|
|
local user="$1"
|
|
local effective pubkey password kbdinteractive usepam maxstartups authorized_keys_file_default
|
|
effective="$(sshd -T -C "user=$user,host=localhost,addr=127.0.0.1" 2>/dev/null || true)"
|
|
if [ -z "$effective" ]; then
|
|
echo "SSHD_EFFECTIVE_CONFIG available=false"
|
|
return 0
|
|
fi
|
|
|
|
pubkey="$(printf '%s\n' "$effective" | awk '$1 == "pubkeyauthentication" {print $2; exit}')"
|
|
password="$(printf '%s\n' "$effective" | awk '$1 == "passwordauthentication" {print $2; exit}')"
|
|
kbdinteractive="$(printf '%s\n' "$effective" | awk '$1 == "kbdinteractiveauthentication" {print $2; exit}')"
|
|
usepam="$(printf '%s\n' "$effective" | awk '$1 == "usepam" {print $2; exit}')"
|
|
maxstartups="$(printf '%s\n' "$effective" | awk '$1 == "maxstartups" {print $2; exit}')"
|
|
if printf '%s\n' "$effective" | awk '$1 == "authorizedkeysfile" {$1=""; print}' | grep -q '\.ssh/authorized_keys'; then
|
|
authorized_keys_file_default=true
|
|
else
|
|
authorized_keys_file_default=false
|
|
fi
|
|
echo "SSHD_EFFECTIVE_CONFIG available=true pubkeyauthentication=${pubkey:-unknown} passwordauthentication=${password:-unknown} kbdinteractiveauthentication=${kbdinteractive:-unknown} usepam=${usepam:-unknown} maxstartups=${maxstartups:-unknown} authorized_keys_file_default=${authorized_keys_file_default}"
|
|
}
|
|
|
|
check_sshd_config_syntax() {
|
|
local label="$1"
|
|
local output rc reason
|
|
|
|
if output="$(sshd -t 2>&1)"; then
|
|
echo "${label}=ok"
|
|
return 0
|
|
fi
|
|
rc=$?
|
|
|
|
reason="sshd_t_failed"
|
|
if printf '%s\n' "$output" | grep -Eiq 'hostkey|host key|permission|no hostkeys'; then
|
|
reason="hostkeys_unavailable_or_permission"
|
|
fi
|
|
if [ "$APPLY" -eq 0 ]; then
|
|
echo "${label}=unverified_requires_root rc=$rc reason=$reason"
|
|
return 0
|
|
fi
|
|
|
|
echo "${label}=failed rc=$rc reason=$reason" >&2
|
|
return "$rc"
|
|
}
|
|
|
|
apply_user_permissions() {
|
|
local user="$1"
|
|
local home_dir
|
|
home_dir="$(getent passwd "$user" | awk -F: '{print $6}')"
|
|
if [ -z "$home_dir" ]; then
|
|
echo "BLOCKED target user missing: $user" >&2
|
|
exit 66
|
|
fi
|
|
if [ ! -d "$home_dir/.ssh" ]; then
|
|
echo "BLOCKED missing $home_dir/.ssh; not creating key material or SSH directories automatically" >&2
|
|
exit 67
|
|
fi
|
|
if [ ! -f "$home_dir/.ssh/authorized_keys" ]; then
|
|
echo "BLOCKED missing $home_dir/.ssh/authorized_keys; not creating key material automatically" >&2
|
|
exit 68
|
|
fi
|
|
|
|
chown "$user:$user" "$home_dir/.ssh" "$home_dir/.ssh/authorized_keys"
|
|
chmod 700 "$home_dir/.ssh"
|
|
chmod 600 "$home_dir/.ssh/authorized_keys"
|
|
echo "APPLIED permissions target_user=$user home=$home_dir"
|
|
}
|
|
|
|
require_110_or_explicit
|
|
|
|
echo "AWOOOI_110_SSH_PUBLICKEY_AUTH_LOCAL_REPAIR mode=$([ "$APPLY" -eq 1 ] && echo apply || echo check) target_user=$TARGET_USER"
|
|
systemctl is-active ssh 2>/dev/null | sed 's/^/SSH_SERVICE_ACTIVE=/' || true
|
|
check_sshd_config_syntax "SSHD_CONFIG_SYNTAX"
|
|
check_user "$TARGET_USER"
|
|
check_sshd_effective_config "$TARGET_USER"
|
|
|
|
if [ "$APPLY" -eq 1 ]; then
|
|
apply_user_permissions "$TARGET_USER"
|
|
check_sshd_config_syntax "SSHD_CONFIG_SYNTAX_AFTER_APPLY"
|
|
if [ "$RELOAD_SSH" = "1" ]; then
|
|
systemctl reload ssh
|
|
echo "SSH_RELOAD=done"
|
|
else
|
|
echo "SSH_RELOAD=skipped"
|
|
fi
|
|
fi
|