SSH — главная дверь в любой Linux-сервер, и это же делает его главной мишенью для перебора паролей. Стоит открыть порт 22 наружу с обычной парольной аутентификацией, и через несколько часов в логах уже будут тысячи попыток подключения ботами, перебирающими стандартные логины вроде root и admin. В этой статье разберём, как закрыть SSH по-настоящему: перейти на вход по ключам, полностью отключить пароли, и дополнительно спрятать порт от автоматического сканирования через port knocking.

Возьмём за пример сервер srv-fs01 (192.168.10.20, домен itpages.lab.local), к которому администраторы подключаются с рабочих станций в сети 192.168.10.0/24. Задача — оставить доступ только владельцам приватных ключей, убрать стандартный порт 22 из зоны видимости для случайного сканирования, и не потерять доступ к серверу в процессе настройки.

Прежде чем менять что-либо в конфигурации SSH, важно железное правило: никогда не закрывай текущую сессию, пока не проверил новую конфигурацию в отдельном окне. Ошибка в sshd_config, из-за которой демон откажется перезапускаться или начнёт отклонять все подключения, при отсутствии второй открытой сессии означает потерю доступа к серверу и необходимость идти к консоли по IPMI или физически.

Генерация пары ключей на клиентской машине

Ключи создаются не на сервере, а на компьютере, с которого будешь подключаться. Современный рекомендуемый алгоритм — ed25519, он компактнее и быстрее RSA при эквивалентной криптографической стойкости:

ssh-keygen -t ed25519 -C "admin@itpages.lab.local"

На запрос пути можно согласиться с вариантом по умолчанию (~/.ssh/id_ed25519), а вот пропускать парольную фразу для самого ключа не стоит — passphrase защищает приватный ключ, если ноутбук администратора будет украден или скомпрометирован. Без фразы украденный файл ключа сразу даёт полный доступ к серверу, с фразой — злоумышленнику ещё нужно её подобрать или обманом получить у владельца.

Копирование публичного ключа на сервер

Самый простой способ — встроенная утилита ssh-copy-id, которая сама добавит ключ в нужный файл с правильными правами:

ssh-copy-id -i ~/.ssh/id_ed25519.pub admin@192.168.10.20

Если утилита недоступна (например, на клиенте под Windows без OpenSSH), сделай то же самое вручную — допиши содержимое публичного ключа в файл авторизованных ключей на сервере:

cat ~/.ssh/id_ed25519.pub | ssh admin@192.168.10.20 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

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

Проверка входа по ключу

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

ssh -i ~/.ssh/id_ed25519 admin@192.168.10.20

Если подключение прошло без запроса пароля (только запрос passphrase самого ключа, если она задана), можно двигаться дальше. Если запрос пароля всё же появился, проверь права на ~/.ssh (700) и authorized_keys (600), а также владельца этих файлов — они должны принадлежать именно тому пользователю, под которым заходишь, а не root.

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

Открой основной конфиг демона SSH:

sudo nano /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
MaxAuthTries 3

PermitRootLogin no запрещает прямой вход под root по SSH вообще — администратор заходит под обычной учётной записью и при необходимости повышает права через sudo, что оставляет след в логах о том, кто именно и когда выполнил привилегированную команду, в отличие от анонимного входа напрямую под root. MaxAuthTries ограничивает число попыток аутентификации за одно соединение, дополнительно затрудняя автоматизированный перебор.

Проверь синтаксис файла перед перезапуском — sshd умеет самостоятельно валидировать конфигурацию без реального применения:

sudo sshd -t
sudo systemctl restart sshd

Пока не закрывай текущую сессию — открой новое подключение в отдельном окне терминала и убедись, что вход по ключу по-прежнему работает, а попытка входа по паролю (например, временно указав неправильный ключ) корректно отклоняется.

Смена стандартного порта

Смена порта 22 не заменяет остальные меры защиты, но резко снижает объём мусорного трафика от автоматических сканеров, которые перебирают стандартный порт по умолчанию:

sudo nano /etc/ssh/sshd_config
Port 2222
sudo systemctl restart sshd

Не забудь открыть новый порт в брандмауэре и, если используется, закрыть старый:

sudo ufw allow from 192.168.10.0/24 to any port 2222 proto tcp
sudo ufw delete allow 22/tcp

После смены порта все последующие подключения требуют явного указания нового порта: ssh -p 2222 admin@192.168.10.20. Полезно сразу же прописать это в конфигурацию клиента ~/.ssh/config, чтобы не вспоминать номер порта каждый раз.

Настройка клиентского конфига для удобства

nano ~/.ssh/config
Host srv-fs01
    HostName 192.168.10.20
    User admin
    Port 2222
    IdentityFile ~/.ssh/id_ed25519

После этого достаточно набрать ssh srv-fs01, чтобы подключиться со всеми нужными параметрами сразу — особенно удобно, когда серверов много и у каждого свой порт, пользователь и ключ.

Ограничение доступа по IP через брандмауэр

Даже с ключами и нестандартным портом стоит ограничить, кто вообще может достучаться до порта SSH сетевым способом:

sudo ufw default deny incoming
sudo ufw allow from 192.168.10.0/24 to any port 2222 proto tcp

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

Установка Fail2ban против перебора

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

sudo apt install -y fail2ban
sudo nano /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 3600
findtime = 600
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

