Skip to content
EN
← Все статьи

Вход по SSH-ключу: генерация, настройка и отключение пароля

Коротко. Вход по SSH-ключу заменяет пароль парой файлов: приватный ключ остаётся у вас, публичный кладётся в ~/.ssh/authorized_keys на сервере. Сгенерируйте ключ командой ssh-keygen -t ed25519, установите его через ssh-copy-id, выставите права 700 на каталог и 600 на файл, проверьте вход в новой сессии и только потом отключайте PasswordAuthentication.

Как работает SSH-подключение по ключу

Пароль — это общий секрет: он есть и у вас, и на сервере, и его можно подобрать перебором. SSH-ключ устроен иначе. Вы генерируете пару файлов:

  • id_ed25519 — приватный ключ. Никогда не покидает вашу машину. Это и есть ваш доступ.
  • id_ed25519.pub — публичный SSH-ключ. Его можно спокойно копировать, отправлять в чат, класть на десяток серверов.

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

Практический эффект: боты, которые круглосуточно перебирают root:123456 на порту 22, перестают быть угрозой в принципе. Не «становятся менее вероятными» — они физически не могут подобрать 256-битный ключ.

Приватный ключ — это не «пароль от сервера», это сам доступ. Файл id_ed25519 нельзя пересылать в мессенджере, класть в общий диск, коммитить в репозиторий и оставлять в Docker-образе. Если он утёк — ключ отзывается целиком, а не «меняется пароль».
Схема аутентификации по SSH-ключу: приватный ключ на клиенте подписывает вызов сервера, публичный ключ в authorized_keys проверяет подпись
Приватный ключ не передаётся по сети — сервер только проверяет подпись.

Какой SSH-ключ выбрать: ed25519 или RSA

Короткий ответ: ed25519. Он появился в OpenSSH 6.5 и с тех пор стал разумным значением по умолчанию. Причины:

  • Стойкость. Ed25519 даёт примерно 128 бит безопасности при длине ключа 256 бит. Чтобы получить сопоставимый уровень на RSA, нужен ключ от 3072 бит.
  • Размер. Публичный ed25519-ключ — одна короткая строка, влезающая в терминал. Публичный RSA 4096 — простыня на несколько строк, которую неудобно копировать вручную.
  • Скорость. Подпись и проверка заметно быстрее, чем у RSA 4096. На массовых деплоях и CI это ощутимо.
  • Меньше способов ошибиться. У ed25519 нет параметров, которые можно выбрать неправильно: нет выбора кривой, нет зависимости подписи от качества генератора случайных чисел на клиенте.

RSA имеет смысл держать во втором ключе только ради совместимости — например, если в контуре остались старые железки, сетевое оборудование или Git-хостинг, не понимающий Ed25519.

Тип ключаСтойкостьРазмер публичного ключаПоддержкаВердикт
ed25519~128 бит, современная кривая Curve25519Одна строка, ~80 символовOpenSSH 6.5 и новее, GitHub, GitLab, все актуальные дистрибутивыВыбор по умолчанию
ed25519-skТо же плюс аппаратное подтверждениеОдна строка, чуть длиннееТребует FIDO2-токена и свежего OpenSSH на обеих сторонахЛучший вариант для админских ключей
RSA 4096Достаточная при длине от 3072 бит; 1024 и 2048 бит уже слабыеНесколько строк, сотни символовПрактически везде, включая легасиЗапасной вариант ради совместимости
ECDSA (nistp256/384/521)Формально сопоставима с ed25519КороткийШирокаяРаботает, но выбирать заново незачем
DSA (ssh-dss)Ограничен 1024 битами, считается устаревшимСреднийОтключён по умолчанию начиная с OpenSSH 7.0, из свежих релизов вырезанНе использовать

Отдельная ловушка: алгоритм подписи ssh-rsa (на SHA-1) отключён по умолчанию в свежих версиях OpenSSH. Сам RSA-ключ при этом остаётся валидным — проблема именно в старом алгоритме подписи. Если после обновления клиента или сервера старый RSA-ключ внезапно перестал приниматься, это почти всегда он.

