Перейти к содержанию

Харденинг SSH и аутентификация по ключам

Каждый сервер Linux, смотрящий в интернет, сканируется на предмет SSH-логинов в течение минут после подключения. Эта статья — о переходе от парольной аутентификации к аутентификации по ключам и об изменениях в sshd_config, которые реально значимо снижают поверхность атаки.

Как это устроено

Генерация и развёртывание пары ключей

ssh-keygen -t ed25519 -C "your-email@example.com"

-t ed25519 выбирает алгоритм Ed25519 — ключи меньше и проверка быстрее, чем у RSA, с эквивалентной или лучшей безопасностью в реальных условиях; предпочитайте его, если не нужна поддержка действительно древнего клиента/сервера, который появился раньше него (RSA с ключом 4096 бит, -t rsa -b 4096 — запасной вариант). Это создаёт приватный ключ (~/.ssh/id_ed25519, никогда никому не передавайте) и публичный ключ (~/.ssh/id_ed25519.pub, безопасно передавать — именно он размещается на серверах).

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

Это дописывает ваш публичный ключ в ~/.ssh/authorized_keys на удалённом сервере (создавая файл и директорию с правильными правами при необходимости). Эквивалент вручную:

cat ~/.ssh/id_ed25519.pub | ssh user@server 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'

Права доступа важны: sshd молча откажется использовать файл authorized_keys (или директорию .ssh), доступный для записи группе или всем, в качестве меры безопасности против вмешательства других локальных пользователей. 700 для ~/.ssh, 600 для authorized_keys и самого приватного ключа.

Харденинг sshd_config

Ключевые настройки в /etc/ssh/sshd_config (подтвердите, что ваша версия OpenSSH их поддерживает — они стабильны уже много лет, ssh -V покажет вашу версию):

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers deploy admin
  • PasswordAuthentication no — только после подтверждения, что вход по ключу реально работает, в отдельной сессии, прежде чем закрывать текущую. Это самый важный шаг харденинга: он делает перебор паролей против SSH полностью бессмысленным, поскольку угадывать больше нечего.
  • PermitRootLogin no — заставляет даже легитимных админов входить под именованным пользователем и использовать sudo, что также означает, что каждое привилегированное действие атрибутируется конкретной учётной записи в логах.
  • MaxAuthTries 3 — отключает после стольки неудачных попыток в рамках одного соединения (не долговременный бан — для этого смотрите fail2ban ниже). Осторожно: каждый ключ, который предлагает ваш SSH-агент, считается отдельной попыткой, поэтому при нескольких загруженных ключах низкое значение может разорвать соединение раньше, чем будет испробован нужный ключ — укажите ключ явно: ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 user@server.
  • AllowUsers — явный allowlist того, каким локальным учётным записям вообще разрешено подключаться по SSH, независимо от наличия у них валидных учётных данных. Опечатка или пропущенное имя здесь полностью закрывает этой учётной записи вход по SSH — в том числе вашей.

После любого изменения sshd_config:

sudo sshd -t              # проверка синтаксиса ПЕРЕД перезапуском — безопасно ловит опечатки
sudo systemctl restart sshd   # Debian/Ubuntu: юнит называется ssh.service (алиас sshd обычно тоже работает)

sshd -t проверяет конфиг, не затрагивая работающий демон — всегда запускайте это перед перезапуском, поскольку синтаксическая ошибка вместе с перезапуском может оставить вас вообще без работающего SSH-демона и без способа вернуться удалённо.

Проверяйте также действующую конфигурацию, а не только файл, который вы правили:

sudo sshd -T | grep -iE 'passwordauthentication|permitrootlogin|maxauthtries'

OpenSSH берёт для каждого параметра первое найденное значение, а дистрибутивы подключают файлы из /etc/ssh/sshd_config.d/*.conf в начале sshd_config. Поэтому 50-cloud-init.conf со строкой PasswordAuthentication yes в образе облачного провайдера молча перекрывает ваш PasswordAuthentication no ниже по основному файлу.

Ограничение повторных неудач через fail2ban

sudo apt install fail2ban          # Debian/Ubuntu
sudo dnf install fail2ban          # RHEL-семейство (из EPEL)
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 4
findtime = 10m
bantime = 1h

fail2ban следит за логом аутентификации, и после maxretry неудачных попыток с одного источника в пределах findtime вставляет правило файрвола, банящее этот источник на bantime. Это другой, дополняющий слой по отношению к MaxAuthTries в sshd_config — последний ограничивает попытки на соединение, fail2ban ограничивает попытки (и отдельные соединения) с одного IP-источника за время.

Различия Ubuntu/Debian и RHEL-подобных систем

Ubuntu/Debian RHEL-подобные
Имя сервиса ssh (юнит ssh.service) sshd (юнит sshd.service)
SELinux Не в режиме enforcing по умолчанию Enforcing — ключ/файл в нестандартном месте может потребовать restorecon, чтобы получить правильный SELinux-контекст, прежде чем sshd его использует

Практическое задание

  1. Сгенерируйте пару ключей Ed25519 и разверните публичный ключ на тестовой VM.
  2. Убедитесь, что вход по ключу работает, в новом терминальном сеансе, не закрывая текущий.
  3. Только после подтверждения шага 2: установите PasswordAuthentication no, выполните sshd -t, затем перезапустите, затем откройте ещё одну новую сессию, чтобы убедиться, что парольный вход теперь отклоняется.

Как проверить, что всё сделано правильно

  • ssh -v user@server (подробный вывод) должен показать Authentication succeeded (publickey) и никогда не запрашивать пароль.
  • Попытка ssh -o PreferredAuthentications=password user@server после харденинга должна быть отклонена сразу, даже не запросив пароль.
  • sudo sshd -T | grep -i passwordauthentication должен вывести passwordauthentication no. Если выводится yes, хотя в файле стоит no, значение перекрывает drop-in из /etc/ssh/sshd_config.d/.

Типичные ошибки

  • Отключение парольной аутентификации до подтверждения, что ключ работает. Если ваша единственная активная сессия закроется, а ключ на самом деле не работает — вы заблокированы; всегда сначала тестируйте во второй, независимой сессии.
  • Копирование приватного ключа вместо публичного на сервер (файл без .pub). Это не даёт доступа и обычно ещё и небезопасно оставляет ваш приватный ключ на удалённом хосте.
  • Забыть sshd -t перед перезапуском после правки — опечатка в sshd_config может помешать демону вообще запуститься, и вы узнаете об этом только после того, как он уже не работает.

⚠ Опасные команды

  • Перезапуск sshd/ssh.service сразу после непроверенного изменения конфига, в вашей единственной активной удалённой сессии, без консоли/доступа вне полосы в качестве запасного варианта. Всегда держите существующую сессию открытой и проверяйте новый конфиг в свежей.
  • chmod -R (рекурсивно) на ~/.ssh может изменить права приватного ключа на то, что sshd отклонит — вместо этого задавайте права на директорию и конкретные файлы явно.

Связанные статьи

Контрольные вопросы

  1. Почему нужно протестировать вход по ключу во второй сессии, прежде чем отключать парольную аутентификацию?
  2. В чём разница между тем, что ограничивает MaxAuthTries в sshd_config, и тем, что ограничивает fail2ban?
  3. Почему sshd отказывается использовать файл authorized_keys, доступный на запись группе?
  4. Что именно проверяет sshd -t, и почему запускать его перед каждым перезапуском?