AxionserveSign in / RegisterEnglish/中文/cn繁体/tw

SSH Hardening Checklist: Twelve Actions for the First Hour

Key login, password auth off, root restricted, fail2ban, firewall, updates, alerts, audit logs, baseline snapshot, NTP and a tested recovery channel — command

· AxionServe Editorial · 云安全
# Why the first hour matters Indiscriminate scanning and brute force hit every new address on the internet, every minute. Completing these twelve actions in the first hour after provisioning blocks the vast majority of automated attacks. Security is not a product you buy — it is a set of defaults you apply. Each action ships as **command + why + verification**, all idempotent; a scripted version lives in the automation script of the security baseline hub. ## Group 1 — how you get in (actions 1–4) **① Key-based login.** Generate locally, push the public key: ```bash ssh-keygen -t ed25519 -C "admin@$(hostname)-$(date +%F)" # local; ed25519 is short and strong ssh-copy-id root@ # or append manually to ~/.ssh/authorized_keys ``` Why: passwords can be dictionary-attacked; a 256-bit key cannot. Verify: a fresh terminal logs in with the key — only then is this step done. **② Disable password authentication** (only after ① is proven): ```bash echo -e "PasswordAuthentication no\nPubkeyAuthentication yes" > /etc/ssh/sshd_config.d/99-hardening.conf systemctl reload sshd # service name may be `ssh` on Debian/Ubuntu ``` Why: this is the endgame switch for brute force — with password auth off, dictionary attacks yield zero. **③ Restrict direct root.** `PermitRootLogin prohibit-password` in the same drop-in: root via key only. Stricter still: a regular user + sudo, which also gives finer audit granularity. **④ Tighten attempt parameters.** `MaxAuthTries 3` and `LoginGraceTime 20`: raise the cost of every probing connection and cut log noise at the same time. ## Group 2 — automatic defence (actions 5–7) **⑤ Install fail2ban:** ```bash apt-get install -y fail2ban # or yum/dnf printf '[sshd]\nenabled = true\nmaxretry = 5\nfindtime = 600\nbantime = 3600\n' > /etc/fail2ban/jail.d/sshd.local systemctl enable --now fail2ban && fail2ban-client status sshd ``` Why: with key login, brute force already yields nothing — but scan noise drowns the logs that matter. fail2ban jails repeat offenders and halves your log volume. **⑥ Firewall: default-deny inbound**, whitelist SSH and your service ports; the full baseline lives in the firewall baseline article. **⑦ Automatic security updates:** `apt-get install -y unattended-upgrades && dpkg-reconfigure -f noninteractive unattended-upgrades`. Security patches only; major version upgrades stay human. "No automatic major upgrades" is part of the discipline. ## Group 3 — visibility (actions 8–10) **⑧ Login alerts.** Fire a mail or webhook on every SSH login (one curl line in /root/.ssh/rc or a pam hook). An alert when you did not log in is your first intrusion signal. **⑨ Audit log sanity:** ```bash journalctl -u sshd --since "1 hour ago" | grep -E "Accepted|Failed" | tail -20 last -10 # do you recognise every IP? ``` Why: after an incident the first question is always "when did they get in". Confirm log retention and completeness on day one — cloud images sometimes ship with truncated journals. **⑩ Baseline snapshot.** Archive open ports (`ss -tlnp`), process tree (`ps auxf`), account list (`awk -F: '$3>=1000{print $1}' /etc/passwd`) and crontabs. Every future "what is this new thing" gets checked against this snapshot. ## Group 4 — depth (actions 11–12) **⑪ Time sync.** `timedatectl set-ntp true`. A machine with scrambled timestamps makes forensics re-align clocks at every step — fix it in hour one. **⑫ Verify the recovery channel.** Test the datacenter's IPMI/VNC/console (dedicated) or snapshot facility (VPS) by actually using it once. When an SSH config typo locks you out — a high-frequency accident — this channel is the only door left. ## The twelve at a glance | # | Action | Where / command | Verification | |---|---|---|---| | 1 | Key login | ssh-keygen + ssh-copy-id | fresh terminal key login | | 2 | No password auth | sshd_config.d drop-in | password login refused | | 3 | Root restricted | PermitRootLogin prohibit-password | config echo | | 4 | Attempt limits | MaxAuthTries / LoginGraceTime | config echo | | 5 | fail2ban | jail.d/sshd.local | `status sshd` shows jail | | 6 | Firewall | default-deny + whitelist | non-whitelisted port closed | | 7 | Auto security patches | unattended-upgrades | service active | | 8 | Login alerts | ssh rc / pam hook | alert on your own login | | 9 | Audit logs | journalctl / last | retention confirmed | | 10 | Baseline snapshot | ss/ps/passwd/crontab dump | snapshot archived | | 11 | NTP | timedatectl set-ntp true | synchronized | | 12 | Recovery channel | IPMI/VNC/snapshot test | logged in via it once | Done in order, the whole set takes under an hour and never fights itself — every step is idempotent and re-runnable.