Генерация SSH-ключа: ssh-keygen шаг за шагом

Базовая команда для создания SSH-ключа:

ssh-keygen -t ed25519 -a 100 -C "alice@laptop-prod" -f ~/.ssh/id_ed25519_prod

Разбор флагов:

  • -t ed25519 — тип ключа.
  • -a 100 — число раундов KDF при шифровании приватного ключа парольной фразой. Больше раундов — дороже перебор украденного файла. 100 — разумный компромисс, задержка при вводе фразы остаётся незаметной.
  • -C "alice@laptop-prod" — комментарий. Он попадает в конец публичного ключа и в authorized_keys. Через полгода именно по комментарию вы поймёте, чей это ключ и можно ли его удалить. Пишите туда человека и машину, а не «my key».
  • -f ~/.ssh/id_ed25519_prod — путь. Отдельные имена под разные контуры удобнее, чем один id_ed25519 на всё.

Парольная фраза: ставить или нет

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

Аргумент «неудобно вводить каждый раз» закрывается ssh-agent: фраза вводится один раз за сессию. Ключ без фразы допустим только для машинных сценариев — CI, деплой, бэкапы, — и такой ключ обязан быть отдельным и максимально ограниченным по правам.

Сменить или добавить фразу к существующему ключу можно без перевыпуска:

ssh-keygen -p -a 100 -f ~/.ssh/id_ed25519_prod

Посмотреть отпечаток ключа и убедиться, что вы работаете с тем самым файлом:

ssh-keygen -lf ~/.ssh/id_ed25519_prod.pub
# 256 SHA256:kx3Y... alice@laptop-prod (ED25519)

Как создать SSH-ключ в Windows

В Windows 10 и 11 есть встроенный OpenSSH-клиент, отдельный софт не нужен. В PowerShell работает ровно та же команда ssh-keygen -t ed25519 -C "...", ключи ложатся в C:\Users\Имя\.ssh. Агент запускается как служба Windows:

Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519

PuTTY — отдельная история. Он не понимает формат OpenSSH и использует собственный .ppk. Ключ генерируется в PuTTYgen, агент называется Pageant. Если ключ уже создан в OpenSSH-формате, его можно импортировать в PuTTYgen и сохранить как .ppk; обратная конвертация тоже доступна через экспорт в OpenSSH-формат. На сервер в любом случае кладётся публичная часть в однострочном виде ssh-ed25519 AAAA... комментарий — не содержимое окна PuTTYgen целиком со служебными заголовками.

Как добавить SSH-ключ на сервер

Простой путь — ssh-copy-id. Он сам создаст каталог, допишет ключ и выставит права:

ssh-copy-id -i ~/.ssh/id_ed25519_prod.pub -p 22 deploy@203.0.113.10

Указывайте .pub явно. Без -i утилита возьмёт ключи из агента, и на сервер может уехать не тот ключ, который вы имели в виду.

Если ssh-copy-id недоступен (типично для macOS без Homebrew и для Windows), тот же результат даёт одна команда:

cat ~/.ssh/id_ed25519_prod.pub | ssh deploy@203.0.113.10 \
  "umask 077; mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

umask 077 здесь важен: он гарантирует, что созданные каталог и файл получат корректные права сразу, а не после отдельного chmod. Обратите внимание на >> — одинарный > затрёт уже существующие ключи других сотрудников.

Ручная установка и проверка

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

mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys      # вставить одну строку целиком
chmod 600 ~/.ssh/authorized_keys
chown -R "$USER:$USER" ~/.ssh

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

ssh-keygen -lf ~/.ssh/authorized_keys

Команда выведет по строке на каждый валидный ключ. Если ключей меньше, чем вы добавили, — где-то съехал перенос.

Ключ добавляется тому пользователю, под которым вы будете входить. Файл /root/.ssh/authorized_keys и /home/deploy/.ssh/authorized_keys — разные вещи. Классическая ошибка: положить ключ под sudo в домашний каталог root, а потом удивляться, почему ssh deploy@host просит пароль.

Права доступа chmod: главная причина Permission denied (publickey)

SSH по умолчанию работает в режиме StrictModes yes: если права на каталог или файлы слишком широкие, сервер молча игнорирует ключ и делает вид, что его нет. В клиентском логе вы увидите только Permission denied (publickey), без объяснений. Это причина примерно половины всех «ключ не работает».

ПутьПраваВладелецЧто ломается при ошибке
/home/user750 или 700 (не групп-/мир-записываемый)userСервер отвергает весь каталог .ssh
~/.ssh700userКлючи не читаются, вход по паролю или отказ
~/.ssh/authorized_keys600userКлюч игнорируется
~/.ssh/id_ed25519 (клиент)600userUNPROTECTED PRIVATE KEY FILE, клиент отказывается использовать ключ
~/.ssh/config (клиент)600userBad owner or permissions

Разовая починка на сервере:

chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R "$(id -un):$(id -gn)" ~/.ssh
restorecon -Rv ~/.ssh 2>/dev/null || true

Последняя строка нужна на системах с SELinux (RHEL, Rocky, AlmaLinux, Fedora): если каталог .ssh создан через копирование из /tmp или распакован из архива, у него будет неверный контекст безопасности, и sshd не сможет прочитать файл при формально правильных правах. На Debian и Ubuntu команда просто отсутствует и безопасно пропускается.

Файл ~/.ssh/config и ssh-agent

Как только серверов становится больше трёх, длинные команды с -i, -p и полным именем пользователя перестают быть выносимыми. Решение — клиентский конфиг с Host-алиасами.

# ~/.ssh/config

Host prod-web
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_prod
    IdentitiesOnly yes

Host db-internal
    HostName 10.0.5.20
    User admin
    IdentityFile ~/.ssh/id_ed25519_prod
    ProxyJump prod-web

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 3
    HashKnownHosts yes

После этого ssh prod-web делает всё то же самое, что длинная команда. А ssh db-internal автоматически ходит через бастион, без ручного проброса.

Ключевой параметр здесь — IdentitiesOnly yes. Без него клиент предлагает серверу все ключи из агента подряд. При шести ключах в агенте и лимите MaxAuthTries 6 на сервере попытки закончатся до того, как дело дойдёт до нужного ключа, и вы получите Too many authentication failures.

ssh-agent: ввести парольную фразу один раз

# Linux: запустить агент, если он не поднят сессией
eval "$(ssh-agent -s)"

ssh-add ~/.ssh/id_ed25519_prod     # спросит фразу один раз
ssh-add -l                          # какие ключи сейчас в агенте
ssh-add -D                          # выгрузить все ключи

Полезная привычка — ограничивать время жизни ключа в агенте: ssh-add -t 4h ~/.ssh/id_ed25519_prod. По истечении срока ключ выгружается сам, и забытая незалоченная сессия перестаёт быть бессрочным доступом.

На macOS агент интегрирован с Keychain: ssh-add --apple-use-keychain ~/.ssh/id_ed25519_prod сохранит фразу в связке ключей, а строка UseKeychain yes в ~/.ssh/config заставит клиент забирать её оттуда автоматически.

Не включайте ForwardAgent yes в блоке Host *. Проброс агента даёт root'у на промежуточном сервере возможность использовать ваши ключи, пока сессия открыта. Если проброс действительно нужен — включайте его точечно для конкретного бастиона, а лучше замените на ProxyJump, который такой проблемы не создаёт.
Схема клиентского файла ssh config с Host-алиасами, IdentityFile и переходом на внутренний сервер через ProxyJump
Host-алиасы и ProxyJump убирают длинные команды и ручные туннели.

Отключение входа по паролю, root-логина и настройка порта SSH

Ключи сами по себе ничего не закрывают: пока PasswordAuthentication yes, боты продолжают перебирать пароли. Смысл появляется после отключения парольного входа.

Правим /etc/ssh/sshd_config:

PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
PermitEmptyPasswords no

MaxAuthTries 3
LoginGraceTime 20
AllowUsers deploy admin

Что здесь важно:

  • KbdInteractiveAuthentication no обязателен вместе с PasswordAuthentication no. Иначе на системах с PAM пароль остаётся доступным через клавиатурно-интерактивный метод, и вы получите ложное ощущение закрытого доступа.
  • PermitRootLogin prohibit-password оставляет root доступным по ключу (это нужно для части автоматизации), но запрещает пароль. Если root вообще не нужен — ставьте no.
  • AllowUsers — белый список. Даже при утечке ключа сервисного пользователя вход под чужим именем не пройдёт.

Ловушка с Include и sshd_config.d

В современных дистрибутивах в начале sshd_config стоит строка Include /etc/ssh/sshd_config.d/*.conf. Для sshd действует правило «первое совпадение выигрывает»: значение, заданное во включённом файле, перебивает всё, что вы напишете ниже в основном конфиге. Облачные образы часто кладут туда файл, включающий парольный вход обратно.

Поэтому проверяйте не файл, а эффективную конфигурацию:

sudo sshd -T | grep -Ei 'passwordauth|permitroot|pubkeyauth|kbdinteractive|^port'
sudo grep -r -n 'PasswordAuthentication' /etc/ssh/

sshd -T выводит итоговые значения с учётом всех включений. Если там passwordauthentication yes, а в вашем файле no — ищите перебивающий файл в sshd_config.d.

Проверка sshd -t и правило второй сессии

Опечатка в sshd_config означает, что демон не поднимется после перезапуска. Если это единственный способ попасть на машину, вы её потеряли до похода в веб-консоль хостера.

# 1. Синтаксическая проверка ДО перезапуска
sudo sshd -t

# 2. Только если проверка молчит — применяем
sudo systemctl reload ssh || sudo systemctl reload sshd

# 3. В ДРУГОМ окне терминала — проверяем вход
ssh -o PreferredAuthentications=publickey deploy@203.0.113.10
Держите текущую SSH-сессию открытой, пока новая не подключилась успешно. reload не рвёт уже установленные соединения — это ваш путь отката. Закрыли обе сессии, не проверив вход, — и единственным вариантом остаётся консоль хостера или загрузка в rescue-режиме.

Смена порта SSH: что она даёт и чего не даёт

Перенос SSH с 22 на нестандартный порт — популярный совет, и он полезен ровно в одном: массовые сканеры, которые долбятся строго в 22, перестают засорять auth.log. Читать логи становится реально.

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

# /etc/ssh/sshd_config
Port 2222

Дальше нужны три вещи, о которых регулярно забывают:

  • Открыть порт в файрволе до перезапуска: sudo ufw allow 2222/tcp или sudo firewall-cmd --permanent --add-port=2222/tcp && sudo firewall-cmd --reload.
  • На SELinux-системах разрешить порт для SSH: sudo semanage port -a -t ssh_port_t -p tcp 2222. Без этого демон не сможет занять порт.
  • Проверить, не запущен ли SSH через systemd-сокет. В свежих Ubuntu демон активируется через ssh.socket, и директива Port из sshd_config при этом игнорируется — порт задаётся в override сокета.
# Если активен ssh.socket — порт меняется здесь
systemctl is-enabled ssh.socket
sudo systemctl edit ssh.socket

# в открывшийся файл:
# [Socket]
# ListenStream=
# ListenStream=2222

Пустая строка ListenStream= обязательна: она сбрасывает унаследованное значение 22, иначе демон будет слушать оба порта.

SSH-ключи для Git: GitHub, GitLab и деплой-ключи

Git по SSH использует ту же механику. Отдельный ключ под Git-хостинг — хорошая практика: его компрометация не даёт доступа к продовым серверам.

ssh-keygen -t ed25519 -C "alice@github" -f ~/.ssh/id_ed25519_github
cat ~/.ssh/id_ed25519_github.pub      # содержимое вставить в настройках аккаунта

# проверка (ответ "successfully authenticated" — норма, шелла там нет)
ssh -T git@github.com
ssh -T git@gitlab.com

Привязка ключа к хосту через конфиг избавляет от догадок, какой ключ уйдёт:

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github
    IdentitiesOnly yes

Host gitlab-work
    HostName gitlab.com
    User git
    IdentityFile ~/.ssh/id_ed25519_work
    IdentitiesOnly yes

Второй блок решает частую задачу «два аккаунта на одном хостинге»: репозиторий клонируется как git clone git@gitlab-work:group/project.git, и клиент подставит нужный ключ.

Почему деплой-ключ должен быть отдельным

Личный ключ разработчика, положенный на сервер ради git pull, даёт этому серверу доступ ко всем репозиториям, к которым имеет доступ человек. Взлом одного веб-сервера превращается в компрометацию всей кодовой базы организации.

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

# одна строка в ~/.ssh/authorized_keys
restrict,from="203.0.113.0/24",command="/usr/local/bin/deploy.sh" ssh-ed25519 AAAAC3Nza... ci@runner
  • restrict выключает сразу всё лишнее: проброс портов, агента, X11, выделение псевдотерминала.
  • from= привязывает ключ к сети источника.
  • command= жёстко задаёт единственную выполняемую команду: что бы клиент ни попросил, запустится только она.
Схема разделения ключей: личный ключ администратора, отдельный ключ для Git-хостинга и ограниченный деплой-ключ с параметрами restrict и command
Разные задачи — разные ключи. Компрометация одного не тянет за собой остальные.

Как удалить SSH-ключ и отозвать доступ

Отзыв ключа — это не «поменять пароль». Ключ работает, пока его строка физически лежит в authorized_keys хотя бы на одном сервере.

Порядок действий при увольнении сотрудника или подозрении на утечку:

# 1. Найти все места, где встречается отпечаток/комментарий ключа
sudo grep -rn "alice@laptop" /home/*/.ssh/authorized_keys /root/.ssh/authorized_keys 2>/dev/null

# 2. Удалить строку (backup обязателен)
sudo cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
sudo sed -i '/alice@laptop/d' /home/deploy/.ssh/authorized_keys

# 3. Убедиться, что список ключей стал ожидаемым
ssh-keygen -lf /home/deploy/.ssh/authorized_keys

Проверьте все точки, а не только очевидную:

  • домашние каталоги всех пользователей, включая сервисных и root;
  • устаревший ~/.ssh/authorized_keys2, если он остался с древних времён;
  • нестандартный путь: sudo sshd -T | grep authorizedkeysfile — некоторые конфигурации выносят ключи в /etc/ssh/authorized_keys/%u;
  • ключи в CI, в панелях хостера, в Git-хостинге (аккаунтные ключи и deploy keys), в образах и в шаблонах виртуалок;
  • активные сессии: удаление строки не рвёт уже открытое соединение — завершите их через who и pkill -u username sshd.

На парке машин удобнее централизованный запрет. Директива RevokedKeys в sshd_config указывает на файл со списком отозванных публичных ключей — они не примутся, даже если строка случайно осталась в чьём-то authorized_keys.

Отдельно про «ssh удалить ключ» в другом смысле — запись сервера в known_hosts на клиенте:

ssh-keygen -R 203.0.113.10
ssh-keygen -R "[203.0.113.10]:2222"     # для нестандартного порта

Разбор ошибок: ssh -vvv и типовые сообщения

Универсальный первый шаг — подробный лог клиента:

ssh -vvv -o PreferredAuthentications=publickey -i ~/.ssh/id_ed25519_prod deploy@203.0.113.10

