Debian 13: проведено ротацію SSH-ключів — акуратно відкличіть доступ і запобігайте розростанню ключів (case #73)

Було корисно?

Ви провели ротацію SSH-ключів. Усі кивнули. Тікети закрито. А потім підрядник, який «точно втратив доступ», все ще заходить з IP кав’ярні, якого ви ніколи раніше не бачили.
Саме так ротація ключів зазвичай провалюється в реальному житті: не на рівні криптографії, а на людському — копіювання/вставка, дрейф, забуті бастіони і та одна
легасі-машина під столом, яку «не можна перезавантажити».

Debian 13 робить простим запуск адекватного стека OpenSSH. Складність — у чистому відкликанні доступу та в доведенні цього факту. Цей кейс-файл — виробничий план:
як інвентаризувати місця зберігання ключів, провести ротацію без простоїв, відкликати точно і припинити відростання ключів як бур’яну на занедбаній парковці.

Визначте, що ви маєте на увазі під «відкликано»

«Ми провели ротацію SSH-ключів» — речення, яке може означати три різні речі, і лише одна з них операційно задовольняє.

  • Заміна ключа: ви видали нові ключі і сказали людям їх використовувати. Старі ключі можуть і далі працювати. Це не відкликання; це ввічлива порада.
  • Видалення ключа: ви прибрали старі публічні ключі з authorized_keys (і скрізь, де вони могли б аутентифікуватися). Це вже відкликання,
    але тільки для шляхів, які ви пам’ятали.
  • Інвалідація доступу: ви видалили/заблокували ключі, завершили живі сесії там, де потрібно, провели аудит альтернативних шляхів (бастіони, спільні облікові записи,
    пересилання агентів, jump-хости) і можете довести, що старі ключі більше не аутентифікуються. Це те, чого ви прагнете.

У Debian 13 OpenSSH здатний, прозаїчний і строгий, якщо ви йому це дозволите. Використовуйте це. Ваш ворог — не математика. Ваш ворог — розростання ключів:
поступове, непомітне дублювання ключів у випадкових місцях, бо найшвидший спосіб «вирішити доступ» — додати ще один рядок
до ще одного authorized_keys.

Корисна ментальна модель: розглядайте SSH-ключі як облікові дані з життєвим циклом, а не як «файли, які розробники тримають у своєму домашньому каталозі».
Життєвий цикл означає інвентаризацію, видачу, ротацію, термін дії, відкликання і перегляд. Якщо щось із цього відсутнє — у вас не система, а фольклор.

Одна цитата, яку я тримаю на стікері, бо це робота:
Надія — не стратегія.
— Ген. Гордон Р. Салліван

Жарт №1: SSH-ключі самі по собі не «закінчуються». Вони як авокадо: якщо за ними не стежити, вони або назавжди недостиглі, або раптово — інцидент безпеки.

Цікавинки & історія (чому сьогоднішній безлад існує)

Трохи контексту допоможе вам діагностувати, чому ваш флот виглядає так, ніби ним керував комітет єнотів.
Ось конкретні факти, що зазвичай мають значення при прибиранні після ротації.

  1. SSH1 vs SSH2: SSH2 замінив SSH1 на початку 2000-х, бо SSH1 мав вразливості. «SSH» сьогодні практично означає SSH2, але легасі-припущення
    залишаються в старих скриптах і пристроях.
  2. DSA-ключі застаріли: ssh-dss (DSA) вийшов із ужитку і за замовчуванням вимкнений у сучасному OpenSSH через обмеження алгоритму та політику. Якщо ви ще бачите DSA-ключі в authorized_keys, ви дивитесь на археологічні шари.
  3. Ed25519 став рекомендованим за замовчуванням: ключі Ed25519 компактні, швидкі і зазвичай кращі за RSA у багатьох середовищах. Проекти ротації часто одночасно оновлюють алгоритм.
  4. authorized_keys створено для простоти: це просто файл з рядками. Саме тому розростання ключів таке просте:
    інструменти розподілу опціональні, копіювання/вставка завжди доступні.
  5. Існують сертифікати, але більшість організацій їх не використовує: OpenSSH підтримує підписані CA користувацькі сертифікати, що значно зменшують розростання, але вони
    вимагають трохи роздумів на початку. Багато команд відкладають ці роздуми назавжди.
  6. Відкликання несиметричне: з сирими публічними ключами ви відкликаєте, видаляючи їх скрізь. З сертифікатами можна відкликати серійні номери або ID ключа через список відкликання, але потрібна інфраструктура CA.
  7. Пересилання агента зробило популярним «просто залізти через бастіон»: воно також зробило межі облікових даних нечіткими. Коли відкликання не вдається, пересилання агента часто виявляється у складі проблеми.
  8. StrictModes існує не просто так: SSH відмовляється використовувати небезпечно дозволені файли ключів, бо намагається захистити вас від вас самих.
    Коли люди «виправляють» помилки з дозволами, вимикаючи перевірки, вони зазвичай створюють більшу зону ураження.
  9. SSH-логи корисні, але не дружні: OpenSSH логгює те, що сталося, а не те, що вам хочеться чути. Найшвидше відновлення після інциденту мають команди, які точно знають, які рядки логу відповідають яким шляхам аутентифікації.

Швидкий план діагностики

Коли хтось каже «старий ключ досі працює» або «новий ключ не працює», не починайте сліпо редагувати файли.
Знайдіть вузьке місце трьома перевірками.

1) Визначте, де приймається рішення про аутентифікацію

