Lesson 4 · Security

Identity & Least Privilege

A firewall decides who can knock. Identity decides who gets in. Today the door stops accepting guessed passwords.

Where we are: Lesson 3 put a default-deny edge around the host — but 22/tcp is deliberately still open, because you need to get in. The audit flagged how that door works: Finding CPermitRootLogin yes and password auth enabled — and Finding G — no brute-force defence. This lesson closes both, and ticks the mission's "SSH is least-privilege, no root password login — and I can explain why in interview terms."

A password is a secret you both know — which means it can be guessed, reused, phished, or leaked, and a bot can try millions of them against your open port. A key is asymmetric: the private half never leaves your machine, and nothing brute-forceable ever crosses the wire. Switching SSH from "password allowed" to "keys only" doesn't just harden the door — it removes the entire category of attack that automated scanners run against every exposed 22 on the internet.

In the field: "disable SSH password authentication" and "no direct root login" are line items in every hardening standard (CIS, STIG, SOC 2). This is the homelab face of IAM (identity & access management) and least privilege: authenticate with something you have, not something you know; give each identity the minimum it needs; and make access auditable. The enterprise endgame is named users + sudo behind a bastion — we'll name that ideal at the end.

What makes an SSH key fundamentally safer than a password?

The danger here is you, not the attacker

Every other lesson's worst case was a service hiccup. This one's worst case is locking yourself out of your own host — disable password login when your key doesn't actually work, and the next connection is refused. So the discipline is entirely about order: prove the new way in before you remove the old one. Tap each step to see why it's where it is.

The safe order of operations

Tap a step to reveal what it protects against. Skipping one is how people get locked out.

  1. Confirm key-based login already works Run ssh -o PasswordAuthentication=no root@host from another machine. If it logs you in, your key is good. Skip this and you're disabling the only door you've tested.
  2. Write the change to a drop-in file Put it in /etc/ssh/sshd_config.d/10-hardening.conf, not the main config — it's isolated, obvious, and trivial to delete to roll back. (Your host already Includes that directory.)
  3. Validate the config before applying sshd -t parses it without touching the running server. Reloading a syntactically broken sshd can drop you and refuse new logins.
  4. Reload — don't restart systemctl reload ssh applies the new rules to new connections while leaving your current session untouched. Your open shell is your safety line.
  5. Test a NEW session before closing this one Open a second terminal and log in. Only when that succeeds do you close the first. Your still-open session is the rollback path if the new one fails.
Your safety nets here are unusually strong: (1) key login is already proven working for you, and root has several authorized keys (your personal key and the management key both load). (2) Even in a total SSH lockout, the Proxmox web console at https://192.168.5.121:8006 gives you a root shell over a completely separate channel (it survived Lesson 3's firewall, since 8006 is management-allowed) — so you can always undo the change. (3) Rollback is deleting one file and reloading.

Before you set PasswordAuthentication no, what must you confirm?

Root, but only with a key

There are two settings doing two jobs. PasswordAuthentication no turns off passwords for everyone. PermitRootLogin prohibit-password says root may still log in — but only with a key, never a password. On Proxmox that's the pragmatic sweet spot: the platform's own tooling and the web UI expect root@pam, so you keep root reachable by key while removing the password as an attack path entirely. That exactly satisfies "no root password login."

What does PermitRootLogin prohibit-password actually do?

Your tangible win: a host that can't be password-guessed

Part A is the real win — key-only SSH, root by key only. Part B adds brute-force defence. Keep your current session open the whole time.

### SAFETY CHECK — prove key login works BEFORE removing passwords ###
# from your laptop / another machine (NOT from inside the host):
ssh -o PasswordAuthentication=no root@192.168.5.121 'echo key-only login OK'
# it prints the message? your key works — safe to proceed.

ssh root@192.168.5.121          # now log in and KEEP THIS SESSION OPEN

### PART A — key-only SSH, root by key only (Finding C) ###
cat > /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF'
# Identity hardening — keys only, root by key only
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
EOF

sshd -t && echo "config OK"     # validate BEFORE applying — never reload a broken config
systemctl reload ssh             # reload, NOT restart: your current session survives

# PROVE it in a NEW terminal before closing this one:
#   ssh root@192.168.5.121                                  -> still works (your key)
#   ssh -o PreferredAuthentications=password root@...121    -> "Permission denied" (good!)

# ROLLBACK: rm /etc/ssh/sshd_config.d/10-hardening.conf && systemctl reload ssh

### PART B — fail2ban: brute-force defence + log hygiene (Finding G) ###
apt-get update && apt-get install -y fail2ban
cat > /etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled  = true
maxretry = 4
bantime  = 1h
EOF
systemctl enable --now fail2ban
fail2ban-client status sshd      # shows the active jail

When a fresh login still works by key but is refused with a password, you've removed the entire password-guessing attack surface from your most exposed port. That's the win.

Honest about fail2ban's role. Once passwords are off, an SSH brute-force can't succeed anyway — so fail2ban here is defence-in-depth, not the main event: it trims the constant bot-scan noise from your logs, saves a little CPU, and is the same tool you'll point at other services later. Worth having; not what saves you. The thing that saves you is Part A.

The enterprise next level (name it in an interview). prohibit-password keeps root usable by key — fine for a single Proxmox box. The stricter ideal is: PermitRootLogin no, log in as a named user, escalate with sudo (so every action is attributable to a person), and reach the host only through a bastion / jump host. That's accountability + least privilege + a single audited entry point — the model behind every serious production estate. Overkill for one host today; exactly the vocabulary that signals you think like an infra engineer.

I'm your teacher — ask me anything. Want me to run Part A with you and verify from a fresh session that key works + password is refused, before anything is irreversible? Curious how to add a named sudo user so we could later flip to PermitRootLogin no? Want to tune the fail2ban jail (ban times, ignoreip for your LAN/Tailnet)? Or jump to Lesson 5 (Blast Radius)? Just ask.

Primary source to read next: the Mozilla OpenSSH Guidelines — a high-trust, current baseline for key auth, root login, and ciphers. Pair it with man sshd_config for the exact meaning of PermitRootLogin and PasswordAuthentication.