Сервер когда-то собирал другой человек: заложил архитектуру, настроил прокси, раннеры, свои образы Docker. Потом он перестал с нами работать — а на сервере остались его ключ, учётка, права и, что неприятнее всего, зависимость от его личного реестра: образы, из которых поднимались все сайты, скачивались оттуда. Вот что пришлось проверить и что сделать.
Это четвёртая часть цикла «Общий сервер: безопасность и восстановление».
1. Ключи: искать не только у его учётки
Первое, что приходит в голову, — заблокировать его пользователя. Но ключ человека может стоять и в authorized_keys других учёток: когда-то добавили «чтобы помочь настроить» и забыли. У нас его ключ нашёлся в файле ключей моей собственной учётки. Блокировка его пользователя ничего бы не дала: он входил бы под моим именем.
# все ключи на сервере с комментариями (комментарий обычно = кто и с какой машины)
sudo sh -c 'for f in /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys; do
[ -f "$f" ] && awk -v f="$f" "{print f\": \"\$NF}" "$f"; done'
Удаляем ключ, сохранив копию файла, — и сразу проверяем свой вход в новой сессии, не закрывая текущую. Если по ошибке удалили свой ключ, текущая сессия — единственный способ это исправить.
2. Учётка: заблокировать, а не удалить
Удалять пользователя сразу не стоит: ему принадлежат файлы — конфиги прокси, часть сайтов, служебные папки. После удаления вместо имени владельца появится номер, и при следующем создании пользователя с тем же номером файлы перейдут к новому человеку. Блокировка делает то же, что нужно, и обратима:
usermod -L -e 1 -s /sbin/nologin <имя> # пароль заблокирован, срок учётки истёк, оболочки нет
gpasswd -d <имя> wheel # без sudo
gpasswd -d <имя> docker # без docker — это важнее, чем кажется (ниже)
mv /home/<имя>/.ssh/authorized_keys /home/<имя>/.ssh/authorized_keys.disabled-$(date +%Y%m%d)
Проверка: в /etc/shadow у пароля восклицательный знак, срок учётки — день 1 (1 января 1970 года, то есть давно истёк), в группах нет wheel и docker, файла ключей нет. И ps -u <имя> — нет ли запущенных от него процессов.
Группа docker — это root. Кто может запускать контейнеры, тот может смонтировать в контейнер корень хоста и сделать с ним что угодно, без всякого sudo. Снять человека из wheel и оставить в docker — то же самое, что оставить sudo.
3. Образы из чужого реестра — мина замедленного действия
Самое неочевидное. Образ nginx, на котором стоят все сайты, и образ раннера CI собирал тот человек, и лежат они в его личном реестре в GitLab. В docker-compose.yml каждого сайта написано что-то вроде:
services:
nginx:
image: registry.gitlab.com/<его-аккаунт>/docker/nginx:latest
Пока образы скачаны, всё работает. Но дальше два сценария, и оба плохие:
- реестр удалят — при следующем
docker compose pullили пересоздании контейнера на новом сервере сайты просто не поднимутся; - образ перезальют под тем же тегом — и к вам приедет чужой код, который вы не проверяли, с доступом ко всем файлам сайтов.
Что делать — перенести образы к себе, пока они есть:
- найти все ссылки:
grep -rn "registry.gitlab.com/<аккаунт>" /server --include=docker-compose.yml; - сохранить уже скачанные образы (это ровно то, что сейчас работает):
docker save, и заодно убедиться, что они есть в резервной копии; - перевесить тег и залить в свой реестр:
docker tag <старое> registry.example.com/our/nginx:1.21 && docker push …; - заменить ссылки в compose — сначала на тестовом сервере, с проверкой, что всё поднимается из нового реестра;
- положить Dockerfile этих образов в свой git, чтобы в следующий раз не восстанавливать их по слоям;
- перестать использовать
:latest: конкретная версия или дайджест образа.
4. Что ещё проверить
- токены и пароли, которые он знал: доступы к хостингу, DNS, реестру, базам, SMTP. Не всё это лежит на сервере — составьте список по памяти и по менеджеру паролей;
- раннеры CI, зарегистрированные на его аккаунт: если GitLab-аккаунт человека удалят, удалятся и его раннеры. Перерегистрируйте их на свой;
- крон и таймеры под его пользователем:
crontab -l -u <имя>,ls /var/spool/cron; - webhooks и интеграции в GitLab и мессенджерах, которые указывают на его серверы или ботов;
- кому ещё на сервере доступна учётка: список всех пользователей с оболочкой — пройтись и про каждого ответить, чей он.
Это не про недоверие к конкретному человеку. Через год никто уже не вспомнит, чей это ключ и зачем он здесь. Уход подрядчика — единственный момент, когда это ещё можно восстановить по памяти. Хорошая практика — делать такую ревизию и при уходе своих сотрудников.
От вас ушёл подрядчик, который настраивал сервер?
Помогу пройти по доступам, ключам и зависимостям и закрыть всё, что осталось, ничего не сломав.
// загружаю комментарии…