Перейти к содержанию

Пользователи, группы и sudo

Каждый файл, процесс и сокет в Linux принадлежит числовому ID пользователя и ID группы. Имена вроде alice или docker — только метки, которые ищутся в базе. Понимание этой базы и того, как sudo решает, кому можно действовать от имени root, лежит в основе прав доступа, SSH, служебных учётных записей и почти любой ошибки «permission denied».

О выводе на этой странице

Вывод id, stat, visudo -V и getent снят на Ubuntu 22.04 (sudo 1.9.9). Вывод команд, изменяющих учётные записи (useradd, usermod, gpasswd), приведён как пример с выдуманным пользователем alice: этим командам нужен root, и для статьи они не запускались.

Как это устроено

Идентичность — это число

Ядро знает только ID пользователя (UID) и ID групп (GID). id показывает их все для текущей сессии:

$ id
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),128(docker)
  • uid=1000(alice) — пользователь. UID 0 — это root, единственный UID, который ядро считает привилегированным.
  • gid=1000(alice) — основная группа. Новые файлы получают эту группу.
  • groups=... — дополнительные группы. Доступ разрешён, если совпала любая из них.

По соглашению UID ниже 1000 (порог — UID_MIN в /etc/login.defs) принадлежат системным и служебным учётным записям, а обычные люди начинаются с 1000.

Где хранятся учётные записи