Користувач автентифікується безпосередньо на цільовому хості, через бастіон, через обгортку з примусовою командою або через обліковий запис конфігураційного менеджера?
Якщо ви припуститесь помилки тут, ви «відкличете» не те місце і нічого не зміниться.

2) Підтвердіть, який ключ фактично пропонується

Клієнтський SSH охоче запропонує низку ключів, якщо ви явно не вкажете інше. Люди часто вірять, що тестують новий ключ, тоді як їхній агент
спочатку пропонує старий і він проходить.

3) Перевірте джерело ключа на сервері

На Debian 13 ключі можуть йти з ~/.ssh/authorized_keys, але також з шляхів AuthorizedKeysFile, або
через AuthorizedKeysCommand (LDAP/HTTP/що-завгодно), або з авторизованих ключів спільного облікового запису, про який ви забули.

Лише після того, як ці три пункти зафіксовано, починайте видаляти рядки, розгортати зміни конфігу і завершувати сесії.

Практичні завдання (команди, виводи, рішення)

Нижче наведені виробничі завдання, які можна виконати на Debian 13 (або на вашій адміністративній робочій станції), щоб перейти від «ми провели ротацію ключів» до «ми відкликали доступ і довели це».
Кожне завдання включає: команду, що означає типовий вивід, і рішення, яке ви приймаєте далі.

Завдання 1 — Перевірте версію OpenSSH сервера (знайте, які у вас можливості)

cr0x@server:~$ sshd -V
OpenSSH_9.7p1 Debian-3, OpenSSL 3.3.1 4 Jun 2024

Значення: У вас сучасний OpenSSH з добрими налаштуваннями за замовчуванням і підтримкою сертифікатів.
Рішення: Віддавайте перевагу ключам Ed25519 або користувацьким сертифікатам OpenSSH; уникайте триманняся за легасі-алгоритми «для сумісності» без доказів.

Завдання 2 — Перелічіть активні SSH-слухачі (уникайте відкликання на неправильному демоні)

cr0x@server:~$ ss -ltnp | grep ssh
LISTEN 0      128          0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=812,fd=3))
LISTEN 0      128             [::]:22           [::]:*    users:(("sshd",pid=812,fd=4))

Значення: sshd слухає на порті 22 для IPv4 і IPv6.
Рішення: Якщо ви очікували бастіон на порту (наприклад, 2222) або лише IPv4, узгодьте це зараз. «Відкликано на порті 22» не допоможе, якщо користувачі підключаються інакше.

Завдання 3 — Підтвердіть джерела аутентифікації sshd (AuthorizedKeysFile / Command)

cr0x@server:~$ sshd -T | egrep 'authorizedkeys(file|command)|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication'
pubkeyauthentication yes
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2
authorizedkeyscommand none
passwordauthentication no
kbdinteractiveauthentication no

Значення: Ключі надходять із локальних файлів у домашніх директоріях користувачів; зовнішньої команди ключів немає.
Рішення: Відкликання означає редагування тих файлів (або їх заміну через конфігураційний менеджмент). Якщо встановлено AuthorizedKeysCommand, відкликання централізоване і ви мусите виправити джерело.

Завдання 4 — Інвентаризуйте локальних користувачів з домашніми директоріями (знайдіть, де можуть бути ключі)

cr0x@server:~$ getent passwd | awk -F: '$6 ~ /^\/home\// {print $1 "\t" $6}'
alice	/home/alice
buildbot	/home/buildbot
deploy	/home/deploy

Значення: Ці користувачі ймовірно мають директорії ~/.ssh.
Рішення: Визначте зону аудиту ключів. Не забувайте про сервісні акаунти, як-от deploy — саме там «тимчасові» ключі живуть вічно.

Завдання 5 — Знайдіть кожен authorized_keys на хості (включно з дивними шляхами)

cr0x@server:~$ sudo find / -xdev -type f -name 'authorized_keys' -o -name 'authorized_keys2' 2>/dev/null
/home/alice/.ssh/authorized_keys
/home/deploy/.ssh/authorized_keys
/root/.ssh/authorized_keys

