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

# ssh-key-harden.sh
#
# Purpose:
#   Help harden SSH access on Ubuntu by using key-based authentication first,
#   then optionally disabling password logins only after you confirm key access works.
#
# Safety:
#   - No destructive default actions.
#   - Does not generate or store credentials on your behalf.
#   - Recommends keeping an existing SSH session open before applying changes.
#   - Designed for Ubuntu/OpenSSH systems.
#
# Usage examples:
#   ./ssh-key-harden.sh status
#   ./ssh-key-harden.sh client-keygen
#   ./ssh-key-harden.sh install-key --user alice --host server.example.com --identity ~/.ssh/id_ed25519
#   ./ssh-key-harden.sh verify --user alice --host server.example.com --identity ~/.ssh/id_ed25519
#   ./ssh-key-harden.sh harden-server
#   ./ssh-key-harden.sh validate-server
#   ./ssh-key-harden.sh test-password-block --user alice --host server.example.com
#
# Notes:
#   - 'install-key' and 'verify' are client-side actions.
#   - 'harden-server' and 'validate-server' must run on the Ubuntu server with sudo access.

usage() {
  cat <<'EOF'
Usage:
  ssh-key-harden.sh <command> [options]

Commands:
  status                 Show what the script can help with.
  client-keygen          Print a recommended ssh-keygen command.
  install-key            Copy a public key to a server using ssh-copy-id (client-side).
  verify                 Verify key-based SSH login (client-side).
  harden-server          Print safe SSH daemon hardening steps (server-side).
  validate-server        Show commands to validate effective sshd settings (server-side).
  test-password-block    Show a safe password-auth test command (client-side).

Options for install-key / verify / test-password-block:
  --user USER            Remote username.
  --host HOST            Remote host or IP.
  --port PORT            SSH port (default: 22).
  --identity FILE        Private key path for login tests (default: ~/.ssh/id_ed25519).
  --pubkey FILE          Public key path for install-key (default: identity with .pub).

Examples:
  ssh-key-harden.sh client-keygen
  ssh-key-harden.sh install-key --user alice --host 192.0.2.10 --identity ~/.ssh/id_ed25519
  ssh-key-harden.sh verify --user alice --host 192.0.2.10 --identity ~/.ssh/id_ed25519
  sudo ssh-key-harden.sh harden-server
  sudo ssh-key-harden.sh validate-server
EOF
}

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
}

expand_path() {
  local p="$1"
  printf '%s\n' "${p/#\~/$HOME}"
}

USER_NAME=""
HOST_NAME=""
PORT="22"
IDENTITY_FILE="~/.ssh/id_ed25519"
PUBKEY_FILE=""

shift_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --user)
        USER_NAME="${2:-}"
        shift 2
        ;;
      --host)
        HOST_NAME="${2:-}"
        shift 2
        ;;
      --port)
        PORT="${2:-22}"
        shift 2
        ;;
      --identity)
        IDENTITY_FILE="${2:-}"
        shift 2
        ;;
      --pubkey)
        PUBKEY_FILE="${2:-}"
        shift 2
        ;;
      -h|--help)
        usage
        exit 0
        ;;
      *)
        echo "Error: unknown option: $1" >&2
        usage
        exit 1
        ;;
    esac
  done
}

command_name="${1:-}"
if [[ -z "$command_name" ]]; then
  usage
  exit 1
fi
shift || true

case "$command_name" in
  status)
    cat <<'EOF'
SSH key-based authentication hardening workflow:
  1) Generate a key pair on your admin workstation.
  2) Install the public key for the target user on the server.
  3) Open a second session and verify key login works.
  4) Update sshd_config to disable password authentication.
  5) Validate the configuration and reload SSH.
  6) Confirm key login still works and password login is blocked.
EOF
    ;;

  client-keygen)
    cat <<'EOF'
Recommended key generation command:
  ssh-keygen -t ed25519 -a 100 -C "your_name@example.com"

Suggested practice:
  - Save the private key in ~/.ssh/id_ed25519 or another protected location.
  - Use a passphrase for interactive admin access.
EOF
    ;;

  install-key)
    shift_args "$@"
    require_cmd ssh-copy-id

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

    resolved_identity="$(expand_path "$IDENTITY_FILE")"
    if [[ -z "$PUBKEY_FILE" ]]; then
      PUBKEY_FILE="${resolved_identity}.pub"
    fi
    resolved_pubkey="$(expand_path "$PUBKEY_FILE")"

    if [[ ! -f "$resolved_pubkey" ]]; then
      echo "Error: public key not found: $resolved_pubkey" >&2
      exit 1
    fi

    echo "Running safe key installation command:"
    echo "ssh-copy-id -i '$resolved_pubkey' -p '$PORT' '$USER_NAME@$HOST_NAME'"
    echo
    echo "Tip: confirm the key works in a second terminal before changing server authentication settings."
    ;;

  verify)
    shift_args "$@"
    require_cmd ssh

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

    resolved_identity="$(expand_path "$IDENTITY_FILE")"
    if [[ ! -f "$resolved_identity" ]]; then
      echo "Error: identity file not found: $resolved_identity" >&2
      exit 1
    fi

    echo "Testing key-based login with a new SSH session:"
    echo "ssh -i '$resolved_identity' -p '$PORT' '$USER_NAME@$HOST_NAME'"
    echo
    echo "If you need troubleshooting detail, try:"
    echo "ssh -v -i '$resolved_identity' -p '$PORT' '$USER_NAME@$HOST_NAME'"
    ;;

  harden-server)
    cat <<'EOF'
Server-side hardening steps for Ubuntu:
  1) Keep an active SSH session open.
  2) Edit sshd configuration:
       sudoedit /etc/ssh/sshd_config
  3) Ensure these settings are present:
       PubkeyAuthentication yes
       PasswordAuthentication no
       KbdInteractiveAuthentication no
       PermitRootLogin no
  4) Check for overrides in /etc/ssh/sshd_config.d/
  5) Validate syntax before reloading:
       sudo sshd -t
  6) Reload SSH:
       sudo systemctl reload ssh
  7) Verify key login still works before ending your original session.
EOF
    ;;

  validate-server)
    cat <<'EOF'
Validate the effective SSH daemon settings on the server:
  sudo sshd -T | grep -E 'pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin'

Check recent logs if needed:
  sudo journalctl -u ssh -n 50 --no-pager
  sudo tail -n 50 /var/log/auth.log
EOF
    ;;

  test-password-block)
    shift_args "$@"
    require_cmd ssh

    if [[ -z "$USER_NAME" || -z "$HOST_NAME" ]]; then
      echo "Error: --user and --host are required for test-password-block." >&2
      exit 1
    fi

    echo "Use this to confirm password authentication is blocked after hardening:"
    echo "ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no -p '$PORT' '$USER_NAME@$HOST_NAME'"
    echo
    echo "Expected outcome: authentication should fail if password logins are disabled."
    ;;

  -h|--help|help)
    usage
    ;;

  *)
    echo "Error: unknown command: $command_name" >&2
    usage
    exit 1
    ;;
esac