Ищите в выводе строки Offering public key: и то, что идёт следом. Если сервер отвечает Authentications that can continue: publickey и цикл повторяется — ключ отправлен, но не принят: проблема на сервере. Если клиент вообще не предлагает нужный файл — проблема локальная: не тот путь, не те права, ключ не в агенте.

Серверная сторона (нужен доступ через второй канал):

sudo journalctl -u ssh -f
sudo tail -f /var/log/auth.log        # Debian/Ubuntu
sudo tail -f /var/log/secure          # RHEL-семейство

Permission denied (publickey)

Самая частая ошибка и самая неинформативная. Проверяйте по порядку:

  1. Права: ~ не групп-записываемый, ~/.ssh — 700, authorized_keys — 600, владелец совпадает с пользователем входа.
  2. Тот ли пользователь: ключ лежит у deploy, а вы заходите как root.
  3. Тот ли ключ: сравните ssh-keygen -lf ключ.pub и ssh-keygen -lf authorized_keys — отпечатки должны совпасть.
  4. Целостность строки: перенос в середине ключа при копипасте.
  5. Пользователь не отсечён списком AllowUsers/AllowGroups, аккаунт не заблокирован (passwd -S deploy, значение L — заблокирован).
  6. SELinux-контекст каталога .ssh.

Bad owner or permissions on /home/user/.ssh/config

Клиент отказывается читать конфиг, доступный на запись группе или другим пользователям. Лечится одной командой: chmod 600 ~/.ssh/config. Та же логика применяется к самому каталогу.

WARNING: UNPROTECTED PRIVATE KEY FILE!

Приватный ключ читаем кем-то кроме владельца. chmod 600 ~/.ssh/id_ed25519. Частый источник — копирование ключа с флешки или из Windows-раздела, где права не сохраняются.

Host key verification failed

Отпечаток сервера не совпал с сохранённым в known_hosts. Законные причины: переустановка ОС, миграция на новую машину, восстановление из бэкапа, смена IP. Незаконная: MITM. Сначала убедитесь через второй канал (консоль хостера, документация), что новый отпечаток настоящий, и только потом удаляйте старую запись через ssh-keygen -R. Отключать проверку через StrictHostKeyChecking no — способ узаконить подмену сервера.

Too many authentication failures

Агент предложил больше ключей, чем разрешает MaxAuthTries. Решение — IdentitiesOnly yes в конфиге и точечный IdentityFile.

no matching host key type found / ssh-rsa

Старый RSA-ключ с подписью на SHA-1 против свежего OpenSSH. Правильное решение — перевыпустить ключ в ed25519. Временный обход — явно разрешить алгоритм в конфиге клиента для конкретного хоста через PubkeyAcceptedAlgorithms +ssh-rsa, но это откладывание проблемы, а не её решение.

Connection refused / Connection timed out

Это уже не аутентификация. refused — порт закрыт или демон не запущен: systemctl status ssh. timed out — трафик режет файрвол или группа безопасности у облачного провайдера. Проверяется снаружи, а не с самой машины.

Дерево диагностики ошибок SSH: от Permission denied publickey через проверку прав, пользователя и отпечатка ключа к серверным логам
Диагностика начинается с ssh -vvv и заканчивается логами sshd.

Как проверить настройку

После правок нужно посмотреть на сервер снаружи, а не изнутри. Локальные ss -tlnp и systemctl status показывают только то, что демон живой; они ничего не говорят о том, что видит интернет.

  • Порт SSH виден снаружи? Просканируйте хост через сканер портов. Если 22 (или ваш нестандартный порт) отвечает всему миру, следующий вопрос — нужно ли это. Лучший вариант для SSH — ограничение по IP на уровне файрвола или облачной security group, а не открытый доступ. Как читать результаты скана, разобрано в статье о проверке открытых портов.
  • Общая гигиена сервера. Прогоните домен через проверку безопасности: заголовки, TLS, признаки утечек конфигурации. SSH — только одна дверь; закрытая на ключ, она не спасает от открытой админки или отсутствующего HSTS. Системный чеклист по всему периметру — в материале о харденинге веб-сервера.
  • Проверка эффективного конфига. sudo sshd -T | grep -Ei 'passwordauth|permitroot|kbdinteractive' — единственный надёжный источник правды о том, что реально применилось.
  • Реальная попытка входа по паролю. ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password deploy@host должна завершиться отказом без запроса пароля. Если пароль спрашивают — парольный вход остался включён.

