Blueforce-Linux/scripts/install/installer/modules/03-user.sh
2026-09-17 13:22:26 +03:00

64 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# Dealer-specific Blueforce user, restricted sudoers, mandatory administrator key.
set -euo pipefail
MODULE="03-user"
LOG_FILE="${LOG_FILE:-/var/log/blueforce-install.log}"
CHECK_MODE=0
[[ "${1:-}" == "--check" ]] && CHECK_MODE=1
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=../identity.sh
source "$SCRIPT_DIR/identity.sh"
DEALER_ID="${DEALER_ID:-}"
[[ -n "$DEALER_ID" ]] && bf_valid_dealer_id "$DEALER_ID" || { echo "FAIL: valid DEALER_ID is required" >&2; exit 1; }
BF_USER="$(bf_username "$DEALER_ID")"
BF_HOME="/home/$BF_USER"
SUDOERS_FILE="/etc/sudoers.d/$BF_USER"
AUTHORIZED_KEYS="$BF_HOME/.ssh/authorized_keys"
BF_ADMIN_PUBLIC_KEY="${BF_ADMIN_PUBLIC_KEY:-}"
BF_ADMIN_PUBLIC_KEY_FILE="${BF_ADMIN_PUBLIC_KEY_FILE:-}"
log() { echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) [03-user] $1" | tee -a "$LOG_FILE"; }
valid_key_file() { [[ -s "$AUTHORIZED_KEYS" ]] && ssh-keygen -l -f "$AUTHORIZED_KEYS" >/dev/null 2>&1; }
load_admin_key() {
[[ -z "$BF_ADMIN_PUBLIC_KEY" && -n "$BF_ADMIN_PUBLIC_KEY_FILE" && -r "$BF_ADMIN_PUBLIC_KEY_FILE" ]] || { log "FAIL: a seed-provided BF_ADMIN_PUBLIC_KEY_FILE is required; inline keys are refused"; return 1; }
[[ "$(stat -c '%U:%a' "$BF_ADMIN_PUBLIC_KEY_FILE")" =~ ^root:6[04]0$ ]] || { log "FAIL: administrator key file must be root-owned and not group/world writable"; return 1; }
grep -qE '^(ssh-(ed25519|rsa|ecdsa)|sk-ssh-ed25519)' "$BF_ADMIN_PUBLIC_KEY_FILE" && ! grep -q 'PRIVATE KEY' "$BF_ADMIN_PUBLIC_KEY_FILE" || { log "FAIL: administrator key file must contain a public SSH key only"; return 1; }
cat "$BF_ADMIN_PUBLIC_KEY_FILE"
}
if [[ "$CHECK_MODE" -eq 1 ]]; then
id "$BF_USER" >/dev/null 2>&1 || { log "FAIL(check): user $BF_USER missing"; exit 1; }
[[ -f "$SUDOERS_FILE" ]] && visudo -cf "$SUDOERS_FILE" >/dev/null 2>&1 || { log "FAIL(check): sudoers invalid"; exit 1; }
valid_key_file || { log "FAIL(check): authorized_keys is empty or invalid"; exit 1; }
log "OK(check): user, sudoers, and a valid administrator key are present"; exit 0
fi
key_data="$(load_admin_key)" || exit 1
[[ -n "${key_data//[[:space:]]/}" ]] || { log "FAIL: administrator key is empty"; exit 1; }
tmp_key="$(mktemp)"; trap 'rm -f "$tmp_key"' EXIT
printf '%s\n' "$key_data" > "$tmp_key"
ssh-keygen -l -f "$tmp_key" >/dev/null 2>&1 || { log "FAIL: supplied administrator public key is invalid"; exit 1; }
if id "$BF_USER" >/dev/null 2>&1; then
if id blueforce >/dev/null 2>&1 && [[ "$BF_USER" != blueforce ]]; then
log "FAIL: both legacy blueforce and target $BF_USER accounts exist; refusing automatic merge"
exit 1
fi
elif id blueforce >/dev/null 2>&1; then
usermod -l "$BF_USER" blueforce
if getent group blueforce >/dev/null 2>&1 && ! getent group "$BF_USER" >/dev/null 2>&1; then
groupmod -n "$BF_USER" blueforce
fi
usermod -d "$BF_HOME" -m "$BF_USER"
else
useradd -m -s /bin/bash "$BF_USER"
fi
passwd -l "$BF_USER" >/dev/null 2>&1 || true
install -d -m 700 -o "$BF_USER" -g "$BF_USER" "$BF_HOME/.ssh"
install -m 600 -o "$BF_USER" -g "$BF_USER" "$tmp_key" "$AUTHORIZED_KEYS"
valid_key_file || { log "FAIL: atomic authorized_keys install did not validate"; exit 1; }
cat > "/tmp/$BF_USER.sudoers" <<EOF
# Managed by blueforce-installer (03-user). Local edits will be overwritten.
$BF_USER ALL=(root) NOPASSWD: /usr/local/bin/bf-status, /usr/local/bin/bf-gui-on, /usr/local/bin/bf-gui-off, /bin/systemctl status *, /bin/systemctl is-active *, /bin/systemctl is-enabled *, /usr/bin/docker ps, /usr/bin/docker logs *
EOF
visudo -cf "/tmp/$BF_USER.sudoers"
install -m 440 "/tmp/$BF_USER.sudoers" "$SUDOERS_FILE"
rm -f /etc/sudoers.d/blueforce
bf_write_identity "$DEALER_ID" || { log "FAIL: dealer identity could not be locked"; exit 1; }
log "OK: user $BF_USER has a validated administrator key and restricted sudoers"