Пароль на сервере перебирают роботы, ключ — нет. Поэтому первое, что делает администратор после создания виртуальной машины, — настраивает вход по SSH-ключу и закрывает парольную аутентификацию. Ниже — полный маршрут: генерация ключей на рабочей машине, перенос публичного ключа на сервер, настройка клиента и диагностика, когда сервер отвечает Permission denied (publickey).
Что понадобится до начала и как устроена пара ключей
Часто пишут, что клиент «шифрует данные приватным ключом, а сервер расшифровывает публичным». Так это не работает: сервер отправляет клиенту вызов — случайные данные, привязанные к сессии, клиент подписывает его приватным ключом, а сервер проверяет подпись публичным. Из подписи невозможно восстановить приватный ключ, поэтому публичную половину пары безопасно размещать хоть на сотне серверов.
Что нужно иметь под рукой:
- IP-адрес сервера и имя пользователя (
root,ubuntu,admin— зависит от образа); - рабочий способ попасть на сервер прямо сейчас: пароль по SSH либо консоль в панели провайдера — она спасёт при ошибке в
sshd_config; - OpenSSH-клиент на вашей машине.
Если сервера под задачу ещё нет, подойдёт облачный сервер Cloud4U — аренда по модели IaaS, где CPU, RAM и диск выделяются под конкретную нагрузку и меняются без переустановки. Для отработки ключевого доступа удобны почасовая тарификация и консоль VMware Cloud Director, через которую вы попадёте на сервер даже при полностью сломанном SSH.
Приватный и публичный ключ: что нельзя никому передавать
Приватный ключ (id_ed25519, без расширения) не покидает вашу машину никогда. Ни в мессенджер, ни в тикет поддержки, ни в git-репозиторий. Если кто-то просит прислать «ваш ключ», он имеет в виду публичный — файл .pub, одну строку вида ssh-ed25519 AAAAC3Nza... user@laptop.
Второе правило: одно устройство — одна пара ключей. Тогда при потере ноутбука вы удаляете одну строку из authorized_keys, а не перегенерируете доступ для всей команды. И генерируйте ключ на той машине, с которой будете подключаться: создавать пару на сервере и скачивать приватную часть себе — плохая практика.
Выбор алгоритма: Ed25519, RSA, ECDSA и аппаратные ключи (ed25519-sk)
По умолчанию берите Ed25519: около 128 бит стойкости, компактность, быстрая подпись и независимость от качества энтропии в момент подписи — в отличие от ECDSA, где слабая энтропия теоретически раскрывает ключ. Поддержка есть в OpenSSH с версии 6.5 (2014). DSA в современных версиях OpenSSH отключён по умолчанию и как алгоритм подписи больше не используется. RSA — только для совместимости со старым оборудованием и системами: устаревшие сетевые устройства, системы с OpenSSH ниже 6.5. Тогда 3072 или 4096 бит, но не 2048.
Отдельная ловушка: с OpenSSH 8.8 (2021) по умолчанию отключена подпись ssh-rsa на базе SHA-1. Симптом — старый RSA-ключ, годами работавший, внезапно перестаёт приниматься после обновления сервера. Сам ключ в порядке, перестал приниматься алгоритм подписи. Временное решение на клиенте:
ssh -o PubkeyAcceptedAlgorithms=+ssh-rsa user@server_ip
Правильное — перевыпустить ключ в Ed25519 или перейти на rsa-sha2-256/rsa-sha2-512: эти варианты подписи поддерживаются с OpenSSH 7.2 и остались без изменений.
Более надёжная альтернатива passphrase — привязка к аппаратному токену (YubiKey и совместимые с FIDO2):
ssh-keygen -t ed25519-sk -O resident -C "yubikey-work"
Тип ed25519-sk требует OpenSSH 8.2+ с обеих сторон. На диске остаётся только «заготовка», криптооперация выполняется внутри токена и требует физического касания, так что копировать такой ключ с украденного ноутбука бесполезно. Флаг -O resident сохраняет ключ в памяти токена — его можно извлечь на новой машине через ssh-keygen -K.
Проверка наличия OpenSSH-клиента в Linux, macOS и Windows 10/11
В Linux и macOS клиент установлен по умолчанию, версию смотрим через ssh -V. Если клиента нет: sudo apt install -y openssh-client в Debian/Ubuntu, sudo dnf install -y openssh-clients в AlmaLinux, Rocky Linux и CentOS Stream. В Windows 10 (со сборки 1809) и Windows 11 клиент доступен как встраиваемый компонент системы, но может быть не установлен; проверка и установка в PowerShell от администратора:
Get-WindowsCapability -Online -Name OpenSSH.Client*
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Если в выводе первой команды State: Installed — клиент уже на месте, при State: Not Present выполняем вторую команду. В Windows Server 2025 клиент и сервер OpenSSH установлены по умолчанию, в более ранних выпусках Windows Server, а также в Windows 10 и 11 — нет.
На Astra Linux, РЕД ОС и ALT Linux всё работает штатно — это тот же OpenSSH. Разница в другом: при аттестации ИСПДн или объектов КИИ у регулятора могут быть требования к криптоалгоритмам, и Ed25519 в перечень ГОСТ-средств формально не входит. На практике для административного доступа это закрывается организационными мерами и наложенными СЗИ, но проектную документацию лучше согласовать заранее.
Генерация ключа в Linux и macOS через ssh-keygen
ssh-keygen -t ed25519 -C "zoya@work-laptop"
Комментарий после -C попадёт в конец публичного ключа и останется видимым в authorized_keys — через полгода именно он подскажет, чей это ключ.
Утилита задаст три вопроса. Первый — путь сохранения (/home/zoya/.ssh/id_ed25519): нажмите Enter для основного ключа, для отдельной задачи задайте своё имя. Второй и третий — парольная фраза. Passphrase шифрует приватный ключ на диске: без неё файл, попавший в чужие руки, сразу даёт доступ ко всем серверам. Вводить фразу на каждое подключение не придётся — для этого есть агент ключей. Пустой passphrase разумен только для сервисных ключей автоматизации.
В выводе строка SHA256:... — отпечаток ключа, он пригодится, чтобы сверить, тот ли ключ лежит на сервере. Проверяем результат через ls -l ~/.ssh/: должны быть id_ed25519 (приватный, около 400 байт) и id_ed25519.pub (одна короткая строка — ключи Ed25519 заметно компактнее RSA).
Разбор флагов: -t, -b, -C, -a, -f
-t— тип ключа:ed25519,rsa,ecdsa,ed25519-sk. Исторически без флага генерировалась пара RSA, поэтому тип указываем явно.-b— длина в битах. Для Ed25519 бессмысленен, для RSA обязателен:ssh-keygen -t rsa -b 4096.-a— число раундов KDF при шифровании приватного ключа. По умолчанию 16;-a 100замедляет перебор passphrase.-f— путь к файлу, позволяет обойтись без интерактивного ввода:
ssh-keygen -t ed25519 -a 64 -C "deploy@ci-runner" -f ~/.ssh/id_ed25519_deploy -N ""
Здесь -N "" задаёт пустую фразу — вариант для CI/CD, не для персонального ключа. Флаг -o из старых инструкций указывать не требуется: современные версии ssh-keygen сохраняют приватный ключ в новом формате и без него.
Права доступа на ~/.ssh и владелец файлов
Самая частая причина «ключ настроил, а не пускает» — права. Демон sshd при включённом StrictModes (по умолчанию) отказывается читать ключи из каталога, доступного на запись кому-то кроме владельца; клиент так же откажется использовать приватный ключ, который видят посторонние.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub
То же на сервере после установки ключа: chmod 700 ~/.ssh, chmod 600 ~/.ssh/authorized_keys, chown -R $USER:$USER ~/.ssh.
Отдельно про домашний каталог. Если на /home/zoya стоят права 775 или 777, либо владелец каталога — не тот пользователь, sshd откажет в доступе, даже когда внутри .ssh всё идеально:
chmod 750 /home/zoya
chown zoya:zoya /home/zoya
Сценарий типичен после восстановления из резервной копии или массового chmod -R по домашним каталогам.
Passphrase и ssh-agent: удобство без потери безопасности
Расшифрованный ключ держит в памяти агент:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
В GNOME и KDE агент уже запущен системой, достаточно одного ssh-add. macOS умеет хранить фразу в Keychain: ssh-add --apple-use-keychain ~/.ssh/id_ed25519, а чтобы не повторять это после перезагрузки, в ~/.ssh/config добавляют блок Host * с UseKeychain yes и AddKeysToAgent yes. В Windows роль агента играет служба ssh-agent, по умолчанию отключённая (PowerShell от администратора):
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Посмотреть загруженные ключи — ssh-add -l. Ответ The agent has no identities означает, что ключ не добавлен, а Could not open a connection to your authentication agent — что агент вообще не запущен в этой сессии.
Генерация ключа в Windows: встроенный OpenSSH и PuTTYgen
Для Windows есть два маршрута с разными форматами файлов, смешивать их не стоит: встроенный OpenSSH — для PowerShell, WSL и скриптов, PuTTYgen — для графического PuTTY и WinSCP.
Генерация в PowerShell и исправление прав на приватный ключ через icacls
Синтаксис OpenSSH одинаков везде: ssh-keygen -t ed25519 -C "zoya@win-work". Ключи будут созданы в C:\Users\<имя>\.ssh\. Скопировать публичный в буфер: Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard.
Типичная для Windows проблема: файлы наследуют разрешения каталога, и на приватный ключ оказываются права у групп Пользователи, Прошедшие проверку или SYSTEM. Клиент отвечает Permissions for '...' are too open. This private key will be ignored. chmod в Windows нет, исправляем через icacls:
icacls $env:USERPROFILE\.ssh\id_ed25519 /inheritance:r
icacls $env:USERPROFILE\.ssh\id_ed25519 /grant:r "$($env:USERNAME):(R)"
icacls $env:USERPROFILE\.ssh\id_ed25519 /remove "Authenticated Users" "BUILTIN\Users" "SYSTEM"
Отдельный случай — Windows как сервер. На Windows Server с OpenSSH Server для пользователей из группы администраторов действует не C:\Users\<имя>\.ssh\authorized_keys, а общий C:\ProgramData\ssh\administrators_authorized_keys; ключ в домашнем каталоге просто проигнорируют. На файл нужны жёсткие права:
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
PuTTYgen: генерация, сохранение .ppk и конвертация в формат OpenSSH
PuTTYgen входит в стандартный установщик PuTTY. Порядок действий:
- В блоке Parameters выберите тип ключа EdDSA и оставьте
Ed25519 (255 bits). Именно EdDSA, а не «SSH-2 RSA 2048»; если сервер устаревший — RSA с 4096 бит. - Нажмите Generate и подвигайте мышью в пустой области окна — PuTTYgen собирает энтропию из движений курсора.
- Заполните Key comment и Key passphrase.
- Save private key — сохраните
.ppk, напримерC:\Users\zoya\.ssh\work.ppk.
Ловушка, на которой спотыкается почти каждый: файл, сохранённый кнопкой Save public key, сервер не примет. Это формат RFC 4716 — многострочный, с заголовками ---- BEGIN SSH2 PUBLIC KEY ----, а в authorized_keys нужен однострочный формат OpenSSH. Брать нужно текст из верхнего поля окна — «Public key for pasting into OpenSSH authorized_keys file». Если окно уже закрыто, откройте .ppk кнопкой Load, введите passphrase — поле заполнится заново.
Конвертация нужна постоянно: ключ сделан в PuTTYgen, а подключаться надо из WSL или Ansible. Через интерфейс: .ppk → OpenSSH — Load → меню Conversions → Export OpenSSH key; OpenSSH → .ppk — Load → фильтр All Files → выбрать id_ed25519 → Save private key. Через командную строку с пакетом putty-tools:
puttygen work.ppk -O private-openssh -o ~/.ssh/id_ed25519
puttygen work.ppk -O public-openssh -o ~/.ssh/id_ed25519.pub
puttygen ~/.ssh/id_ed25519 -o work.ppk
После конвертации приватного ключа в Linux сразу выставьте chmod 600. Потеряли .pub, но приватный ключ цел? Публичную часть можно восстановить, обратное невозможно:
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub
Добавление публичного ключа на сервер
Публичный ключ должен оказаться в ~/.ssh/authorized_keys того пользователя, под которым вы входите. Одна строка — один ключ.
Автоматическая и ручная установка ключа в authorized_keys
Способ первый — ssh-copy-id, если парольный вход пока разрешён:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server_ip
Утилита создаст ~/.ssh с правами 700, допишет ключ и выставит 600. Указывайте .pub явно: без -i утилита может отправить все ключи из агента. Нестандартный порт — флагом -p 2222.
Способ второй — вручную одной командой, когда ssh-copy-id недоступен (в Windows его нет):
cat ~/.ssh/id_ed25519.pub | ssh user@server_ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Из PowerShell то же самое с Get-Content вместо cat. Обратите внимание на >>, а не >: одиночная стрелка затрёт все ключи, которые уже лежали в файле.
Способ третий — через панель провайдера. При создании ВМ почти везде есть поле для публичного ключа: сервер поднимается уже с настроенным ключевым доступом.
Сверить, тот ли ключ лежит на сервере, можно по отпечатку:
ssh-keygen -lf ~/.ssh/id_ed25519.pub
ssh user@server_ip "ssh-keygen -lf ~/.ssh/authorized_keys"
Строки SHA256:... должны совпасть. Из PuTTY подключение настраивается так: Connection → SSH → Auth → Credentials, поле Private key file for authentication — путь к .ppk; в Connection → Data в Auto-login username — имя пользователя.
Ограничение прав ключа: from, command, no-port-forwarding
Строка в authorized_keys может начинаться с опций — и это превращает ключ из универсального доступа в узкий пропуск. Ключ для системы резервного копирования, которому разрешено только снимать дамп и только с конкретной подсети:
from="10.20.0.0/24",command="/usr/local/bin/backup-dump.sh",no-port-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3Nza... backup@nas
from="..."— принимать ключ только с этих адресов или подсетей;command="..."— при входе выполняется строго эта команда, что бы клиент ни просил; запрошенная им попадёт вSSH_ORIGINAL_COMMAND;no-port-forwarding,no-agent-forwarding,no-X11-forwarding— запрет туннелей, проброса агента и графики;no-pty— не выдавать терминал.
Есть краткая форма restrict, которая включает все запреты разом, а нужное возвращается точечно: restrict,pty,from="192.0.2.5" ssh-ed25519 AAAA.... Для деплой-ключей в CI/CD это минимальная разумная мера. Раз в квартал полезно смотреть, чьи ключи лежат на серверах:
sudo awk '/^ssh-|^ecdsa-|^sk-/ {print FILENAME": "$NF}' /home/*/.ssh/authorized_keys /root/.ssh/authorized_keys 2>/dev/null
Когда машин больше пары десятков, россыпь ключей заменяют SSH-сертификатами: центр сертификации подписывает ключ пользователя на ограниченный срок, сервера доверяют подписи через TrustedUserCAKeys, а отзыв доступа сводится к тому, что сертификат не продлевают.
Настройка входа без пароля и отключение парольной аутентификации
Конфиг ~/.ssh/config: алиасы, IdentityFile, ProxyJump
Когда серверов больше одного, набирать ssh -i ~/.ssh/id_ed25519_deploy -p 2222 deploy@203.0.113.10 надоедает на третий раз. Создайте ~/.ssh/config:
Host prod-web
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_deploy
IdentitiesOnly yes
Host db-internal
HostName 10.0.5.20
User admin
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
ProxyJump prod-web
Host *
ServerAliveInterval 60
AddKeysToAgent yes
Теперь подключение — просто ssh prod-web, а ssh db-internal автоматически пройдёт через бастион, не требуя копировать на него приватный ключ.
Ключевая опция здесь — IdentitiesOnly yes, и её пропускают почти всегда. Без неё клиент предлагает серверу все ключи из агента подряд; если их больше пяти-шести, сервер разрывает соединение с Too many authentication failures ещё до того, как дойдёт очередь до нужного. ServerAliveInterval 60 спасает от обрыва простаивающих сессий на промежуточном NAT. Права на конфиг — chmod 600.
Правка sshd_config без риска потерять доступ к серверу
Перед правкой убедитесь, что вход по ключу уже работает прямо сейчас, оставьте открытой вторую SSH-сессию и проверьте, что консоль в панели провайдера открывается.
Вместо редактирования основного файла лучше положить отдельный файл в каталог подключаемых конфигураций — так обновление пакета не затрёт изменения. Директива Include /etc/ssh/sshd_config.d/*.conf есть в актуальных выпусках Ubuntu, Debian, AlmaLinux и Rocky Linux; проверить её наличие можно командой grep -i include /etc/ssh/sshd_config:
sudo tee /etc/ssh/sshd_config.d/99-keys-only.conf > /dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
EOF
KbdInteractiveAuthentication no закрывает интерактивный ввод пароля, через который на некоторых сборках пароль просачивается в обход PasswordAuthentication no. Если Include в системе нет, добавьте те же строки в /etc/ssh/sshd_config, сделав копию файла, и проверьте, что параметры не заданы повторно ниже: sshd применяет первое встреченное значение.
Проверяем синтаксис командой sudo sshd -t — отсутствие вывода означает, что ошибок нет. Полезнее посмотреть итоговую конфигурацию с учётом всех включённых файлов:
sudo sshd -T | grep -Ei "passwordauthentication|pubkeyauthentication|permitrootlogin|kbdinteractive"
Применяем через sudo systemctl reload sshd — reload перечитывает конфигурацию, не обрывая сессии. На Debian и Ubuntu служба может называться ssh. Если в системе включена сокет-активация sshd (проверяется через systemctl is-enabled ssh.socket), то при изменении порта одного reload не хватит — нужен sudo systemctl restart ssh.socket.
Из третьего окна, не закрывая страховочную сессию, проверяем, что ключевой вход работает, а парольный закрыт:
ssh prod-web
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@server_ip
Первая команда должна пустить без вопросов, вторая — ответить Permission denied (publickey).
Проверка и решение проблем
Основной инструмент диагностики — подробный режим клиента ssh -v user@server_ip. В выводе ищите строки Offering public key, Server accepts key и Authenticated to ... using "publickey".
Клиент вообще не предлагает ключ. Строки Offering public key нет — клиент не нашёл файл или не считает его подходящим. Проверьте путь в IdentityFile, права на приватный ключ (600) и то, что агент держит ключ (ssh-add -l). Укажите ключ явно: ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@server_ip.
Ключ предложен, но сервер его отверг — после Offering public key сразу идёт Permission denied (publickey). Проблема на сервере: заходите через консоль провайдера и смотрите sudo journalctl -u ssh -n 50 --no-pager, на системах с rsyslog — /var/log/auth.log (Debian, Ubuntu) или /var/log/secure (AlmaLinux, Rocky Linux). Расшифровка частых записей:
Authentication refused: bad ownership or modes for directory /home/zoya— сработалStrictModes. Исправляетсяchmod 750иchownна домашний каталог.no such identityили пустойauthorized_keys— ключ установлен не туда: частый случай, когда ключ ставили пользователюroot, а подключаются какubuntu.key_read: uudecode failed— строка ключа повреждена переносом или лишним пробелом.userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms— тот самый случай с отключённой подписью SHA-1 у старых RSA-ключей.
Too many authentication failures. Клиент перебрал все ключи из агента и исчерпал лимит попыток сервера (MaxAuthTries, по умолчанию 6). Исправляется IdentitiesOnly yes в конфиге.
Windows: Permissions for '...' are too open. Разбирали в разделе про icacls. В WSL та же ошибка возникает, если ключ лежит на диске Windows (/mnt/c/Users/...): файловая система DrvFs не хранит права Unix. Скопируйте ключ внутрь WSL и выставьте chmod 600.
Изменился отпечаток сервера. Появляется WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!, подключение блокируется. Причин две: сервер переустановили — или кто-то встал посередине соединения. Сначала убедитесь, что верно первое, сверив отпечаток через консоль провайдера, и только потом удаляйте старую запись командой ssh-keygen -R server_ip.
Passphrase забыта. Восстановить нельзя, но если ключ добавлен в агент, его можно сменить в текущей сессии: ssh-keygen -p -f ~/.ssh/id_ed25519.
Приватный ключ утрачен или скомпрометирован. Сгенерируйте новую пару на чистой машине; зайдите на серверы через страховочный доступ; удалите строку старого ключа из authorized_keys на каждом сервере и добавьте новый; пройдите по внешним сервисам, куда загружали публичную часть; просмотрите журналы на предмет входов с посторонних адресов.
Класть приватный ключ в облачное хранилище, в репозиторий или на общий диск нельзя — это ровно тот путь, которым ключи и утекают. Если копия нужна, храните её в менеджере паролей или на зашифрованном носителе. Правильнее не создавать резервную копию ключа вообще, а иметь на серверах второй ключ доступа — с другой машины или с аппаратного токена.