Файл Содержимое Обычные права
/etc/passwd Строка на пользователя: name:x:UID:GID:comment:home:shell -rw-r--r-- (читается всеми)
/etc/shadow Хеши паролей и поля срока действия -rw-r----- root:shadow
/etc/group Группы и их участники -rw-r--r--
/etc/sudoers, /etc/sudoers.d/* Кто какие команды может запускать через sudo -r--r----- root:root

Символ x в поле пароля /etc/passwd означает «хеш лежит в /etc/shadow». Разделение нужно потому, что /etc/passwd должен читаться всеми (программы сопоставляют UID с именами), а хеши — нет.

Не разбирайте эти файлы вручную в скриптах. Используйте getent: он идёт по той же цепочке поиска, что и остальная система (/etc/nsswitch.conf), и поэтому находит также пользователей из LDAP, SSSD и других источников:

getent passwd alice      # alice:x:1000:1000:Alice:/home/alice:/bin/bash
getent group sudo        # sudo:x:27:alice

Создание пользователей и управление группами

sudo useradd -m -s /bin/bash alice        # -m создаёт /home/alice, -s задаёт оболочку входа
sudo passwd alice                         # задать пароль интерактивно
sudo usermod -aG docker alice             # ДОБАВИТЬ alice в группу docker
sudo gpasswd -d alice docker              # убрать alice из docker

Ключ -a в usermod -aG важен: он значит append (добавить). См. предупреждение ниже.

В Debian и Ubuntu adduser alice — более удобная обёртка: она запрашивает пароль и копирует файлы из skeleton; useradd — низкоуровневый инструмент, доступный в любом дистрибутиве.

Изменение групп не применяется к уже открытым сессиям. Процесс получает список групп при входе, поэтому alice должна выйти и войти снова (или запустить новую оболочку через newgrp docker), чтобы новая группа заработала. id в старой сессии по-прежнему показывает старый список. Это обычная причина ситуации «добавил себя в группу, а доступа всё равно нет».

Как sudo принимает решение

sudo — программа с setuid-root (-rwsr-xr-x root:root /usr/bin/sudo). Когда вы запускаете sudo command, она читает правила sudoers, проверяет, разрешено ли вашему пользователю или одной из ваших групп запускать эту команду от целевого пользователя, спрашивает ваш собственный пароль (не root), если правило не говорит иное, и запускает команду.

Правило sudoers выглядит так:

кто   где=(от_кого)   что
alice ALL=(ALL:ALL)   ALL
%sudo ALL=(ALL:ALL)   ALL

Первая строка читается так: пользователь alice на любом хосте (ALL) может запускать любые команды от любого пользователя и группы. Знак % в начале означает группу, поэтому вторая строка даёт те же права всем участникам группы sudo. В этом весь механизм «добавьте пользователя в группу sudo»:

  • Debian и Ubuntu поставляют %sudo ALL=(ALL:ALL) ALL в /etc/sudoers.
  • В RHEL-подобных системах то же правило задано для группы wheel.

Узкие правила лучше, чем ALL:

# /etc/sudoers.d/deploy
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/systemctl status myapp

Всегда редактируйте через visudo, а не обычным редактором: он блокирует файл и проверяет синтаксис перед сохранением. Для drop-in файла: sudo visudo -f /etc/sudoers.d/deploy. Проверка без редактирования:

$ sudo visudo -c
/etc/sudoers: parsed OK
/etc/sudoers.d/deploy: parsed OK

Что разрешено пользователю, смотрите через sudo -l (для себя) или sudo -l -U alice (от root).

Различия Ubuntu/Debian и RHEL-подобных систем

Ubuntu/Debian RHEL-подобные
Группа администраторов sudo wheel
Удобный инструмент adduser / deluser только useradd / userdel
Учётная запись root В Ubuntu по умолчанию заблокирована (используйте sudo -i); Debian при установке запрашивает пароль root, если его не оставили пустым Пароль root обычно задаётся при установке
Права домашнего каталога /home/user — 0750 в свежих Ubuntu 0700

Поэтому добавление в группу администраторов выглядит как usermod -aG sudo alice в Debian/Ubuntu и usermod -aG wheel alice в RHEL-подобных системах.

Практическое задание

Выполняйте на одноразовой виртуальной машине, а не на рабочем сервере.

  1. Создайте пользователя и посмотрите записи:
    sudo useradd -m -s /bin/bash lab1
    getent passwd lab1
    sudo getent shadow lab1        # поле хеша: ! или * или $y$... в зависимости от состояния
    id lab1
    
  2. Добавьте lab1 в группу и проверьте:
    sudo groupadd labgroup
    sudo usermod -aG labgroup lab1
    id lab1
    
  3. Дайте lab1 узкое правило sudo, проверьте синтаксис и протестируйте:
    echo 'lab1 ALL=(root) NOPASSWD: /usr/bin/id' | sudo tee /etc/sudoers.d/lab1
    sudo chmod 0440 /etc/sudoers.d/lab1
    sudo visudo -c
    sudo -l -U lab1
    sudo -u lab1 sudo -n id        # запускает id от root, без пароля
    sudo -u lab1 sudo -n ls /root  # должно быть отказано
    
  4. Очистка:
    sudo rm /etc/sudoers.d/lab1
    sudo userdel -r lab1           # -r удаляет также /home/lab1 и почтовый ящик
    sudo groupdel labgroup
    

Как проверить, что всё сделано правильно

  • Шаг 1: id lab1 показывает uid=<n>(lab1) gid=<n>(lab1) groups=<n>(lab1), где <n> не меньше 1000.
  • Шаг 2: id lab1 теперь содержит labgroup в groups=.
  • Шаг 3: visudo -c печатает parsed OK для нового файла; sudo -u lab1 sudo -n id печатает uid=0(root)...; попытка ls /root завершается sudo: a password is required (правило покрывает только id, а -n запрещает запрос пароля).
  • Шаг 4: getent passwd lab1 и ls /etc/sudoers.d/lab1 ничего не находят.

Типичные ошибки

  • Забыть, что смена групп требует нового входа. Работающая сессия хранит старый список групп.
  • Легко выдавать членство в группе docker. Любой участник docker может запустить контейнер с монтированием / и менять его от root, то есть группа равна root. Относитесь к ней как к sudo.
  • Терять окружение в sudo. sudo по замыслу сбрасывает большинство переменных окружения; если команде нужна переменная, передайте её явно (sudo VAR=value cmd), а не отключайте env_reset.
  • Неверные права у drop-in файла sudoers. Файлы в /etc/sudoers.d/ не должны быть доступны на запись группе или остальным (используйте 0440), иначе sudo их игнорирует или отвергает.
  • Точка или тильда в имени файла в /etc/sudoers.d/. Механизм include пропускает файлы с . в имени и заканчивающиеся на ~, поэтому deploy.conf может молча ничего не делать.

⚠ Опасные команды

  • usermod -G docker alice (без -a) заменяет все дополнительные группы. Если alice была в sudo, она только что потеряла права администратора; если это была единственная административная учётная запись, вы можете остаться без привилегированного доступа. Всегда используйте -aG.
  • Редактирование /etc/sudoers напрямую через nano/vim. Одна синтаксическая ошибка — и sudo перестаёт работать у всех. Всегда visudo; при смене правил держите открытым root-шелл в другом терминале.
  • NOPASSWD: ALL для человека или любое правило, разрешающее оболочку, редактор или less (они запускают шелл): это неограниченный root без запроса пароля. Разрешайте точные команды.
  • userdel -r удаляет домашний каталог без возможности отмены. Сначала сделайте резервную копию и убедитесь, что у учётной записи нет работающих процессов (pgrep -u alice).
  • Удаление или перенумерация UID 0 и системных учётных записей. Не меняйте UID существующего пользователя, не исправив владельца всех его файлов (find / -xdev -uid <старый> -exec chown ...).

Связанные статьи

Контрольные вопросы

  1. Что на самом деле использует ядро для решения о доступе — имена или числа? Откуда берутся имена?
  2. Почему usermod -G без -a может оставить вас без доступа?
  3. Вы добавили пользователя в группу, но id в его открытом терминале её не показывает. Почему?
  4. Какая команда проверяет синтаксис sudoers, пока он не сломал sudo у всех?
  5. Почему членство в группе docker фактически равно доступу root?