Значення: Локально існують три точки входу ключів.
Рішення: Якщо ви відкликаєте підрядника, перевірте всі з них. Root часто забувають і часто зловживають.

Завдання 6 — Порахуйте ключі і знайдіть очевидний дрейф (коментарі важливі)

cr0x@server:~$ sudo awk 'NF && $1 !~ /^#/ {print FILENAME ":" NR ":" $0}' /home/*/.ssh/authorized_keys /root/.ssh/authorized_keys | head -n 6
/home/alice/.ssh/authorized_keys:1:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... alice@laptop
/home/alice/.ssh/authorized_keys:2:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... old-admin
/home/deploy/.ssh/authorized_keys:1:command="/usr/local/bin/deploy-wrap" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... ci@runner
/root/.ssh/authorized_keys:1:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... breakglass@vault

Значення: У вас змішані алгоритми і принаймні один «old-admin» ключ. Також є ключ з примусовою командою для deploy.
Рішення: Розглядайте будь-який рядок без корисного коментаря як підозрілий і вимагайте перевидачі. Для ключів deploy перевірте, чи примусова команда робить те, що ви очікуєте.

Завдання 7 — Отримайте відбиток відомого шкідливого публічного ключа (щоб можна було надійно шукати)

cr0x@server:~$ ssh-keygen -lf /tmp/contractor_id_ed25519.pub
256 SHA256:Wm3xNq7nq0M9m+eOQmR0f0sY0p+9QH8Zq4xkYw1o9X8 contractor@mbp (ED25519)

Значення: Це стабільний відбиток, за яким ви можете шукати, коли коментарі брешуть.
Рішення: Використовуйте відбитки як канонічний ідентифікатор у тікетах і аудитах. Коментарі — підказки, а не ідентичність.

Завдання 8 — Знайдіть відбиток у всіх authorized_keys (знайдіть розростання)

cr0x@server:~$ sudo grep -R --line-number --fixed-strings 'AAAAC3NzaC1lZDI1NTE5AAAAI' /home/*/.ssh/authorized_keys /root/.ssh/authorized_keys
/home/alice/.ssh/authorized_keys:7:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... contractor@mbp
/root/.ssh/authorized_keys:4:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... contractor@mbp

Значення: Ключ існує в кількох місцях (включно з root).
Рішення: Відкличте в усіх локаціях і відкрийте супровідний інцидент: «Чому ключ підрядника опинився у root/authorized_keys?»

Завдання 9 — Акуратно видаліть ключ (точечне редагування, з веденням аудиту)

cr0x@server:~$ sudo cp -a /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bak.$(date +%F)
cr0x@server:~$ sudo sed -i '\#contractor@mbp#d' /root/.ssh/authorized_keys
cr0x@server:~$ sudo ssh-keygen -lf /root/.ssh/authorized_keys | head -n 3
256 SHA256:... breakglass@vault (ED25519)

Значення: Ви зробили резервну копію, прибрали рядок підрядника за відповідністю коментарю і перевірили, що залишені записи парсяться.
Рішення: Якщо коментарі ненадійні, видаляйте, збігаючись по підрядку ключа. Завжди тримайте датовану копію для судово-експертної та відкату.

Завдання 10 — Перезавантажте налаштування sshd (не рестартуйте, якщо можна уникнути)

cr0x@server:~$ sudo systemctl reload ssh
cr0x@server:~$ systemctl is-active ssh
active

Значення: Конфіг і файли ключів набрали чинності; sshd залишився активним.
Рішення: Віддавайте перевагу reload над restart, щоб не скидати з’єднання на завантажених бастіонах — якщо тільки ви не змінили щось, що вимагає рестарту (рідко).

Завдання 11 — Доведіть, що старий ключ відкидається (лог-докази на сервері)

cr0x@server:~$ sudo journalctl -u ssh -S "10 minutes ago" | tail -n 6
Dec 31 09:12:41 server sshd[22418]: Connection from 203.0.113.44 port 51221 on 10.0.0.10 port 22 rdomain ""
Dec 31 09:12:41 server sshd[22418]: Failed publickey for alice from 203.0.113.44 port 51221 ssh2: ED25519 SHA256:Wm3xNq7nq0M9m+eOQmR0f0sY0p+9QH8Zq4xkYw1o9X8
Dec 31 09:12:43 server sshd[22418]: Connection closed by authenticating user alice 203.0.113.44 port 51221 [preauth]

Значення: Точний відбиток зазнав невдачі. Це ваше підтвердження.
Рішення: Позначте ключ як відкликаний для цього хоста. Повторіть на інших хостах або — краще — автоматизуйте пошук по флоту, щоб не «довіряти вибірці».

Завдання 12 — Підтвердіть, який ключ клієнт пропонує (перестаньте тестувати не те)