Для админских ключей есть уровень выше: аппаратный токен (ssh-keygen -t ed25519-sk) требует физического касания при каждом подключении, поэтому украденный файл ключа сам по себе бесполезен. Логика та же, что у современных методов входа в веб-сервисы — см. разборы двухфакторной аутентификации и passkeys против классической 2FA.

Частые вопросы

Можно ли использовать один SSH-ключ на всех серверах?

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

Что делать, если приватный ключ утёк?

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

Нужен ли fail2ban, если пароли отключены?

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

Почему ключ работает у одного пользователя и не работает у другого?

Почти всегда — права или владелец. Каталог .ssh, скопированный от другого пользователя через cp -r под sudo, сохраняет старого владельца, и sshd его отвергает. Проверьте ls -ld ~ ~/.ssh ~/.ssh/authorized_keys — владелец должен совпадать с именем пользователя, под которым вы входите.

Обязательно ли отключать вход root по SSH?

Как минимум отключите пароль для root (PermitRootLogin prohibit-password). Полный запрет плюс работа через обычного пользователя с sudo лучше: появляется персонализированный аудит — в логах видно, кто именно выполнил команду, а не безликий root.

Ключ перестал работать после переустановки сервера — почему?

Переустановка стирает authorized_keys вместе с домашним каталогом, а сервер получает новый host key. Первое лечится повторной установкой ключа, второе — ssh-keygen -R и подтверждением нового отпечатка через консоль хостера.

Чеклист

  • Ключ сгенерирован как ed25519, с осмысленным комментарием и парольной фразой.
  • Приватный ключ никуда не копировался: ни в чат, ни в репозиторий, ни в образ.
  • Публичный ключ добавлен нужному пользователю, одной строкой, отпечатки совпадают.
  • Права выставлены: домашний каталог не групп-записываемый, ~/.ssh — 700, authorized_keys — 600, владелец верный.
  • Клиентские ~/.ssh/config и приватные ключи — 600.
  • Вход по ключу проверен в отдельной сессии до изменения конфига сервера.
  • PasswordAuthentication no и KbdInteractiveAuthentication no подтверждены через sshd -T, а не только записаны в файл.
  • Проверен каталог sshd_config.d на перебивающие директивы.
  • sudo sshd -t выполнен до перезапуска, вторая сессия держалась открытой.
  • Порт (если менялся) открыт в файрволе, разрешён в SELinux, учтён ssh.socket.
  • Для Git и деплоя выпущены отдельные ключи, деплой-ключ ограничен restrict и command=.
  • Есть процедура отзыва: где искать ключи, кто её выполняет, как проверяется результат.
  • Порт проверен снаружи через сканер портов, периметр — через проверку безопасности.

Проверьте ваш сайт прямо сейчас

Проверить безопасность сайта →
Другие статьи: Безопасность
Безопасность
Правила WAF: написание эффективных политик веб-файрвола
16.03.2026 · 701 просм.
Безопасность
Как проверить сайт на вирусы: 4 уровня проверки и план лечения
01.04.2026 · 502 просм.
Безопасность
Заголовки безопасности: CSP, HSTS, X-Frame-Options и другие
10.03.2025 · 411 просм.
Безопасность
Реестр блокировок РКН в цифрах: анализ 131 000 заблокированных доменов (2026)
26.06.2026 · 395 просм.