nigig-org/nimanyatta/deploy/verify-hardening.sh
andodeki fd8b0632ca
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
Include nimanyatta as normal tree (not embedded git)
2026-09-26 09:29:36 +03:00

106 lines
4.2 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# verify-hardening.sh - Idempotent audit of the VPS hardening state.
#
# Safe to run any time, as root or via sudo. Exit code 0 = all checks pass,
# non-zero = at least one check failed. Prints a PASS/FAIL line per check.
#
# sudo bash deploy/verify-hardening.sh
#
set -uo pipefail
DEPLOY_USER="${DEPLOY_USER:-deploy}"
SSH_PORT="${SSH_PORT:-22}"
GREEN='\033[0;32m'; RED='\033[0;31m'; NC='\033[0m'
pass() { echo -e "${GREEN}[PASS]${NC} $*"; }
fail() { echo -e "${RED}[FAIL]${NC} $*"; FAILED=$((FAILED + 1)); }
FAILED=0
# ── 1. Non-root deploy user exists ─────────────────────────────────────────
if id "${DEPLOY_USER}" >/dev/null 2>&1; then
pass "deploy user '${DEPLOY_USER}' exists"
else
fail "deploy user '${DEPLOY_USER}' does not exist"
fi
# ── 2. Root SSH login disabled ─────────────────────────────────────────────
if grep -qE '^\s*PermitRootLogin\s+no' /etc/ssh/sshd_config 2>/dev/null; then
pass "PermitRootLogin is 'no'"
else
fail "PermitRootLogin is not 'no'"
fi
# ── 3. Password auth disabled ──────────────────────────────────────────────
if grep -qE '^\s*PasswordAuthentication\s+no' /etc/ssh/sshd_config 2>/dev/null; then
pass "PasswordAuthentication is 'no'"
else
fail "PasswordAuthentication is not 'no'"
fi
# ── 4. Deploy user key exists and is locked down ───────────────────────────
KEY="${DEPLOY_USER}"
KEYFILE="/home/${KEY}/.ssh/authorized_keys"
if [ -f "${KEYFILE}" ] && [ -s "${KEYFILE}" ]; then
pass "authorized_keys present for '${KEY}'"
[ "$(stat -c '%a' "${KEYFILE}" 2>/dev/null)" = "600" ] && \
pass "authorized_keys mode is 600" || fail "authorized_keys mode is not 600"
else
fail "no authorized_keys for '${KEY}'"
fi
# ── 5. SSH config is valid ─────────────────────────────────────────────────
if sshd -t 2>/dev/null; then
pass "sshd_config validates"
else
fail "sshd_config does NOT validate"
fi
# ── 6. Firewall active and restrictive ─────────────────────────────────────
if command -v ufw >/dev/null 2>&1; then
if ufw status | grep -q "Status: active"; then
pass "UFW is active"
if ufw status verbose | grep -qE "Deny|deny"; then
pass "UFW default deny in place"
else
fail "UFW default policy not 'deny incoming'"
fi
else
fail "UFW is not active"
fi
else
fail "ufw not installed"
fi
# ── 7. fail2ban active ─────────────────────────────────────────────────────
if systemctl is-active --quiet fail2ban 2>/dev/null; then
pass "fail2ban is active"
if fail2ban-client status sshd >/dev/null 2>&1; then
pass "fail2ban sshd jail enabled"
else
fail "fail2ban sshd jail not found"
fi
else
fail "fail2ban not active"
fi
# ── 8. Unattended security upgrades ────────────────────────────────────────
if systemctl is-active --quiet unattended-upgrades 2>/dev/null; then
pass "unattended-upgrades active"
else
fail "unattended-upgrades not active"
fi
# ── 9. Recent brute-force attempts (informational) ─────────────────────────
echo
echo "Recent SSH brute-force attempts (last 10 unique 'Invalid user'):"
grep -h "Invalid user" /var/log/auth.log* 2>/dev/null \
| awk '{print $10}' | sort | uniq -c | sort -rn | head -10 || true
echo
if [ "${FAILED}" -eq 0 ]; then
echo -e "${GREEN}[OK] All hardening checks passed.${NC}"
else
echo -e "${RED}[WARN] ${FAILED} check(s) failed - re-run deploy/hardening.sh or fix manually.${NC}"
fi
exit "${FAILED}"