#!/usr/bin/env bash
set -euo pipefail

# ssh-hardening-check.sh
#
# Purpose:
#   Validate a CentOS 7 SSH key-based authentication rollout before disabling
#   password login.
#
# Safe by design:
#   - No destructive changes are made.
#   - No SSH configuration is modified.
#   - No keys are generated or copied automatically.
#   - Use this from a trusted admin workstation and a separate terminal session.
#
# Usage:
#   ./ssh-hardening-check.sh -u user -h server.example.com [-i ~/.ssh/id_ed25519]
#
# Examples:
#   ./ssh-hardening-check.sh -u admin -h 192.0.2.10
#   ./ssh-hardening-check.sh -u admin -h server.example.com -i ~/.ssh/id_ed25519
#
# Notes:
#   - If you run this on the server itself, the local checks can still help,
#     but remote login verification should be done from a second session.

usage() {
  cat <<'EOF'
Usage: ssh-hardening-check.sh -u USER -h HOST [-p PORT] [-i IDENTITY] [--skip-remote]

Required:
  -u USER        Remote username to test
  -h HOST        Remote host or IP address

Optional:
  -p PORT        SSH port (default: 22)
  -i IDENTITY    Private key path to use for testing (default: ~/.ssh/id_ed25519)
  --skip-remote  Skip remote SSH login tests and only run local checks
  -? | --help    Show this help text
EOF
}

REMOTE_USER=""
REMOTE_HOST=""
SSH_PORT="22"
IDENTITY_FILE="${HOME}/.ssh/id_ed25519"
SKIP_REMOTE="false"

while [[ $# -gt 0 ]]; do
  case "$1" in
    -u)
      REMOTE_USER="${2:-}"
      shift 2
      ;;
    -h)
      REMOTE_HOST="${2:-}"
      shift 2
      ;;
    -p)
      SSH_PORT="${2:-}"
      shift 2
      ;;
    -i)
      IDENTITY_FILE="${2:-}"
      shift 2
      ;;
    --skip-remote)
      SKIP_REMOTE="true"
      shift
      ;;
    -? | --help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage >&2
      exit 1
      ;;
  esac
done

if [[ -z "$REMOTE_USER" || -z "$REMOTE_HOST" ]]; then
  echo "Error: both -u USER and -h HOST are required." >&2
  usage >&2
  exit 1
fi

info() { printf '[INFO] %s\n' "$*"; }
warn() { printf '[WARN] %s\n' "$*"; }
pass() { printf '[ OK ] %s\n' "$*"; }
fail() { printf '[FAIL] %s\n' "$*"; exit 1; }

info "Local environment checks"

if command -v ssh >/dev/null 2>&1; then
  pass "ssh client is installed"
else
  fail "ssh client is not installed"
fi

if [[ -f "$IDENTITY_FILE" ]]; then
  pass "Identity file exists: $IDENTITY_FILE"
else
  fail "Identity file not found: $IDENTITY_FILE"
fi

if [[ -f "${IDENTITY_FILE}.pub" ]]; then
  pass "Public key exists: ${IDENTITY_FILE}.pub"
else
  warn "Public key not found next to the private key: ${IDENTITY_FILE}.pub"
fi

if [[ -r "$IDENTITY_FILE" ]]; then
  pass "Private key is readable by the current user"
else
  fail "Private key is not readable"
fi

if command -v stat >/dev/null 2>&1; then
  KEY_PERMS="$(stat -c '%a' "$IDENTITY_FILE" 2>/dev/null || true)"
  if [[ -n "$KEY_PERMS" ]]; then
    if [[ "$KEY_PERMS" =~ ^(600|400|440)$ ]]; then
      pass "Private key permissions look acceptable: $KEY_PERMS"
    else
      warn "Private key permissions may be too open: $KEY_PERMS"
    fi
  fi
fi

info "Remote SSH service and configuration checks"

if [[ "$SKIP_REMOTE" == "true" ]]; then
  warn "Remote checks skipped by request"
else
  if command -v ssh >/dev/null 2>&1; then
    info "Testing key-based login to ${REMOTE_USER}@${REMOTE_HOST}:${SSH_PORT}"
    SSH_OPTS=(
      -i "$IDENTITY_FILE"
      -p "$SSH_PORT"
      -o BatchMode=yes
      -o ConnectTimeout=10
      -o PreferredAuthentications=publickey
      -o PasswordAuthentication=no
      -o StrictHostKeyChecking=accept-new
    )

    if ssh "${SSH_OPTS[@]}" "${REMOTE_USER}@${REMOTE_HOST}" 'hostname && whoami' >/tmp/ssh-hardening-check.out 2>/tmp/ssh-hardening-check.err; then
      pass "Key-based SSH login succeeded"
      cat /tmp/ssh-hardening-check.out
    else
      warn "Key-based SSH login failed"
      warn "Client output:"
      sed 's/^/[SSH] /' /tmp/ssh-hardening-check.err || true
      warn "Common causes: wrong key, wrong username, permissions on ~/.ssh, or sshd config not yet reloaded"
    fi
    rm -f /tmp/ssh-hardening-check.out /tmp/ssh-hardening-check.err
  else
    fail "ssh client is unavailable for remote verification"
  fi
fi

info "Manual server-side verification reminders"
cat <<EOF
- Confirm sshd is running: systemctl status sshd
- Validate syntax before reload: sudo sshd -t
- Confirm effective settings: sudo sshd -T | egrep 'pubkeyauthentication|passwordauthentication|challengeresponseauthentication|permitrootlogin'
- Ensure the target account's ~/.ssh permissions are 700 and authorized_keys is 600
- Test from a second session before disabling password authentication
EOF

pass "Validation script completed"