Антипаттерн: общий root-пароль на всю команду
Новый сервер, три разработчика, один пароль root в закреплённом сообщении в чате — знакомая картина почти в каждой команде на старте. Работает это ровно до первого инцидента: сервис упал, конфиг кто-то поправил вручную, а в логах — только root, и непонятно, кто именно. Разбираем, почему общий root-пароль — это техдолг с процентами, и что сделать вместо него за один вечер.
Содержание
- Как выглядит "общий root" в реальности
- Проблема #1: невозможность аудита — кто это сделал
- Проблема #2: увольнение сотрудника — пароль знает весь мир
- Проблема #3: пароль неизбежно расшаривается небезопасными способами
- Проблема #4: нельзя разграничить привилегии
- Как сделать правильно: именные учётки и sudo
- Централизованное управление ключами и доступом
Как выглядит "общий root" в реальности
Схема почти всегда одна и та же: на новом VPS создаётся пароль для root, он кладётся в закреплённое сообщение Telegram, в общий файл passwords.txt в репозитории или в заметку в Notion. Дальше все — от тимлида до стажёра на испытательном сроке — заходят на сервер одной и той же командой:
ssh root@203.0.113.10
Поначалу это действительно удобно: не нужно заводить пользователей, разбираться с sudo, настраивать ключи каждому. Работает — и ладно. Проблема в том, что удобство линейно падает с ростом команды и количества серверов, а риски растут нелинейно: чем дольше живёт общий пароль, тем больше людей его видели, тем больше копий разошлось по чатам и файлам, и тем дороже становится его сменить.
Дальше по пунктам — что именно ломается в этой схеме и почему временное решение почти никогда не заменяют вовремя.
Проблема #1: невозможность аудита — кто это сделал
Это главная причина, по которой общий root — не просто "не best practice", а конкретная операционная дыра. Когда все заходят под одной учёткой, у вас физически нет данных, чтобы ответить на вопрос "кто внёс это изменение".
Смотрим на практике. Команда last показывает историю входов:
last -a | head -20
root pts/0 Mon Aug 24 09:12 still logged in 203.0.113.55
root pts/1 Mon Aug 24 08:40 - 08:55 (00:15) 198.51.100.12
root pts/0 Sun Aug 23 22:03 - 22:40 (00:37) 203.0.113.55
Вы видите три сессии под root с разных IP — и всё. Кто из команды сидел за 198.51.100.12 в 8:40 утра в понедельник? Файл /var/log/auth.log (Debian/Ubuntu) или /var/log/secure (RHEL/AlmaLinux) тоже пишет Accepted password for root from 198.51.100.12 — имя человека там взяться неоткуда, потому что человека как сущности в системе просто нет, есть только учётка root.
То же самое с sudo-логами, если бы sudo вообще использовался: команда sudo -l и записи в /var/log/auth.log привязаны к конкретному пользователю системы. Под общим root этот механизм не работает вообще — root и так может всё, sudo ему не нужен, а значит и логировать нечего.
Итог: если ночью упал прод из-за случайно выполненной команды вроде rm -rf не в той директории или неудачного systemctl restart на боевом сервисе — разбор инцидента упирается в стену. У вас есть факт (что произошло), но нет субъекта (кто это сделал). А без субъекта нельзя ни поговорить с человеком, ни понять, было ли это ошибкой доступа, невнимательностью или чем-то, что нужно исправить в процессе.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПроблема #2: увольнение сотрудника — пароль знает весь мир
Второй удар приходит на отзыве доступа. С именными учётками увольнение сотрудника — рутинная операция: userdel, удаление ключа из authorized_keys, готово. С общим root всё иначе — вы не можете отозвать доступ одному человеку, потому что доступ не привязан к человеку. Единственный способ — сменить пароль root на всех серверах, куда он был выдан.
На практике это означает:
- зайти на каждый сервер, где стоял этот пароль (а их обычно больше, чем кажется — тестовый стенд, staging, пара забытых VPS для экспериментов);
- сменить пароль на каждом;
- разослать новый пароль всем оставшимся членам команды тем же небезопасным способом, которым расшаривали старый;
- понадеяться, что уволенный сотрудник не успел где-то этот пароль сохранить или что бывший коллега случайно не перешлёт новый пароль в старый чат по привычке.
Мы разбирали похожий случай, где доступ уволенного сотрудника не отозвали вовремя — там доступ хотя бы был именным и его можно было отозвать точечно, просто забыли это сделать. С общим root ситуация хуже вдвойне: точечно отозвать нечего в принципе, только сменить всё и для всех. На практике это откладывают, а значит бывший сотрудник ещё долго технически может зайти на сервер — просто потому, что "сменить пароль везде" звучит как отдельная задача на день, а не операция в один клик.
Проблема #3: пароль неизбежно расшаривается небезопасными способами
Пароль, которым пользуется больше одного человека, обязан где-то храниться в доступном виде — иначе им нельзя поделиться. И почти всегда этим местом становится что-то из списка:
- закреплённое сообщение в Telegram или Slack (история чата = история пароля, доступна всем, кто когда-либо был в этом чате, включая ботов-интеграторов);
- файл
passwords.txt,.envилиserver-access.mdв репозитории — иногда в приватном, иногда, по ошибке, в публичном; - заметка в Notion/Google Docs с доступом "у всех, у кого есть ссылка";
- личные заметки в блокноте телефона, скриншоты.
Каждый такой канал — это отдельная точка утечки, причём утечка может произойти не по злому умыслу, а просто по невнимательности: репозиторий форкнули для нового проекта и забыли вычистить историю, скриншот с паролем попал в бэкап телефона в облаке, сообщение переслали не в тот чат. Секреты, случайно попавшие в публичный репозиторий, боты-сканеры GitHub забирают за считаные минуты — этого достаточно, чтобы начать ими пользоваться.
Дополнительная проблема: root по паролю (а не по SSH-ключу) означает, что сервер уязвим и к перебору снаружи. Если вдобавок к общему паролю ещё и разрешён вход по паролю через SSH (PasswordAuthentication yes) — это открытая дверь для брутфорса ботами, которые круглосуточно сканируют интернет на предмет root:пароль. Даже сложный пароль здесь не панацея: длина пароля защищает от подбора, но не спасает, если сама модель доступа — один секрет, известный многим, передаваемый открытым текстом — в принципе не рассчитана на конфиденциальность.
Проблема #4: нельзя разграничить привилегии
У root нет промежуточных уровней — это либо полный доступ ко всей системе, либо ничего. А в реальной команде люди делают на сервере разные вещи:
| Роль | Что реально нужно | Что даёт общий root |
|---|---|---|
| Frontend-разработчик | Посмотреть логи своего сервиса, перезапустить его контейнер | Полный доступ: удалить любой файл, остановить базу, поменять firewall |
| DevOps/SRE | Полный административный доступ, работа с системными сервисами | То же самое (тут действительно совпадает) |
| Стажёр/подрядчик на пилотной задаче | Доступ к одной директории проекта на чтение-запись | Root на всём сервере, включая чужие проекты и секреты |
| Внешний аудитор безопасности | Временный доступ на просмотр конфигов и логов, без права менять | Постоянный root-пароль, который потом никто не думает отзывать |
Когда у всех одинаковый максимальный уровень доступа, любая ошибка масштабируется до максимума. Стажёр, который перепутал сервер и выполнил команду не на staging, а на проде, с общим root получает точно такие же последствия, как если бы это сделал ведущий инженер намеренно. Разграничение привилегий — это не бюрократия, а способ ограничить радиус поражения одной ошибки одним человеком.
Как сделать правильно: именные учётки и sudo
Базовая альтернатива требует минимум усилий и решает три проблемы выше сразу — заводится не общий root, а отдельный системный пользователь на каждого человека:
adduser ivan
usermod -aG sudo ivan # Debian/Ubuntu
usermod -aG wheel ivan # RHEL/AlmaLinux
Дальше — SSH-ключ вместо пароля, отдельно на каждого:
mkdir -p /home/ivan/.ssh
echo "ssh-ed25519 AAAA... ivan@laptop" >> /home/ivan/.ssh/authorized_keys
chown -R ivan:ivan /home/ivan/.ssh
chmod 700 /home/ivan/.ssh
chmod 600 /home/ivan/.ssh/authorized_keys
И запрет прямого входа под root вместе с паролями по SSH в /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
Как настроить это с нуля пошагово (генерация ключей, копирование на сервер, типичные ошибки с правами на .ssh) — отдельно разобрано в статье про SSH-ключи вместо пароля на сервере.
После этого у каждого человека — своя учётка, свой ключ, своя история команд, и sudo вместо root даёт нужную гранулярность. Не всем в группе sudo обязательно давать право на все команды без ограничений: через visudo и файлы в /etc/sudoers.d/ можно выдать доступ точечно — например, разрешить перезапускать только конкретный сервис:
# /etc/sudoers.d/ivan-deploy
ivan ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/systemctl status myapp
Теперь sudo логирует каждую команду с привязкой к пользователю — sudo -l покажет, что именно разрешено конкретному человеку, а /var/log/auth.log зафиксирует, кто и когда выполнил sudo systemctl restart myapp. Аудит, которого не было под общим root, появляется бесплатно как побочный эффект правильной модели доступа. Про то, как выстроить это на уровне процесса, а не только команд в консоли — какие роли заводить, что фиксировать в регламенте доступа — мы подробно разбирали в статье как раздать доступ команде без выдачи root. Общий подход к тому, почему "всё под root" вредно даже без вопроса общего пароля — в статье про антипаттерн работы всей команды под root.
Централизованное управление ключами и доступом
Ручное управление пользователями и ключами работает, пока серверов немного — условно, до пяти-десяти. Дальше поддерживать список "у кого какой доступ на каком сервере" вручную становится утомительно и ненадёжно: кто-то уволился, а его ключ остался на трёх серверах из двенадцати, потому что про них забыли.
Практические варианты в порядке роста сложности:
Ansible-плейбук с описанием доступа как кода. Список пользователей и их публичных ключей хранится в git (в приватном репозитории, не путать с паролями в открытом виде — ключ публичный и сам по себе не секрет). Один плейбук раскатывает нужный набор пользователей на все серверы сразу, а отзыв доступа — это удаление строки и повторный прогон:
- name: Sync team access
hosts: all
tasks:
- name: Ensure user exists
user:
name: "{{ item.name }}"
groups: sudo
shell: /bin/bash
loop: "{{ team_members }}"
- name: Deploy SSH key
authorized_key:
user: "{{ item.name }}"
key: "{{ item.ssh_key }}"
loop: "{{ team_members }}"
Централизованная идентификация (LDAP/FreeIPA + SSSD). Пользователи и группы заводятся один раз в центральной директории, а не на каждом сервере отдельно — серверы просто подключены к ней через SSSD. Уволили человека — удалили в одном месте, доступ пропал везде одновременно. Оправдано от нескольких десятков серверов и постоянной команды.
Bastion-хост / SSH Certificate Authority (например, step-ca) или готовые PAM-решения (Teleport, HashiCorp Boundary). Вместо статичных ключей в authorized_keys выдаются короткоживущие сертификаты на сессию — доступ автоматически "протухает" сам, плюс из коробки есть запись сессий и централизованные логи. Дороже в настройке, но снимает саму задачу "не забыть отозвать ключ на всех серверах" — это особенно ценно, если в команде есть подрядчики с временным доступом.
Что бы вы ни выбрали, ключевой принцип один: доступ должен выдаваться и отзываться в одном месте, а не путём ручного обхода списка серверов по памяти. Именно ручной обход — та самая причина, по которой доступ уволенного сотрудника остаётся живым неделями, а иногда и месяцами после ухода — не потому что про безопасность забыли принципиально, а потому что процесс отзыва требовал ручных действий на каждом сервере, и один из них пропустили.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
У нас команда из двух человек, это правда критично?
Критичность растёт со временем, а не только с числом людей. Даже вдвоём вы теряете аудит "кто это сделал" и рискуете паролём, лежащим в чате. Настройка именных учёток на двух-трёх серверах занимает 15–20 минут — дешевле, чем разбираться в инциденте без логов.
Можно ли просто сменить общий root-пароль на длинный и сложный, ничего не переделывая?
Это снизит риск подбора пароля снаружи, но не решит ни одну из проблем аудита и разграничения — пароль всё равно общий, и внутри команды по-прежнему не видно, кто что сделал. Длина пароля защищает от брутфорса, а не от отсутствия учёта пользователей.
Что делать, если общий root уже используется на десятке серверов и переделывать страшно?
Начните с одного некритичного сервера — заведите себе и одному коллеге именные учётки, проверьте, что sudo и вход по ключу работают, и только потом раскатывайте на остальные, лучше через Ansible-плейбук, чтобы не повторять действия руками на каждом.
Обязательно ли полностью отключать root по SSH?
Да, для входа по паролю или напрямую — PermitRootLogin no закрывает основной вектор перебора. При необходимости выполнить что-то от root используется sudo из именной учётки, что оставляет запись, кто и когда это сделал.
А если нужен экстренный доступ, когда единственный админ недоступен?
Это отдельная задача аварийного доступа (break-glass), а не повод возвращаться к общему паролю на каждый день. Обычно решается запечатанным паролем root в сейфе или менеджере паролей с журналом доступа, который вскрывается только в экстренной ситуации и обязательно меняется после использования.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →