← All posts Security

Who can SSH into your server right now? You probably don't know.

The Tryssh team · July 19, 2026

Ask yourself a simple question about any server you run: how many SSH keys can open it, and whose are they?

Most people can't answer. Keys accumulate — the contractor from 2024, the CI system you migrated off, the laptop you wiped last year, that one key you added "temporarily" during an incident. Nothing ever removes them. And unlike passwords, SSH keys don't expire: a key added five years ago works exactly as well today.

Meanwhile the internet keeps knocking. Honeypot studies routinely log tens of millions of SSH brute-force attempts in a few months; if your box has port 22 open to the world, it's being probed right now. An access audit is an hour of work. Here's the whole thing.

Step 1: Enumerate every key on the box

The mistake is checking only your own ~/.ssh/authorized_keys. Keys can live under any user with a shell — including service accounts you forgot exist:

sudo find / -name authorized_keys -not -path "/proc/*" 2>/dev/null \
  | while read f; do echo "== $f"; sudo cat "$f"; done

Fingerprint them so you can talk about them precisely:

ssh-keygen -l -f /home/deploy/.ssh/authorized_keys

Now the uncomfortable part: for each key, name the human who holds the private half. The comment field at the end of each line is the only clue you get — Linux stores no "date added" for a key. Any key you can't attribute to a person who still needs access is a finding. In audits of real fleets, the departed-employee key is the single most common one.

Step 2: Read what sshd actually enforces

Not what the config file says — what the running daemon resolved, includes and all:

sudo sshd -T | grep -E "permitrootlogin|passwordauthentication|maxauthtries|x11forwarding"

Three answers matter most:

  • passwordauthentication yes means every one of those brute-force bots gets to play the lottery. This is the highest-value single change on the list.
  • permitrootlogin yes hands attackers the one username that exists on every Linux box, and erases your audit trail — everything root does is just "root."
  • maxauthtries 6 gives six guesses per connection. Three is plenty for a human with the right key.

Step 3: Check the escalation path

A key gets an attacker in the door; sudo decides what they become. One line to hunt for:

sudo grep -rE "NOPASSWD" /etc/sudoers /etc/sudoers.d/ | grep -v "^#"

(ALL) NOPASSWD: ALL on a service account means any compromise of that account — a web app RCE, a leaked deploy key — is instantly root, no password required. If automation genuinely needs passwordless sudo, scope it to exact commands: NOPASSWD: /usr/bin/systemctl restart nginx, not ALL.

Step 4: Look at who's actually been getting in

last -a | head -20          # recent successful logins, with source IPs
sudo lastb --ip | head      # failed attempts — meet your attackers
w                           # who's on right now

lastb is grimly educational the first time: pages of root, admin, oracle, test from IPs you've never heard of. That's the background radiation your config has to survive.

Hardening without locking yourself out

Every SSH hardening story has a version where the author cuts off the branch they're sitting on. The discipline that prevents it:

  1. Keep your current session open the whole time. A live session survives an sshd restart; it's your escape hatch if the new config is broken.
  2. Confirm key login works from a second, new terminal before disabling password auth.
  3. sudo sshd -t after every edit — it catches syntax errors before they take down the daemon.
  4. systemctl reload ssh, test a fresh login, and only then close the old session.

One directive at a time. The lockout stories all start with someone changing five things and restarting once.

Making it a habit instead of a heroic effort

The audit above is genuinely easy — it's eight commands. The reason nobody does it quarterly is that it's eight commands times every host you run, plus the cross-referencing, plus remembering what sshd -T output is supposed to look like.

This is the kind of job Tryssh collapses into a sentence. Ask the copilot "audit ssh access on this box — who can get in and how?" and it runs the enumeration for you: every authorized_keys on the host, the effective sshd config, the sudoers grep, the login history. All of it is read-only, so it runs without ceremony — and the copilot hands you findings, not raw output:

The audit is read-only, so the agent just runs it. The fix waits for your click.

The fixes are where it stops. PasswordAuthentication no, deleting that stale key line, tightening sudoers — each renders as an exact change and waits for your approval, with your session held open. The gate that keeps the agent from breaking things is the same discipline that keeps you from locking yourself out. That's not a coincidence; it's the product.

Tryssh is a native macOS SSH workspace with an agentic copilot. Download it free — the terminal is never metered.