#!/usr/bin/env bash # audit_ssh_config # ---------------- # Audita la configuración de sshd_config evaluando parámetros de seguridad, # revisa intentos de login fallidos y lista las claves autorizadas del usuario. # # USO (directo): # audit_ssh_config [/ruta/a/sshd_config] # # Depende de: grep, ssh (opcional para validación), journalctl o /var/log/auth.log SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../shell/bash_colors.sh" source "$SCRIPT_DIR/../shell/bash_log.sh" bash_colors bash_log_init # ─── Funciones puras ────────────────────────────────────────────────────────── _ssh_get_value() { local config="$1" local key="$2" grep -iE "^[[:space:]]*${key}[[:space:]]" "$config" 2>/dev/null \ | tail -1 | awk '{print $2}' | xargs } _ssh_eval_permit_root() { local val="${1:-yes}" case "${val,,}" in no|prohibit-password) echo "ok" ;; without-password) echo "warn" ;; *) echo "bad" ;; esac } _ssh_eval_password_auth() { local val="${1:-yes}" [[ "${val,,}" == "no" ]] && echo "ok" || echo "bad" } _ssh_eval_max_auth_tries() { local val="${1:-6}" [[ "$val" -le 3 ]] && echo "ok" || echo "warn" } _ssh_eval_x11_forwarding() { local val="${1:-no}" [[ "${val,,}" == "no" ]] && echo "ok" || echo "warn" } # ─── Funciones de presentación ──────────────────────────────────────────────── _ssh_print_check() { local level="$1" local label="$2" local value="$3" local note="$4" case "$level" in ok) echo -e " ${GREEN}[ok]${NC} ${label}: ${value}" ;; warn) echo -e " ${YELLOW}[!] ${NC} ${label}: ${value} -- ${note}" ;; bad) echo -e " ${RED}[x] ${NC} ${label}: ${value} -- ${note}" ;; esac } _ssh_show_config_checks() { local config="$1" echo -e "${PURPLE}════════ Configuración sshd_config ════════════${NC}" echo "" local permit_root permit_root="$(_ssh_get_value "$config" "PermitRootLogin")" permit_root="${permit_root:-yes (por defecto)}" _ssh_print_check "$(_ssh_eval_permit_root "$permit_root")" \ "PermitRootLogin" "$permit_root" "debería ser 'no' o 'prohibit-password'" local pass_auth pass_auth="$(_ssh_get_value "$config" "PasswordAuthentication")" pass_auth="${pass_auth:-yes (por defecto)}" _ssh_print_check "$(_ssh_eval_password_auth "$pass_auth")" \ "PasswordAuthentication" "$pass_auth" "debería ser 'no' (usar claves)" local port port="$(_ssh_get_value "$config" "Port")" port="${port:-22 (por defecto)}" if [[ "$port" == "22"* ]]; then _ssh_print_check "warn" "Port" "$port" "considera cambiar el puerto 22" else _ssh_print_check "ok" "Port" "$port" "" fi local max_tries max_tries="$(_ssh_get_value "$config" "MaxAuthTries")" max_tries="${max_tries:-6 (por defecto)}" _ssh_print_check "$(_ssh_eval_max_auth_tries "${max_tries%% *}")" \ "MaxAuthTries" "$max_tries" "recomendado <= 3" local x11 x11="$(_ssh_get_value "$config" "X11Forwarding")" x11="${x11:-no (por defecto)}" _ssh_print_check "$(_ssh_eval_x11_forwarding "$x11")" \ "X11Forwarding" "$x11" "deshabilitar si no se usa" local allow_users allow_groups allow_users="$(_ssh_get_value "$config" "AllowUsers")" allow_groups="$(_ssh_get_value "$config" "AllowGroups")" if [[ -z "$allow_users" && -z "$allow_groups" ]]; then _ssh_print_check "warn" "AllowUsers/AllowGroups" "(no definidos)" "considera restringir acceso por usuario o grupo" else [[ -n "$allow_users" ]] && _ssh_print_check "ok" "AllowUsers" "$allow_users" "" [[ -n "$allow_groups" ]] && _ssh_print_check "ok" "AllowGroups" "$allow_groups" "" fi echo "" } _ssh_show_failed_logins() { echo -e "${PURPLE}════════ Últimos intentos de login fallidos ════${NC}" echo "" if command -v journalctl &>/dev/null; then journalctl -u ssh -u sshd --no-pager -q 2>/dev/null \ | grep -i "failed\|invalid\|error" | tail -10 \ | while IFS= read -r line; do echo -e " ${DIM_GRAY}${line}${NC}"; done || true elif [[ -f /var/log/auth.log ]]; then grep -i "failed\|invalid" /var/log/auth.log 2>/dev/null | tail -10 \ | while IFS= read -r line; do echo -e " ${DIM_GRAY}${line}${NC}"; done || true else info "No se encontró fuente de logs de autenticación" fi echo "" } _ssh_show_authorized_keys() { echo -e "${PURPLE}════════ Claves autorizadas (~/.ssh) ═══════════${NC}" echo "" local auth_keys="$HOME/.ssh/authorized_keys" if [[ -f "$auth_keys" ]]; then local count count="$(wc -l < "$auth_keys")" info "${count} clave(s) en authorized_keys:" while IFS= read -r line; do [[ -z "$line" || "$line" == "#"* ]] && continue local key_type key_comment key_type="$(echo "$line" | awk '{print $1}')" key_comment="$(echo "$line" | awk '{print $NF}')" echo -e " ${GREEN}*${NC} ${key_type} -- ${key_comment}" done < "$auth_keys" else info "No existe $auth_keys" fi echo "" } # ─── Punto de entrada ───────────────────────────────────────────────────────── audit_ssh_config() { local config_path="${1:-/etc/ssh/sshd_config}" if [[ ! -f "$config_path" ]]; then warning "audit_ssh_config: no se encontró $config_path -- ¿está instalado sshd?" else _ssh_show_config_checks "$config_path" fi _ssh_show_failed_logins _ssh_show_authorized_keys } # Ejecutar si se llama directamente if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then audit_ssh_config "$@" fi