Перейти к основному содержимому
02ОТДЕЛЬНЫЕ ТЕМЫ · ГЛАВА 02SSH-ключи глубокоprivatepublic

SSH-ключи глубоко

Прочитано 0%Квизы 0/3Тренажёры 0/2Уровень 1 · Новичок

Зачем это нужно

В главе «Файлы, пакеты, SSH» мы подключались к серверу по паролю и один раз сгенерировали ключ, чтобы пароль больше не вводить. Этого хватает, чтобы «работало». Но очень быстро наступает момент, когда «работает» мало: ключей становится два — для чемпионатного сервера и для GitHub; терминал начинает при каждом подключении спрашивать парольную фразу; команда подключения разрастается до ssh -i ~/.ssh/work_key -p 2222 student@192.168.1.10, которую невозможно запомнить. На этой странице разберём механизм ключей до конца: как пара ключей на самом деле доказывает серверу, кто ты, что лежит в каждом файле внутри ~/.ssh, зачем нужен агент и как файл config превращает длинные заклинания в короткое ssh champ.

Эта страница — углубление: сначала пройди главу «Файлы, пакеты, SSH», где ssh и ssh-keygen появляются впервые.

Как пара ключей доказывает, кто ты

Ключ SSH — это всегда пара из двух файлов, которые генерируются одновременно и математически связаны:

  • Приватный ключ (private key) — твой секрет. Никогда не покидает твою машину, никому не отправляется, ни в чат, ни в репозиторий.
  • Публичный ключ (public key) — открытая половина. Её можно показывать кому угодно: она кладётся на каждый сервер, куда ты хочешь входить.

Механика подключения — по сути «вызов-ответ»:

твоя машина сервер
┌───────────────────┐ ┌────────────────────────┐
│ приватный ключ │ │ authorized_keys: │
│ id_ed25519 │ │ ...твой публичный... │
└────────┬──────────┘ └───────────┬────────────┘
│ 1. «хочу войти как student» │
│ ────────────────────────────────────► │
│ 2. случайный вызов (challenge) │
│ ◄──────────────────────────────────── │
│ 3. подпись вызова приватным ключом │
│ ────────────────────────────────────► │
│ 4. проверка подписи публичным ключом │
│ ◄──────────────── вход разрешён ───── │

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

SSH · РУКОПОЖАТИЕ КЛЮЧАМИтвоя машинаid_ed25519приватный ключсерверauthorized_keysтвой публичный внутри1. «пускаю как student?»2. случайный вызов (challenge)3. подпись вызова приватным ключом4. подпись верна публичным → вход разрешёнприватный ключ подписывает вызов; сервер проверяет подпись публичным — сам приватный ключ по сети не передаётся
Приватный ключ подписывает случайный вызов сервера; сервер проверяет подпись публичным — сам приватный ключ по сети не передаётся.

Сгенерировать пару мы уже умеем, теперь прочитаем команду целиком:

Нажми на часть выражения

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

Что лежит в ~/.ssh

После пары подключений каталог ~/.ssh выглядит так:

ФайлЧто этоПрава
id_ed25519приватный ключ — секрет600 (только владелец, только чтение-запись)
id_ed25519.pubпубличный ключ — одна строка текста644
configтвои настройки подключений (разберём ниже)600
known_hostsотпечатки серверов, куда ты уже ходилведёт сам ssh
authorized_keysна сервере: список публичных ключей, кому можно входить600

Права — не формальность: ssh отказывается использовать приватный ключ, доступный на чтение кому-то кроме владельца, с ошибкой WARNING: UNPROTECTED PRIVATE KEY FILE!. Починка — chmod 600 ~/.ssh/id_ed25519 (вот где пригодилась глава про права).

Доставить публичный ключ на сервер проще всего командой ssh-copy-id student@192.168.1.10: она сама допишет твой .pub в ~/.ssh/authorized_keys на сервере с правильными правами. Руками это то же самое, что дописать одну строку в тот файл.

~/.SSH · ГДЕ ЛЕЖАТ КЛЮЧИ~/.ssh/ — твоя машинаid_ed25519приватный · права 600id_ed25519.pubпубличный · права 644config · known_hosts — тоже здесьauthorized_keysсервер · список впущенныхпубличных ключейssh-copy-idприватный остаётся дома под правами 600; публичный уезжает в authorized_keys на каждый сервер
Приватный ключ остаётся дома под правами 600; публичный уезжает командой ssh-copy-id в authorized_keys на каждый сервер.