cr0x@server:~$ ssh -vvv -i ~/.ssh/id_ed25519_new alice@server 2>&1 | egrep 'Offering public key|Server accepts key|Authentications that can continue'
debug1: Offering public key: /home/alice/.ssh/id_ed25519_new ED25519 SHA256:9aZkNf...
debug1: Authentications that can continue: publickey
debug1: Server accepts key: /home/alice/.ssh/id_ed25519_new ED25519 SHA256:9aZkNf...
debug1: Authentication succeeded (publickey).

Значення: Новий ключ використовується і приймається.
Рішення: Якщо все ще не працює, проблема, ймовірно, у серверних обмеженнях (command=, from=, principals, дозволи) або ви потрапляєте на інший хост/шлях.

Завдання 13 — Перелічіть активні SSH-сесії (відкликання не вбиває існуючі шелли)

cr0x@server:~$ who
alice    pts/1        2025-12-31 09:03 (203.0.113.44)
deploy   pts/2        2025-12-31 08:50 (10.0.2.15)

Значення: Користувачі мають активні сесії, які вже аутентифіковані.
Рішення: Якщо ключ було скомпрометовано, ймовірно, потрібно завершити сесії. Якщо це планова ротація, можна дозволити сесіям завершитись самостійно, щоб уникнути порушень.

Завдання 14 — Завершіть скомпрометовану сесію (обачно, з наміром)

cr0x@server:~$ ps -ft pts/1
UID        PID  PPID  C STIME TTY          TIME CMD
alice    22391 22388  0 09:03 pts/1    00:00:00 -bash
cr0x@server:~$ sudo kill -HUP 22391
cr0x@server:~$ ps -p 22391
  PID TTY          TIME CMD

Значення: Шелл вийшов і сесія зникла.
Рішення: Використовуйте цілеспрямовані kill, а не «перезапуск ssh». Перезапуск демона не обов’язково вбиває сесії і створює побічні наслідки.

Завдання 15 — Перевірте дозволи файлів (уникніть «працює на одному хості» нісенітниці)

cr0x@server:~$ sudo namei -l /home/alice/.ssh/authorized_keys
f: /home/alice/.ssh/authorized_keys
drwxr-xr-x root  root  /
drwxr-xr-x root  root  home
drwxr-x--- alice alice alice
drwx------ alice alice .ssh
-rw------- alice alice authorized_keys

Значення: Дозволи суворі; sshd має приймати файл.
Рішення: Якщо бачите директорії або файли з дозволами для групи/світу, виправте їх замість вимкнення StrictModes.

Завдання 16 — Виявлення повторного використання ключа між обліковими записами (один ключ — багато дверей)