bantime = 3600 банит нарушителя на час, findtime = 600 — окно в 10 минут, за которое считаются попытки. Три неудачные попытки за десять минут — и адрес блокируется, что практически исключает автоматизированный перебор, оставляя при этом законному администратору право на пару опечаток при вводе passphrase.

Port knocking: скрываем порт до нужной последовательности

Port knocking — техника, при которой порт SSH держится закрытым брандмауэром постоянно и открывается только после того, как клиент «постучится» в заранее заданную последовательность других портов в правильном порядке. Для сканера порт просто не существует, пока не выполнена нужная последовательность. Установим knockd:

sudo apt install -y knockd
sudo nano /etc/knockd.conf
[options]
    UseSyslog

[openSSH]
    sequence    = 7000,8000,9000
    seq_timeout = 5
    command     = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = 9000,8000,7000
    seq_timeout = 5
    command     = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
    tcpflags    = syn

Первая секция открывает доступ к порту 2222 для адреса клиента после стука по портам 7000, 8000, 9000 подряд в течение 5 секунд, вторая — закрывает его обратной последовательностью. По умолчанию порт SSH при этом должен быть закрыт основным правилом брандмауэра, а не разрешён напрямую:

sudo nano /etc/default/knockd
START_KNOCKD=1
KNOCKD_OPTS="-i eth0"
sudo systemctl enable knockd
sudo systemctl start knockd

С клиентской стороны для стука есть утилита knock:

knock 192.168.10.20 7000 8000 9000
ssh srv-fs01

Стоит трезво понимать: port knocking — это security through obscurity, дополнительный барьер, а не замена аутентификации по ключу. Последовательность передаётся открытым текстом и теоретически может быть перехвачена в незашифрованном виде на пути, поэтому её ценность — в отсечении массового автоматического сканирования, а не в защите от целенаправленной атаки на конкретный сервер.

Дополнительные полезные ограничения sshd_config

AllowUsers admin backup-agent
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no

AllowUsers явно ограничивает список системных пользователей, которым вообще разрешён вход по SSH, даже если у них технически есть ключ в authorized_keys — полезный дополнительный барьер против случайно оставленного доступа у уволенного сотрудника или устаревшей учётной записи сервиса. ClientAliveInterval и ClientAliveCountMax закрывают зависшие или разорванные без явного отключения сессии, освобождая ресурсы сервера.

Двухфакторная аутентификация как дополнительный слой

Для серверов с повышенными требованиями к безопасности ключ можно дополнить одноразовым кодом из приложения-аутентификатора — тогда для входа понадобится и ключ, и код с телефона администратора. Модуль google-authenticator подключается через PAM:

sudo apt install -y libpam-google-authenticator

Под учётной записью администратора запусти настройку и отсканируй появившийся QR-код приложением-аутентификатором на телефоне:

google-authenticator

Отвечай Y на вопрос об одноразовом использовании кодов (защита от повторного использования перехваченного кода) и на вопрос об ограничении частоты попыток. Дальше подключаем модуль в PAM и в конфигурацию sshd:

sudo nano /etc/pam.d/sshd
auth required pam_google_authenticator.so
sudo nano /etc/ssh/sshd_config
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

AuthenticationMethods publickey,keyboard-interactive требует пройти оба фактора по очереди: сначала подтвердить владение приватным ключом, и только потом ввести шестизначный код из приложения. Обрати внимание, что здесь KbdInteractiveAuthentication включается снова — это не откат к паролям, а именно канал для одноразового кода, пароль по-прежнему запрещён параметром PasswordAuthentication no. Как и в случае с отключением пароля, обязательно проверяй вход в отдельной сессии, прежде чем закрывать текущую — ошибка в цепочке AuthenticationMethods точно так же способна оставить сервер недоступным для входа.

Резервный ключ на отдельном носителе

Единственный ключ на рабочем ноутбуке администратора — это единая точка отказа: сломался диск или потерялся ноутбук, и доступ к серверам пропал вместе с ним. Разумная практика — держать резервную пару ключей на отдельном защищённом носителе (аппаратный токен вроде YubiKey или зашифрованная флешка в сейфе) и заранее прописать публичный ключ этой резервной пары в authorized_keys наравне с основным:

cat backup_key.pub | ssh -p 2222 srv-fs01 "cat >> ~/.ssh/authorized_keys"

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

Частые ошибки и как их избежать

  • Отключили пароль, не проверив вход по ключу в отдельной сессии. Если после PasswordAuthentication no и рестарта sshd окажется, что ключ по какой-то причине не подходит, единственная открытая сессия при её случайном закрытии обрывает доступ к серверу полностью. Всегда держи вторую сессию открытой до полной проверки.
  • Слишком открытые права на ~/.ssh или authorized_keys. SSH молча игнорирует ключ вместо явной ошибки, если права на директорию или файл шире рекомендованных — это одна из самых частых причин необъяснимого запроса пароля вместо входа по ключу. Держи 700 на директории и 600 на файле ключей.
  • Port knocking настроен без базового ограничения брандмауэра или без Fail2ban. Сам по себе knocking не заменяет остальные меры защиты — он лишь прячет порт от массового сканирования. Используй его как дополнительный слой поверх ключей, отключённых паролей и разумных правил брандмауэра, а не вместо них.

Что дальше

Эта настройка почти всегда идёт в связке с соседними задачами администрирования Linux: