Парольный вход по SSH — самая большая открытая поверхность обычного сервера. Против него бессильны и Fail2ban, и любые пороги: тысяча адресов по одной попытке в час не наберёт лимита никогда, а перебирать они будут ровно до тех пор, пока подбор в принципе возможен. Ключи убирают саму возможность, и это единственная настройка из всего списка «хардынга», которая меняет положение дел качественно.

Пугает здесь одно: отключить пароль и остаться снаружи. Ниже порядок, при котором это исключено.

Ключ

Генерируется на своей машине, не на сервере:

ssh-keygen -t ed25519 -C "рабочий ноутбук"

ed25519 вместо RSA — короче, быстрее и без вопросов о длине. RSA нужен, только если предстоит ходить на что-то очень старое; тогда -t rsa -b 4096.

Пароль на ключ (passphrase) ставить стоит: файл ключа могут украсть с ноутбука, и без пароля он сразу же работает. Вводить его каждый раз не придётся — этим занимается ssh-agent, а в macOS и большинстве десктопных Linux он уже запущен.

Копирование на сервер — одной командой, пока пароль ещё работает:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@203.0.113.25

Если ssh-copy-id недоступен, содержимое .pub-файла дописывается строкой в ~/.ssh/authorized_keys на сервере. Права важны: каталог .ssh — 700, файл — 600, владелец — сам пользователь. При других правах sshd молча откажется читать файл, и это самая частая причина «ключ не работает».

Проверка, которая всё решает

Прежде чем что-либо отключать, откройте второе соединение, не закрывая первое:

ssh -o PasswordAuthentication=no user@203.0.113.25

Опция запрещает клиенту откатываться на пароль — то есть если вход состоялся, он состоялся именно по ключу. Пока эта команда не отработает, к следующему шагу переходить нельзя. И первое соединение до самого конца не закрываем: через него чинится всё, что можно сломать.

Отключение пароля и один неочевидный подвох

Настройки кладём отдельным файлом, чтобы обновление пакета их не затёрло. Но имя файла имеет значение:

sudo tee /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF'
PasswordAuthentication no
PermitRootLogin no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LogLevel VERBOSE
EOF

Дело в том, что OpenSSH использует первое встреченное значение параметра, а не последнее, как почти везде. Файлы из sshd_config.d читаются по алфавиту, и облачные образы Ubuntu кладут туда 50-cloud-init.conf, в котором нередко стоит PasswordAuthentication yes. Ваш файл с номером 90 в такой ситуации не сделает ничего: настройка вроде бы прописана, а пароль продолжает работать. Отсюда номер 10 — он читается раньше.

Проверить, что именно получилось в итоге, можно не гадая:

sudo sshd -T | grep -Ei 'passwordauth|permitrootlogin|pubkeyauth'

Эта команда печатает действующую конфигурацию после всех включений. Ей и верьте, а не содержимому файлов.

Дальше — проверка синтаксиса и мягкая перезагрузка службы:

sudo sshd -t && sudo systemctl reload ssh

sshd -t обязателен: опечатка в конфиге при restart оставит службу лежать, а вас — снаружи. reload к тому же не рвёт открытые сессии.

Ubuntu 24.04: порт меняется не там

Отдельная ловушка свежих Ubuntu: sshd там запускается через сокет systemd. Строка Port в sshd_config в этом режиме не делает ничего — слушает сокет, а не демон. Если вы меняете порт, править надо его:

sudo systemctl edit ssh.socket

и указывать ListenStream= (пустое значение сбрасывает прежнее) с новым портом. Симптом, по которому это узнаётся: конфиг изменён, служба перезапущена, а сервер по-прежнему отвечает на 22.

Кстати, о смене порта: как защита она не работает — сканеры находят службу на любом порту за минуты. Единственный её эффект — в логах становится тише, потому что массовый перебор идёт только по 22. Это удобно, но с безопасностью не путайте.

Кто вообще может входить

Полезное дополнение — явный список:

AllowUsers deploy admin

Всё, что не перечислено, отсекается ещё до проверки ключа. Это заодно закрывает случай, когда какой-нибудь пакет заводит системного пользователя с оболочкой и домашним каталогом.

Запасной вход

Один ключ на одном ноутбуке — единственная точка отказа. Диск умирает, ноутбук теряется, и сервер становится недоступен навсегда. Разумный минимум:

  • второй ключ с другого устройства в authorized_keys;
  • копия приватного ключа в менеджере паролей или на зашифрованной флешке;
  • проверенный доступ к консоли у хостера — VNC или serial. Проверенный означает, что вы туда хотя бы раз входили, а не «где-то в панели есть кнопка».

Заодно посмотрите, что уже лежит в authorized_keys — и у своего пользователя, и у root. Чужой ключ там переживает любую смену пароля и остаётся рабочим доступом.

После

Перебор паролей никуда не денется, просто он теперь бесполезен: в логах останутся тысячи Failed password, ни одна из которых не может закончиться успехом. А вот на что смотреть теперь стоит — это на успешные входы: с какого адреса, под каким пользователем, в какое время. Успешный вход по ключу с незнакомого адреса — событие куда более важное, чем миллион неудачных попыток, и заметить его в общем потоке гораздо труднее. Именно эту картину показывает страница демо ниже.