Короткий ответ
Скомпрометированный ключ отзывают везде, где он в authorized_keys, authorized_keys2, cloud-init, gitlab deploy keys, панелях и агентах. Сгенерируйте новую пару на безопасной машине, разложите новый pubkey пользователю admin, удалите старую строку по fingerprint, проверьте Accepted publickey в journal. Не «поменяйте пароль UNIX» вместо отзыва ключа: SSH при PubkeyAuthentication пароль не спрашивает. Не оставляйте старый ключ «на ноутбуке в отпуске».
Хост host.example (10.0.20.10). Параллельно закройте root SSH, если он был открыт: root login.
Симптомы и как отличить
Accepted publickey for admin from 203.0.113.5в нерабочее время;- в
authorized_keysкомментарийivan-old-laptopили ключ без комментария; - один и тот же
SHA256:…на десятке серверов; - приватный ключ лежит в
~/Downloads, в тикете, в ansible-vault «на время».
| Сигнал | Не компрометация ключа | Куда |
|---|---|---|
Failed publickey затем пароль | боты | парольный SSH |
| Свой IP, свой ноут | норма | аудит last |
| Уволенный UNIX-аккаунт ещё активен | учётка | неиспользуемые учётки |
| Подозрение на rootkit | шире IR | не только keys |
Возможные причины
- Ноутбук украден без disk encryption / без пароля агента.
- Ключ без passphrase в CI, в Docker image, в
.env. - Копия
id_rsaв backup NAS world-readable. - Агент ssh-agent проброшен на скомпрометированный hop (
ForwardAgent yes). - Старый ключ сотрудника не сняли с
admin(общая учётка). - AuthorizedPrincipals / сертификаты SSH CA: отозвали не тот serial.
Диагностика
1. Какие ключи пускают admin
sudo awk '{print}' /home/admin/.ssh/authorized_keys
sudo ssh-keygen -lf /home/admin/.ssh/authorized_keys
sudo ls -la /home/admin/.ssh/
sudo grep -Rni . /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys 2>/dev/nullРежимы: каталог 700, файл 600, владелец admin. 644 на ключах — sshd может игнорировать файл (StrictModes).
2. Чем входили недавно
sudo journalctl -u ssh --since '30 days ago' --no-pager | grep 'Accepted publickey'
lastlog -u admin
last adminOpenSSH может логировать fingerprint в Accepted publickey for admin … ssh2: ED25519 SHA256:… — зависит от версии и LogLevel. На 22.04/24.04 при LogLevel VERBOSE чаще виден SHA256. Если только IP — сверяйте по времени с известными hop.
3. Где ещё лежит тот же pubkey
Ищите строку или fingerprint по инвентарю (ansible, gitlab, панели облака, jump host.example). Один хост — не инцидент закрыт.
# на jump-хосте
grep -F 'AAAAC3NzaC1lZDI1NTE5AAAA' /home/admin/.ssh/authorized_keys /etc/ssh/authorized_keys 2>/dev/null || trueПодставьте свой blob, не пример. Не публикуйте украденный приватный ключ в заявке — только fingerprint и comment.
4. Сертификаты CA
sudo sshd -T | grep -Ei 'trustedusercakeys|authorizedprincipals|pubkeyacceptedalgorithms'
sudo ls /etc/ssh/ | grep -i caЕсли вход по SSH-сертификату, удаление строки из authorized_keys недостаточно — нужен KRL (revoked_keys) или перевыпуск CA. Не путайте с обычным pubkey.
Решение
Сценарий A. Обычный pubkey admin на одном хосте
- С доверенной машины сгенерируйте новую пару (ed25519, passphrase):
ssh-keygen -t ed25519 -a 64 -f ~/.ssh/admin-host-example-2026 -C 'admin@host.example-2026-09'- Добавьте новый pubkey до удаления старого (консоль открыта):
# на сервере, вставив новую строку
sudo -u admin mkdir -p /home/admin/.ssh
sudo -u admin chmod 700 /home/admin/.ssh
printf '%s\n' 'ssh-ed25519 AAAA... admin@host.example-2026-09' | sudo tee -a /home/admin/.ssh/authorized_keys
sudo chown admin:admin /home/admin/.ssh/authorized_keys
sudo chmod 600 /home/admin/.ssh/authorized_keys-
Проверьте вход новым ключом во втором окне.
-
Удалите старую строку целиком. Не комментируйте «на неделю».
sudo -u admin ssh-keygen -lf /home/admin/.ssh/authorized_keys- На рабочей станции: уберите старый ключ из агента и с диска (после backup в сейф, если нужен forensic copy офлайн).
ssh-add -d ~/.ssh/id_ed25519 2>/dev/null || true
ssh-add -lСценарий B. Один ключ на парк
Отзыв — массовая замена authorized_keys и deploy keys. Инвентаризация: ansible grep, cloud metadata ssh-keys, GitHub/GitLab, панели Proxmox, сетевые ОС. Порядок: jump-хост первым, иначе потеряете вход в сегмент.
Не переиспользуйте новый ключ снова на 40 хостов, если политика — per-host или per-user. Минимум: per-person, не shared admin на всех с одним ключом. Shared admin + один ключ = один инцидент на парк.
Сценарий C. ForwardAgent и hop
Если подозреваете проброс агента:
# клиентский конфиг: выключить
# ForwardAgent noНа серверах не держите AllowAgentForwarding yes без нужды (sshd -T | grep allowagentforwarding). Скомпрометированный hop с форвардом = использование ключа без кражи файла.
Сценарий D. Ключ в git
Считайте его сгоревшим независимо от «репозиторий private». История git хранит blob. Ротация + git filter не отменяет отзыв на серверах. Проверьте CI variables.
После отзыва имеет смысл сузить SSH: sshd_config и аудит пользователей.
Как проверить, что проблема устранена
- Fingerprint старого ключа отсутствует во всех
authorized_keysинвентаря. ssh -i old_key admin@10.0.20.10→Permission denied.ssh -i new_key admin@10.0.20.10→ код 0.- В journal нет
Acceptedсо старым SHA256 (если логируется). - Deploy keys в GitLab/панелях обновлены.
ssh-add -lна рабочих станциях админов не держит старый ключ.
Если не помогло
- Вход старым ключом жив:
AuthorizedKeysFileуказывает на несколько путей (.ssh/authorized_keys .ssh/authorized_keys2), cloud-init при буте дописывает из metadata. Match User adminчитает ключи из/etc/ssh/authorized_keys/%u.- AuthorizedKeysCommand (LDAP/sss) — правьте каталог, не файл.
- Сертификат CA не отозван: нужен KRL, не только keys.
- Пароль UNIX сменили, ключ жив — ожидаемо.
- Подозрение, что украли новый ключ тем же каналом (тот же незашифрованный ноут) — сначала диск/агент, потом очередная пара.
Профилактика
- Passphrase на ключе, диск LUKS/BitLocker, таймаут агента.
ForwardAgent noпо умолчанию;-Aтолько точечно.- Именные ключи, комментарий с ФИО и годом, не
admin. - Инвентарь pubkey (fingerprint → человек → хосты).
- Отзыв в чеклисте увольнения вместе с UNIX: неиспользуемые учётки.
- Не коммитить
id_ed25519«даже в private».
FAQ
Нужно ли менять пароль admin?
Да как слой, нет как замена отзыва ключа. При ключах пароль UNIX нужен для sudo/консоли, не для SSH.
Можно ли добавить from=«IP» вместо отзыва?
from="10.0.20.0/24" сужает украденный ключ, не лечит компрометацию. После кражи всё равно ротация.
Что делать с ключом в ssh-agent на телефоне?
Считайте отдельной копией. Удалите identity, перевыпустите. Агент с разблокированным ключом = ключ без passphrase на время сессии.
Host key сервера украден?
Это другая история (MITM/known_hosts). Ротируйте host key (ssh-keygen -A осознанно, рассылка нового FP). Не путайте с user key.
FIDO2/sk-ключи лучше?
Да против кражи файла: без токена приватник не уезжает. Это не отменяет authorized_keys hygiene и отзыв serial/credential при потере токена.