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

Из чего складывается защита удалённого доступа

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

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

Третий слой это ограничение по адресу источника. Если доступ нужен с двух известных сетей, всё остальное можно закрыть на уровне фильтра, и до службы такие попытки не дойдут вовсе.

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

Порядок внедрения имеет значение. Сначала настраивают вход по ключам и проверяют его, затем отключают пароли, и только после этого применяют остальные ограничения. Обратный порядок рискует оставить администратора без доступа к собственной машине.

Создание ключей и публикация открытой части

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

ssh-keygen -t ed25519 -a 100 -C "admin@workstation" -f ~/.ssh/id_ed25519
ssh-keygen -lf ~/.ssh/id_ed25519.pub

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

Открытая часть переносится на сервер утилитой, которая дописывает её в нужный файл с корректными правами.

ssh-copy-id -i ~/.ssh/id_ed25519.pub Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript..5
ssh -i ~/.ssh/id_ed25519 Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript..5 'echo ok'

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

mkdir -p ~/.ssh && chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys

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

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

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l

На клиентской стороне стоит ограничить, какие ключи предлагаются какому серверу, иначе при большом их числе попытки перебирают список и сервер обрывает соединение до того, как нужный ключ будет предложен.

Host srv
    HostName 192.168.10.5
    User admin
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Изменение конфигурации службы и отказ от паролей

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

# /etc/ssh/sshd_config.d/10-hardening.conf
Port 22022
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
AllowGroups ssh-users
MaxAuthTries 3
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no

Параметр PermitRootLogin со значением no запрещает вход от имени администратора, при значении prohibit-password разрешает его только по ключу. Параметр AuthenticationMethods задаёт обязательный способ, и его указание защищает от случайного возврата к паролям при правке соседних строк.

Директива AllowGroups ограничивает вход членами указанной группы, что надёжнее перечисления пользователей: при добавлении сотрудника достаточно включить его в группу.

sudo groupadd ssh-users
sudo usermod -aG ssh-users admin
id admin

Параметры ClientAliveInterval и ClientAliveCountMax закрывают забытые сессии: при отсутствии ответа от клиента за указанное число интервалов соединение разрывается, и заброшенные терминалы не занимают слоты.

Параметр MaxAuthTries ограничивает число попыток в пределах одного соединения, а LoginGraceTime время, отведённое на аутентификацию. Вместе они снижают эффективность перебора даже до включения блокировок.

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

sudo sshd -t
sudo systemctl reload ssh
sudo journalctl -u ssh -n 30 --no-pager

Правило простое: до завершения проверки новой схемы входа держат открытой вторую сессию. Если что-то пошло не так, через неё возвращают прежние настройки.

Автоматическая блокировка адресов через fail2ban

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

sudo apt install fail2ban
# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 4
backend  = systemd
ignoreip = 127.0.0.1/8 ::1 192.168.10.0/24

[sshd]
enabled  = true
port     = 22022
mode     = aggressive

Параметр maxretry задаёт число неудач в пределах интервала findtime, после которого адрес блокируется на срок bantime. Список ignoreip исключает собственные адреса и диапазоны служебных машин, и его стоит заполнить до включения службы, иначе блокировка может отрезать доступ администратору.

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

sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd

Вывод состояния показывает число заблокированных адресов и их список. Разблокировка выполняется одной командой, и её стоит проверять заранее, а не в момент, когда доступ уже потерян.

sudo fail2ban-client set sshd unbanip 203.0.113.7
sudo fail2ban-client set sshd banip 203.0.113.7

Срок блокировки можно увеличивать для адресов, которые возвращаются после разблокировки. Для этого служит механизм нарастающего наказания, при котором каждое повторное срабатывание удлиняет срок.

Отдельно проверяют, что служба использует правильный механизм фильтрации. На машинах с набором правил nftables блокировка выполняется через соответствующую цепочку, и её видно в списке правил.

sudo nft list ruleset | grep -A5 'f2b'

Смена порта и ограничение по адресу источника

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

sudo ss -tlnp | grep ssh
sudo nft list ruleset | grep 22022

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

Если набор адресов, с которых нужен вход, известен, доступ ограничивают на уровне фильтра, и служба такие попытки даже не видит.

sudo nft add table inet ssh-guard
sudo nft add chain inet ssh-guard input '{ type filter hook input priority filter; policy accept; }'
sudo nft add rule inet ssh-guard input tcp dport 22022 ip saddr { 203.0.113.0/24, 198.51.100.7 } accept
sudo nft add rule inet ssh-guard input tcp dport 22022 drop

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

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

Дополнительные механизмы и двухфакторная проверка

Одноразовые коды добавляют второй фактор к ключу. Настройка выполняется подключаемым модулем аутентификации, после чего сервер запрашивает код из приложения на телефоне.

sudo apt install libpam-google-authenticator
google-authenticator -t -d -f -r 3 -R 30 -W

В конфигурации службы включают комбинированный способ, при котором требуются и ключ, и код.

# /etc/ssh/sshd_config.d/20-2fa.conf
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes
sudo sed -i 's/^@include common-auth$/auth required pam_google_authenticator.so/' /etc/pam.d/sshd
sudo sshd -t && sudo systemctl reload ssh

Двухфакторная проверка оправдана для серверов с доступом из интернета и для учётных записей с полными правами. Для машин внутри сети она чаще создаёт неудобство, чем добавляет защиты, поскольку первый фактор и так достаточно надёжен.

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

echo 'admin ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload ssh' | sudo tee /etc/sudoers.d/ssh-reload
sudo chmod 440 /etc/sudoers.d/ssh-reload
sudo visudo -c

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

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

Match User deploy
    AllowTcpForwarding yes
    X11Forwarding no
    PermitTTY yes

Проверка схемы и ведение журнала

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

ssh -v Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript..5 exit
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript..5
grep -i 'Accepted\|Failed' /var/log/auth.log | tail -n 20

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

Журнал попыток стоит просматривать регулярно либо передавать в систему сбора. По числу неудачных попыток и разнообразию имён пользователей видно, идёт ли целенаправленный подбор или обычный фоновый шум.

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

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