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

# CentOS 8 SSH Key Authentication Hardening Helper
#
# Purpose:
#   Validate the common prerequisites for SSH key authentication hardening
#   before you disable password logins on a CentOS 8 host.
#
# What this script does:
#   - Checks local SSH client availability
#   - Validates the target account, public key file, and SSH directory permissions
#   - Optionally tests an SSH login with a specified key
#   - Optionally runs a remote command to confirm the intended authentication path
#   - Prints a safe checklist for production readiness
#
# What this script does NOT do:
#   - It does not modify sshd configuration
#   - It does not remove passwords
#   - It does not restart services
#   - It does not copy keys automatically
#
# Usage examples:
#   ./centos8-ssh-key-harden-check.sh --user alice --host server.example
#   ./centos8-ssh-key-harden-check.sh --user alice --host server.example --key ~/.ssh/id_ed25519
#   ./centos8-ssh-key-harden-check.sh --user alice --host server.example --remote-cmd 'whoami'
#
# Notes:
#   - Run this from the client system that will connect to the CentOS 8 host.
#   - If you omit --key, the script will use your SSH agent/default keys for the test.
#   - For non-interactive use, ensure the private key is available locally and unlocked.

usage() {
  cat <<'EOF'
Usage:
  centos8-ssh-key-harden-check.sh --user USER --host HOST [options]

Required:
  --user USER           Target SSH account on the CentOS 8 host
  --host HOST           Hostname or IP address of the SSH server

Optional:
  --key PATH            Path to private key file used for the login test
  --port PORT           SSH port (default: 22)
  --remote-cmd CMD      Remote command to run after login succeeds
  --expected-user USER  Expected remote username output for validation
  --skip-ssh-test       Skip the SSH connectivity test
  --help                Show this help text

Examples:
  ./centos8-ssh-key-harden-check.sh --user alice --host 192.0.2.10 --key ~/.ssh/id_ed25519
  ./centos8-ssh-key-harden-check.sh --user alice --host bastion.example --remote-cmd 'id -un'
EOF
}

USER_NAME=""
HOST_NAME=""
KEY_PATH=""
PORT="22"
REMOTE_CMD=""
EXPECTED_USER=""
SKIP_SSH_TEST="false"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --user)
      USER_NAME="${2:-}"
      shift 2
      ;;
    --host)
      HOST_NAME="${2:-}"
      shift 2
      ;;
    --key)
      KEY_PATH="${2:-}"
      shift 2
      ;;
    --port)
      PORT="${2:-}"
      shift 2
      ;;
    --remote-cmd)
      REMOTE_CMD="${2:-}"
      shift 2
      ;;
    --expected-user)
      EXPECTED_USER="${2:-}"
      shift 2
      ;;
    --skip-ssh-test)
      SKIP_SSH_TEST="true"
      shift
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage
      exit 1
      ;;
  esac
done

require_cmd() {
  local cmd="$1"
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "ERROR: Required command not found: $cmd" >&2
    exit 1
  fi
}

trim_tilde() {
  local input="$1"
  if [[ "$input" == ~/* ]]; then
    printf '%s\n' "$HOME/${input:2}"
  else
    printf '%s\n' "$input"
  fi
}

require_cmd ssh
require_cmd stat
require_cmd awk

if [[ -z "$USER_NAME" || -z "$HOST_NAME" ]]; then
  echo "ERROR: --user and --host are required." >&2
  usage
  exit 1
fi

if [[ -n "$KEY_PATH" ]]; then
  KEY_PATH="$(trim_tilde "$KEY_PATH")"
fi

echo "== SSH Key Authentication Readiness Check =="
echo "Target user : $USER_NAME"
echo "Target host : $HOST_NAME"
echo "Target port : $PORT"
if [[ -n "$KEY_PATH" ]]; then
  echo "Key file    : $KEY_PATH"
else
  echo "Key file    : (default agent/default identity handling)"
fi

echo

echo "[1/6] Local prerequisites"
if [[ -n "$KEY_PATH" ]]; then
  if [[ ! -f "$KEY_PATH" ]]; then
    echo "ERROR: Private key file not found: $KEY_PATH" >&2
    exit 1
  fi
  if [[ ! -r "$KEY_PATH" ]]; then
    echo "ERROR: Private key file is not readable: $KEY_PATH" >&2
    exit 1
  fi
fi

echo "OK: Local inputs look valid."

echo

echo "[2/6] Recommended production checks"
cat <<'EOF'
- Confirm the target account has the intended public key in ~/.ssh/authorized_keys
- Confirm ~/.ssh is owned by the target user and not group/world writable
- Confirm authorized_keys is owned by the target user and not group/world writable
- Confirm you have a console, out-of-band, or break-glass recovery path
- Confirm you have tested access from the same network path you will use in production
EOF

echo

echo "[3/6] Optional permission reminders"
cat <<'EOF'
Typical safe permissions on the target host:
  ~/.ssh          700
  ~/.ssh/authorized_keys 600
Ownership:
  The target user should own both the home SSH directory and authorized_keys
EOF

echo

echo "[4/6] SSH login test"
if [[ "$SKIP_SSH_TEST" == "true" ]]; then
  echo "Skipped by request."
else
  SSH_BASE_OPTS=(-p "$PORT" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new)
  if [[ -n "$KEY_PATH" ]]; then
    SSH_BASE_OPTS+=(-i "$KEY_PATH")
  fi

  echo "Attempting key-based connection..."
  if [[ -n "$REMOTE_CMD" ]]; then
    if ssh "${SSH_BASE_OPTS[@]}" "${USER_NAME}@${HOST_NAME}" "$REMOTE_CMD"; then
      echo "OK: Remote command succeeded over SSH."
    else
      echo "ERROR: Remote command failed. Review authentication, network reachability, and server-side logs." >&2
      exit 1
    fi
  else
    if ssh "${SSH_BASE_OPTS[@]}" "${USER_NAME}@${HOST_NAME}" 'true'; then
      echo "OK: SSH key-based login test succeeded."
    else
      echo "ERROR: SSH key-based login test failed." >&2
      echo "Hint: Re-run with --remote-cmd 'id -un' or use -vvv externally for more detail." >&2
      exit 1
    fi
  fi
fi

echo

echo "[5/6] Password-login probe guidance"
cat <<'EOF'
If you expect password logins to be disabled, validate that separately from a trusted admin path.
Example probe:
  ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no USER@HOST
Observe whether the server still permits a password path for the intended account.
EOF

echo

echo "[6/6] Final production readiness questions"
cat <<'EOF'
Before disabling password authentication, you should be able to answer:
  1. Which users still need SSH access?
  2. Which keys correspond to those users?
  3. What is your recovery path if the key or client is unavailable?
EOF

if [[ -n "$EXPECTED_USER" ]]; then
  echo
  echo "[Validation] Expected remote user check"
  echo "If you ran a remote command that prints the username, confirm it matches: $EXPECTED_USER"
fi

echo
echo "Done. No changes were made to the server."