А known_hosts решает обратную задачу — проверяет сервер: при первом подключении ssh показывает отпечаток (fingerprint) ключа сервера и спрашивает Are you sure you want to continue connecting?. После твоего yes отпечаток запоминается, и если однажды сервер ответит другим ключом, ssh поднимет тревогу REMOTE HOST IDENTIFICATION HAS CHANGED! — либо сервер переустановили, либо кто-то притворяется им.

Отвечено вопросов: 0 из 4
Какой из файлов можно спокойно отправить администратору сервера?
Что шифрует парольная фраза (passphrase), заданная при ssh-keygen?
ssh пишет WARNING: UNPROTECTED PRIVATE KEY FILE! Что случилось и как чинить?
Зачем нужен файл authorized_keys на сервере?
Отвечено верно: 0 из 4

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

Парольная фраза защищает ключ, но вводить её при каждом git push — мучение. Для этого есть агент — программа ssh-agent, которая один раз расшифровывает приватный ключ и держит его в памяти до конца сеанса; все следующие подключения обращаются к агенту и проходят без вопросов.

eval "$(ssh-agent -s)" # запустить агента (обычно уже запущен системой)
ssh-add ~/.ssh/id_ed25519 # добавить ключ — парольную фразу спросит один раз
ssh-add -l # список ключей, которые агент уже держит

Странная на вид первая строка объясняется просто: ssh-agent -s печатает команды настройки переменных окружения, а eval их выполняет в текущей оболочке — так остальные команды узнают, где искать агента. В Ubuntu с графическим входом агент, как правило, уже запущен, и остаётся только ssh-add.

SSH-AGENT · СПРОСИТЬ ОДИН РАЗ ЗА СЕАНСбез агента — вопрос при каждом подключенииgit pushpassphrase?git pushpassphrase?git pushpassphrase?с агентом — спросит один разssh-addагент держит ключв памятиpushpushpushssh-add расшифровывает ключ один раз за сеанс — дальше подключения проходят без вопросов
ssh-add расшифровывает ключ один раз за сеанс; агент держит его в памяти — дальше подключения проходят без вопросов.
Отвечено вопросов: 0 из 4
Что именно делает ssh-agent?
Какая команда добавит ключ в агента и спросит парольную фразу?
Зачем в строке eval "$(ssh-agent -s)" нужен eval?
Ты перезагрузил компьютер. Что будет с ключами, которые держал агент?
Отвечено верно: 0 из 4

~/.ssh/config: короткие имена вместо заклинаний

Команда ssh -i ~/.ssh/work_key -p 2222 student@192.168.1.10 — это четыре вещи, которые нужно помнить: ключ, порт, пользователь, адрес. Файл ~/.ssh/config позволяет записать их один раз:

Host champ
HostName 192.168.1.10
User student
Port 2222
IdentityFile ~/.ssh/work_key

После этого всё то же самое делает команда ssh champ — а заодно scp file.txt champ:~/ и любой инструмент поверх ssh, включая git. Разберём поля:

Нажми на часть выражения

Блоков Host в файле может быть сколько угодно — по одному на каждый сервер. Отступы внутри блока — просто читаемость: ssh их не требует, но все так пишут.

Несколько ключей на одной машине

Типичная ситуация: один ключ для чемпионатного сервера, второй — для GitHub. Ключи не обязаны называться id_ed25519: при генерации задай своё имя файла, например ~/.ssh/github_key. Дальше всё решает config — каждому серверу свой IdentityFile:

Host champ
HostName 192.168.1.10
User student
IdentityFile ~/.ssh/champ_key

Host github.com
User git
IdentityFile ~/.ssh/github_key
~/.SSH/CONFIG · СВОЙ КЛЮЧ НА КАЖДЫЙ ХОСТHost champIdentityFile champ_key192.168.1.10Host github.comIdentityFile github_keygithub.comssh читает config по алиасу Host и сам подставляет нужный IdentityFile — короткое имя тянет весь блок
ssh читает config по алиасу Host и сам подставляет нужный IdentityFile — короткое имя тянет за собой весь блок.

Для GitHub псевдоним совпадает с настоящим адресом — так git, который ходит на github.com, автоматически подхватит нужный ключ. Обрати внимание на User git: на GitHub все подключаются пользователем git, а кто именно ты — сервер понимает по предъявленному ключу. Именно поэтому команда проверки выглядит так:

ssh -T git@github.com

и отвечает Hi <твой-логин>! You've successfully authenticated... — ключ и есть твоё имя.

Отвечено вопросов: 0 из 4
Зачем нужен ssh-agent?
Что заменяет команда ssh champ после настройки блока Host champ в ~/.ssh/config?
Как заставить git использовать конкретный ключ для GitHub?
Почему при проверке подключения пишут ssh -T git@github.com, а не свой логин?
Отвечено верно: 0 из 4

Практика: собери свой ~/.ssh

Учебный терминал не умеет запускать настоящий ssh-keygen, но раскладку файлов — самое частое место ошибок — отрепетировать можно. Собери каталог ~/.ssh руками: создай его, положи внутрь «ключи» и запиши в config блок для сервера champ (используй echo 'текст' >> .ssh/config, чтобы дописывать строки).

Задание: Создай .ssh с парой ключей champ_key/champ_key.pub и файлом config
  • .ssh/champ_key
  • .ssh/champ_key.pub
  • .ssh/config
Учебный терминал. Введите help, чтобы увидеть список команд.
student@pgk:~$
Как это устроено под капотом
Никакого настоящего Linux здесь нет: файловая система — обычный JS-объект в памяти браузера, где папка — это вложенный объект, а файл — строка с содержимым. Команды ls, cd, mkdir, rm и остальные — функции, которые читают и меняют этот объект, а cp -r — просто глубокое копирование куска JSON. После каждой команды проверка квеста проходит по требуемым путям и смотрит, существуют ли они в этом дереве. Перезагрузишь страницу — «диск» создастся заново с нуля, так что ломать тут можно безнаказанно.

И набери команды этой страницы руками — на настоящей машине они должны отлетать без подглядывания:

Цель: точность ≥ 90%

ssh-keygen -t ed25519 -C 'oleg@laptop'

Шпаргалка

Команда / файлЧто делает
ssh-keygen -t ed25519 -C 'метка'сгенерировать пару ключей Ed25519
ssh-copy-id user@hostдоставить публичный ключ в authorized_keys сервера
chmod 600 ~/.ssh/id_ed25519починить права приватного ключа
eval "$(ssh-agent -s)"запустить агента в текущей оболочке
ssh-add ~/.ssh/id_ed25519добавить ключ агенту (passphrase — один раз)
ssh-add -lкакие ключи агент уже держит
~/.ssh/configблоки Host: адрес, пользователь, порт, ключ — под коротким именем
ssh -T git@github.comпроверить ключ для GitHub
id_ed25519 / id_ed25519.pubприватный (секрет!) / публичный (можно делиться)
known_hostsотпечатки серверов, которым ты уже доверился
Углубиться

Почему именно Ed25519, а не RSA. Старые руководства учат ssh-keygen -t rsa -b 4096. RSA-ключи по-прежнему работают, но Ed25519 моложе, короче (68 символов публичного ключа против сотен), быстрее и не имеет истории «слабых» вариантов при неудачном выборе длины. Новые ключи имеет смысл делать Ed25519; RSA остаётся для редких старых систем, которые Ed25519 не понимают.

Отпечаток ключа. Команда ssh-keygen -lf ~/.ssh/id_ed25519.pub печатает fingerprint — короткую сводку ключа вида SHA256:.... По ней удобно сверять ключи, не сравнивая длинные строки целиком: тот же отпечаток GitHub показывает в настройках рядом с каждым добавленным ключом.

Агент можно пробрасывать — осторожно. Флаг ssh -A (agent forwarding) позволяет с промежуточного сервера ходить дальше твоим локальным ключом, не копируя ключ на этот сервер. Удобно, но администратор промежуточного сервера в этот момент может пользоваться твоим агентом. Официальная документация прямо советует включать проброс только для доверенных машин; чаще правильный ответ — ProxyJump в config.

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

Дальше по теме:

Что должен уметь

  • Объяснять на пальцах, как пара ключей доказывает серверу личность и почему приватный ключ не передаётся по сети.
  • Называть роль каждого файла в ~/.ssh: ключи, config, known_hosts — и authorized_keys на сервере.
  • Чинить ошибку UNPROTECTED PRIVATE KEY FILE и понимать, зачем приватному ключу права 600.
  • Доставлять публичный ключ на сервер через ssh-copy-id и объяснять, что она меняет на сервере.
  • Пользоваться ssh-agent: добавить ключ, посмотреть список, объяснить, зачем нужна конструкция с eval.
  • Писать блоки Host в ~/.ssh/config — включая отдельные ключи для разных серверов и для GitHub.

Куда дальше: проверенные ресурсы

Интересный факт

SSH создал в 1995 году финский исследователь Тату Улёнен — после того, как в сети его университета завёлся сниффер паролей. Программа, написанная в ответ на один инцидент, за пару месяцев набрала двадцать тысяч пользователей.

Комментарии

Комментарии появятся после настройки. Нужен аккаунт GitHub — вход прямо в виджете выше.