cr0x@server:~$ sudo awk 'NF && $1 !~ /^#/ {print $2}' /home/*/.ssh/authorized_keys /root/.ssh/authorized_keys | sort | uniq -c | sort -nr | head
      2 AAAAC3NzaC1lZDI1NTE5AAAAI... 
      1 AAAAB3NzaC1yc2EAAAADAQABAAABAQ...

Значення: Одна бінарна копія ключа з’являється кілька разів по системі.
Рішення: Забороніть повторне використання ключів між обліковими записами. Воно руйнує атрибуцію і робить відкликання складнішим, ніж потрібно.

Завдання 17 — Перевірте використання ssh-agent forwarding (змінює модель загроз)

cr0x@server:~$ sudo grep -R --line-number 'ForwardAgent' /etc/ssh/ssh_config /etc/ssh/ssh_config.d 2>/dev/null
/etc/ssh/ssh_config.d/20-bastion.conf:3:    ForwardAgent yes

Значення: Для чогось (ймовірно бастіона) увімкнено пересилання агента.
Рішення: Якщо ви відкликаєте через компрометацію, вважайте пересилання агентів підозрілим. Розгляньте його відключення та використання сертифікатів або ProxyJump-патернів.

Завдання 18 — Перевірте конфіг sshd перед розгортанням (щоб не заблокувати себе)

cr0x@server:~$ sudo sshd -t
cr0x@server:~$ echo $?
0

Значення: Синтаксис конфігу коректний.
Рішення: Ніколи не робіть reload sshd в автоматизації без sshd -t. Єдине гірше за розростання ключів — це заблокувати відповідального on-call.

Стратегії відкликання, що реально працюють

Стратегія A: Сирі публічні ключі в authorized_keys (реальність за замовчуванням)

Це світ, у якому живуть більшість команд: файли authorized_keys розсіяні по хостах.
Відкликання тут — грубий інструмент: видалити ключ усюди, де він з’являється, включно зі спільними обліковими записами і root (якщо ви їх дозволяєте).
Завдання не в «видалити рядок». Завдання — «закрити всі двері, які відкривав цей рядок».

Якщо ви використовуєте сирі ключі, наполегливо дотримуйтесь таких політик:

  • Одна людина → один ключ для пристрою (лаптоп, робоча станція, CI-runner). Ніяких спільних ключів. Ніяких «командних ключів».
  • Кожен рядок ключа має бути атрибутований: коментар містить власника і призначення, а відбиток фіксується в IAM чи системі тікетів.
  • Кожен ключ має власника і дату рев’ю. Якщо ви не можете назвати власника — ви не можете виправдати ризик.
  • Ніяких ручних правок на «петах»: якщо хост важливий, ключі керуються конфігураційним менеджментом (або централізованою командою ключів).

Складність у дрейфі: ключі копіюються в місця, які ви не планували, ключі лишаються після деофбордингу, ключі впікаються в образи/AMI/контейнери. Ось чому інвентар має бути відтворюваним.

Стратегія B: Централізувати ключі з AuthorizedKeysCommand (добре для великих флотів)

За допомогою AuthorizedKeysCommand sshd виконує команду для отримання ключів під час логіну. Та команда може запитувати LDAP, локальний кеш,
менеджер секретів або простий файл, згенерований з джерела істини.

Операційна перевага: відкликання негайне і централізоване. Більше не виникає питання «ми оновили ту одну коробку?».

Операційний недолік: ви ввели залежність у шлях логіну. Якщо вона повільна, впала або некоректна — ніхто не залогіниться.

Якщо ви обираєте цей шлях, ставтесь до нього як до виробничого сервісу:

  • Кешуйте результати локально з TTL; захищайте дозволи кеша.
  • Майте аварійну статичну альтернативу (break-glass ключ у root, з жорстким контролем).
  • Інструментуйте та сповіщуйте про помилки і затримки команди.
  • Обмежуйте швидкість і зміцнюйте парсинг вводу. sshd буде запускати вашу команду часто.

Стратегія C: Перейти на OpenSSH користувацькі сертифікати (опція проти розростання)

Сертифікати — як припинити розростання ключів замість постійного кошення.
Користувачі все ще мають приватний ключ, але аутентифікуються з короткоживучим сертифікатом, підписаним вашим SSH CA.
Сервери довіряють CA, а не кожному окремому публічному ключу.

Що змінюється:

  • На серверах: ви раз або рідко розгортаєте публічний ключ CA. Це корінь довіри.
  • На клієнтах: користувачі отримують сертифікат (бажано короткоживучий) від сервісу підпису після SSO/MFA.
  • Відкликання: ви можете припинити видачу, скоротити TTL сертифікатів і (за потреби) використовувати списки відкликання ключів для конкретних сертифікатів.

Моя думка: Якщо у вас більше кількох серверів і ви ротаєте ключі частіше ніж раз на рік, сертифікати окупають себе.
Вони перетворюють відкликання з «полювання за рядками» на «припиніть видачу; дочекайтеся TTL».

Жорсткі налаштування sshd на Debian 13 після ротації

Проекти ротації — це подарунок: ви все одно торкаєтесь sshd, отже виправте структурні проблеми, що дозволили розростання.
Мета не «максимальна паранойя». Мета — передбачуваний контроль доступу.

Зробіть шляхи аутентифікації явними

Якщо ви ротували ключі через компрометацію або політику, розгляньте впровадження цієї політики в sshd, щоб ви не регресували непомітно.
Наприклад, відключіть парольну та keyboard-interactive автентифікацію, якщо ви ними справді не користуєтесь; інакше нападники просто скористаються іншою дверима.
Ви вже бачили в Завданні 3, як це перевірити.

Припиніть дозволяти випадковим обліковим записам ставати точками входу

Найшвидший шлях опинитись у пеклі розростання ключів — дозволяти великій кількості акаунтів приймати довільні ключі.
Віддавайте перевагу меншій кількості логін-акаунтів і використовуйте sudo з жорсткою політикою для привілеїв. Ще краще — персонифіковані акаунти й уникнення спільних облікових записів.
Коли уникнути спільного акаунта не можна (CI-runner, deploy), обмежуйте його:

  • Примусова команда для CI-ключів (як у Завданні 6).
  • Обмежуйте вихідні IP за допомогою from="10.0.2.15" у authorized_keys.
  • Вимикайте PTY, порт-форвардинг і X11-форвардинг для не-людського доступу.

Використовуйте Match-блоки для бастіонів і спеціальних користувачів

Не «ставте глобально і сподівайтесь». Бастіони — інші. CI-користувачі — інші. Root — інший.
OpenSSH Debian підтримує гранульовані правила Match. Вони читаються, коли тримаються короткими.

Break-glass не опціональний; він має бути контрольованим

Вам потрібен вхід, коли ваш сервіс ключів або розгортання конфига ламається. Але break-glass повинен бути:
рідко використовуваним, детально логованим і швидко ротованим.
Один ретельно збережений аварійний ключ краще за п’ять випадкових «на всякий випадок» ключів, розкиданих навколо.

Жарт №2: «Тимчасовий SSH-ключ» — найперманентніша річ в ІТ — аж поки не прийдуть аудитори й він миттєво не стане «неporозумінням».

Три корпоративні міні-історії (усі достатньо реальні, щоб боліти)

Інцидент через неправильне припущення: «Ми видалили ключ, отже він не може заходити»

Середня SaaS-компанія провела ротацію SSH-ключів після крадіжки лаптопа. Команда зробила очевидне: видалила скомпрометований публічний ключ з
authorized_keys інженера по production. Вони використовували конфігураційний менеджмент, зміни розгорнулись, і інцидент закрили в тікеті.

Через два дні підозрілий логін зачепив базу даних. Логи чітко показували публічну аутентифікацію зі старим відбитком.
Пішла паніка, як це зазвичай буває, і перша хвиля дій була передбачувана: рестарт sshd, ще одна ротація ключів і блокування IP.
Логін тривав з нових IP.

Насправді проблема була маленька і принизлива: хост бази даних не використовував персонифіковані ключі зовсім. Доступ здійснювався через легасі
спільний акаунт dbmaint, який жив поза конфігураційним менеджментом, бо його створили «для вендора роки тому».
Цей акаунт мав власний authorized_keys, і скомпрометований ключ був там також.

Неправильне припущення полягало в тому, що «видалення ключа з користувача» означає «видалення ключа з системи».
Ключі не цікавляться організаційними діаграмами. Їх цікавлять файли і шляхи довіри.

Виправлення не було героїчним: проінвентаризувати кожний authorized_keys на кожному хості, видалити відбиток по флоту і потім видалити
спільний акаунт повністю. Найкраща частина? Після прибирання майбутні відкликання стали нудними, бо у них з’явився повний список місць, де можуть існувати ключі.

Оптимізація, яка обернулась проти: «Прискоримо онбординг, копіюючи ключі скрізь»

Велика ентерпрайз-платформна команда мала проблему онбордингу: новим інженерам потрібен доступ до десятків хостів, а погодження займали час.
Хтось запропонував «просту оптимізацію»: скрипт, що додає публічний ключ новачка в шаблон /etc/skel
і в кілька спільних сервісних акаунтів, щоб доступ «просто працював».

Це спрацювало в короткостроковій перспективі. Час онбордингу зменшився. Менше тікетів. Усім сподобався скрипт.
Потім стався перший офбординг старшої інженерки, яка пішла в поганих стосунках.
Вони ротували її ключі. Видалили ключ із очевидних місць. Вона все ще мала доступ.

Скрипт створив розростання швидше, ніж будь-яка людина могла би. Ключі опинилися в домашніх каталогах, створених із /etc/skel, у спільних акаунтах
і в кількох випадкових «ops helper» облікових записах, які люди створювали роками. Ніхто не знав повного набору. Ніхто не мав наміру створювати паралельний IAM.
Але вони його створили.

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

Урок: оптимізувати швидкість онбордингу шляхом дублювання облікових даних — це як оптимізувати виникнення пожеж, складаючи бензин у коридорах.
Працює, поки вам не потрібно швидко щось зупинити.

Нудна але правильна практика, яка врятувала ситуацію: «Ми можемо довести, хто може зайти»

Інфраструктурна команда фінтеху керувала Debian-хостами з суворим правилом: ніяких ручних правок authorized_keys в продакшені. Ключі розгорталися
з Git-репозиторію через конфігураційний менеджмент. Кожен рядок ключа містив власника, призначення і дату рев’ю у коментарі.
Вони також записували відбитки у тікет доступу.

Одного дня спрацював алерт: повторні невдалі спроби SSH і потім успішний логін на бастіон. Успішний логін використовував відбиток ключа,
якого не було в їхньому репозиторії. Так не мало бути.

Ось де дисципліна нудних практик окупилась: вони не дебатували. Запустили пошук по флоту за тим відбитком. Він з’явився лише на бастіоні,
доданий вручну протягом останньої години. Мітка часу файлу і логи аудиту збіглися з людською помилкою: хтось вставив ключ вендора під час сесії підтримки.

Вони видалили ключ, перезавантажили sshd, вбили сесію, а потім порівняли authorized_keys бастіона з версією з конфігураційного менеджменту.
Дельта була точно одним рядком. Вони відновили файл з CM, відкрили інцидент процесу і посилили workflow підтримки.

Жодних драматичних форензик. Жодного тижневого «проекту аудиту ключів». Просто швидка ізоляція, бо система мала джерело істини і правило проти ад-хок змін.

Типові помилки (симптом → корінна причина → виправлення)

1) «Старий ключ досі працює» після ротації

Симптом: Відкликаний ключ продовжує аутентифікуватися на деяких хостах.

Корінна причина: Ключ існує в кількох акаунтах або джерелах ключів (спільні акаунти, root, альтернативні шляхи AuthorizedKeysFile, бастіони).

Виправлення: Отримайте відбиток ключа і шукайте по флоту всі authorized_keys (та будь-яке централізоване джерело). Видаліть усюди. Перевірте логи.

2) «Новий ключ не працює, але на іншому сервері працює»

Симптом: Той самий користувач, той самий ключ, але різний результат залежно від хоста.

Корінна причина: Проблеми з дозволами (StrictModes), різний конфіг sshd, різний шлях домашнього каталогу користувача або рядок ключа має обмеження (from=, command=), що не підходять.

Виправлення: Запустіть sshd -T на хості, де не працює, перевірте дозволи через namei -l і перевірте обмеження в рядку authorized_keys.

3) «Ми видалили ключ, але сесія залишилась активною»

Симптом: Користувач залишається підключеним і може продовжувати робити дії.

Корінна причина: Перевірка ключів відбувається під час аутентифікації; видалення ключів не розбалонить існуючі сесії.

Виправлення: Ідентифікуйте сесії за допомогою who / ss / ps і вибірково завершуйте їх, коли потрібно.

4) «Ми себе заблокували»

Симптом: Після reload/restart ніхто не може зайти.

Корінна причина: Поганий конфіг sshd, неправильний шлях AuthorizedKeysFile, поломка дозволів або надмірне відключення методів автентифікації без тестованого ключа.

Виправлення: Завжди запускайте sshd -t перед reload, тримайте аварійний консольний доступ і поступово розгортайте зміни з перевіркою.

5) «Підрядник деофбордований, але CI продовжує падати»

Симптом: Після чистки ключів автоматизовані job-и не можуть деплоїти.

Корінна причина: CI використовував персональний ключ підрядника (так, таке буває) або випадково було видалено ключ сервісного акаунта.

Виправлення: CI повинен мати власний виділений ключ/сертифікат з примусовою командою та обмеженнями. Тимчасово відновіть доступ сервісного акаунта, а потім реархітектуруйте.

6) «Ми відкликали ключ на хостах, але доступ все ще йде через бастіон»

Симптом: Прямий логін зазнає невдачі, але хоп через бастіон успішний.

Корінна причина: Ключ все ще дійсний на бастіоні, або пересилання агентів дозволяє використати інший ключ на кінцевому хості.

Виправлення: Відкличте на бастіоні першим, перегляньте налаштування пересилання агентів і вимагайте явного використання IdentityFile під час тестів інциденту.

7) «Аудит показує 400 ключів; у нас тільки 60 співробітників»

Симптом: authorized_keys забиті невідомими записами.

Корінна причина: Історичне накопичення: колишні співробітники, доступ вендорів, одноразове налагодження, копійовані образи і повторне використання ключів.

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

Контрольні списки / покроковий план

Фаза 0 — Визначте політику (одна сторінка, що застосовується)

  • Дозволені алгоритми (переважайте Ed25519; дозволяйте RSA тільки якщо його вимагають клієнти, яких ви можете назвати).
  • Правила власності ключів (ніяких спільних людських ключів; сервісні акаунти отримують виділені ключі).
  • Формат обов’язкових коментарів ключа (власник + призначення + опційно дата закінчення/рев’ю).
  • Де ключі зберігаються і керуються (репозиторій конфігураційного менеджменту або джерело AuthorizedKeysCommand).
  • Метод аварійного доступу (break-glass) і графік ротації.

Фаза 1 — Інвентаризація (те, що всі хочуть пропустити)

  • Перелічіть всі акаунти, здатні логінитися (люди і сервіси).
  • Перелічіть усі джерела ключів: шляхи AuthorizedKeysFile, root-ключі, спільні акаунти, будь-яка централізована команда ключів.
  • Екстрагуйте відбитки у таблицю інвентарю (відбиток → користувач → хост → файл → коментар рядка).
  • Позначте невідомі ключі і дублікати (та ж бінарна копія ключа у кількох акаунтах).

Фаза 2 — Ротація (впровадження нових ключів без збоїв доступу)

  • Видайте нові ключі/сертифікати користувачам і сервісам.
  • Розгорніть нові публічні ключі поруч зі старими тимчасово (якщо не було компрометації).
  • Проводьте контрольні тести: один користувач, один хост, явний -i і підтвердження в логах.
  • Розгортайте поступово: спочатку бастіон, потім цінні цілі, потім решта.

Фаза 3 — Відкликання (зробіть старі ключі непридатними і доведіть це)

  • Видаліть старі ключі по флоту, включно з бастіонами і спільними акаунтами.
  • Переопитуйте sshd після валідації.
  • Під час компрометації: завершіть активні сесії, автентифіковані відкликаними обліковими даними, коли це доцільно.
  • Зберіть докази: рядки логів з відхиленими спробами publickey з відкликаним відбитком після змін.

Фаза 4 — Запобігання повторному росту (зупиніть розростання на джерелі)

  • Забороніть ручні правки на продакшені; забезпечте це через конфігураційний менеджмент і моніторинг цілісності файлів.
  • Зменшіть кількість акаунтів, яким дозволено SSH-логіни.
  • Застосуйте обмеження до сервісних ключів (примусові команди, без пересилання, обмеження по IP).
  • Прийміть сертифікати або централізований lookup ключів, якщо розмір флоту це виправдовує.
  • Заплануйте регулярні аудити (щомісяця/щокварталу) і зв’яжіть їх з офбордингом.

Поширені запитання

1) Якщо ми видалимо ключ з authorized_keys, це одразу відкликає його?

Для нових підключень — так. Для існуючих сесій — ні. SSH не перевіряє authorized_keys під час сесії. Якщо ключ було скомпрометовано, навмисно завершіть сесії.

2) Який єдиний найкращий спосіб уникнути розростання ключів?

Припиніть використовувати authorized_keys як дошку для нотаток. Використовуйте джерело істини (конфігураційний менеджмент або централізований lookup) і забороніть ручні правки на продакшені.
Якщо можете — використовуйте короткоживучі OpenSSH сертифікати.

3) Навіщо нам потрібні відбитки, якщо вже є коментарі?

Бо коментарі брешуть, копіюються або зникають. Відбитки ідентифікують реальний матеріал ключа. В інцидентах ваш аудит має посилатися на відбитки.

4) Ми ротували ключі, але користувачі все ще аутентифікуються старим ключем через агент. Чому?

Клієнт SSH може автоматично пропонувати кілька ключів. Використовуйте ssh -vvv -i, щоб нав’язати потрібний ключ під час тестів, і встановіть правила ідентичності per-host в конфігурації SSH.

5) Чи варто відключити прямий root SSH-прихід під час або після ротації?

Якщо можете — так: відключіть прямий логін root і вимагайте sudo з іменованих акаунтів. Якщо треба зберегти — сильно обмежте і ставтеся до root/authorized_keys як до священного.

6) Чи безпечно використовувати AuthorizedKeysCommand в продакшені?

Може бути, якщо ви ставитесь до цього як до залежності: кеш, моніторинг і аварійний break-glass. Якщо ваша організація не може надійно управляти невеликими сервісами, тримайтеся файлів з CM.

7) Як відкликати доступ вендора, який користувався спільним акаунтом?

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

8) Як довести аудиторам, що ключ відкликано?

Покажіть: (1) відбиток ключа, (2) докази його видалення з джерел, і (3) лог-докази відхилених спроб аутентифікації з тим відбитком після зміни, на репрезентативних хостах або по флоту, якщо можливо.

9) Що робити з ключами, впеченими в образи або контейнери?

Якщо образ містить authorized_keys-дані, ви будете постійно реанімувати відкликані ключі. Проскануйте образи, виправте пайплайн збірки і анулюйте старі образи.
Іншими словами: припиніть доставки облікових даних як артефактів.

10) Чи потрібно ротувати хост-ключі також?

Це інша проблема. Ротація користувацьких ключів відкликає доступ користувача; ротація хост-ключів змінює ідентичність сервера і впливає на довіру known_hosts.
Ротуйте хост-ключі при компрометації або політиці, але плануйте оновлення довіри клієнтів.

Наступні кроки, які можна зробити цього тижня

Якщо хочете, щоб ротація пройшла і закріпилась, зробіть три речі в наступні сім днів:

  1. Сформуйте інвентар відбитків з кожного authorized_keys на репрезентативній вибірці хостів. Ви знайдете сюрпризи. Це і є суть.
  2. Оберіть механізм відкликання, який ви зможете експлуатувати: конфігураційно керовані authorized_keys, AuthorizedKeysCommand з кешуванням або (найкраще) короткоживучі сертифікати.
  3. Опишіть правило «ніяких ручних правок» і впровадьте його, починаючи з бастіонів і продакшену. Дрейф — це шлях, яким сьогоднішні ключі стають завтрашніми інцидентами.

Ротація ключів — це не церемонія. Це зміна контролю доступу з вимірюваними результатами: старі ключі не проходять, нові — проходять, і є паперовий слід, який ви готові читати о 3 ранку.
Зробіть це один раз, зробіть це чисто, а потім спроєктуйте систему так, щоб вам не доводилось заново вчити той самий урок кожного кварталу.

← Попередня
Proxmox Ceph HEALTH_WARN: з чого почати безпечне усунення несправностей
Наступна →
ZFS SLOG: коли лог-пристрій допомагає, коли марний, коли небезпечний

Залишити коментар