Learning Platform
Глоссарий Troubleshooting
Урок 07.01 · 22 мин
Начальный
UsersGroupsUIDGID/etc/passwd/etc/shadowuseraddadduser

Зачем DE знать про users и groups

Когда твой Airflow DAG падает с PermissionError: [Errno 13] Permission denied: '/var/log/airflow/dag_processor.log', первое что нужно понять — под каким пользователем работает Airflow scheduler и в какие группы этот пользователь входит. То же самое для chown-конфликтов при копировании файлов из S3, для прав на ~/.ssh/id_rsa, для sudo-проверок на CI runner.

Linux — multi-user OS с самого UNIX-а 1969 года. Каждый процесс, каждый файл, каждый сокет принадлежит какому-то пользователю и какой-то группе. Без этой модели нельзя разделять права, нельзя изолировать сервисы, нельзя ограничить rm -rf / от непривилегированного юзера.

UID: пользователь — это число

Когда ты делаешь whoami и видишь airflow, это имя. А для kernel пользователь — это число, UID (User ID). 32-битное беззнаковое целое, 0 до 4294967295. Имя airflow — это просто строка в /etc/passwd, которая мапит UID на читаемое для человека name.

$ id
uid=1000(levo) gid=1000(levo) groups=1000(levo),27(sudo),100(users),999(docker)

uid=1000 — это твой реальный идентификатор. Когда процесс делает open("/etc/shadow", O_RDONLY), kernel сравнивает не имя levo, а число 1000 с тем, что записано в inode файла. Имена нужны только людям — ядру они не интересны.

Категории UID

UID-диапазоны в современной Ubuntu

Разные UID-диапазоны несут разный смысл — от root до nobody.

UID 0root — суперпользовательUID=0 — единственный, кому kernel даёт право обхода всех permission-checks. Это hardcoded в коде ядра: capable(CAP_DAC_OVERRIDE) для UID=0 возвращает true.
UID 1—999системные сервисыsystemd, postgres, redis, www-data, airflow, nobody — все живут здесь. Создаются автоматически при установке пакета через postinst-скрипт.
UID 1000—60000обычные пользователиРегулярные люди-пользователи. Первый созданный при инсталляции получает UID=1000. Это явная политика adduser, не правило kernel.
UID 65534nobodyСпециальный 'никто' — используется для NFS-маппинга, для unshare/sandbox, для контейнерных user namespaces. Минимально привилегированный регулярный user.

Граница UID < 1000 важна на практике: useradd -r создаёт system user в диапазоне 100-999 (без home-директории, без shell для логина). А adduser без флагов на Debian/Ubuntu создаст regular user с UID >= 1000.

/etc/passwd: 7 полей через двоеточие

Формат /etc/passwd — это CSV с разделителем :, придуманный ещё для UNIX V1. Семь полей на строке, кодировка ASCII (на современных системах — UTF-8 для GECOS).

$ grep '^levo:' /etc/passwd
levo:x:1000:1000:Lev Neganov,,,:/home/levo:/bin/bash
Анатомия строки /etc/passwd

Каждое поле имеет смысл — даже устаревший 'x' во втором.

1: usernamelevoИмя для входа. Регистро-чувствительно. Стандарт POSIX рекомендует [a-z_][a-z0-9_-]*, до 32 символов.
2: password placeholderxРаньше здесь был хеш пароля. Сейчас 'x' означает: пароль в /etc/shadow. '!' или '*' — аккаунт заблокирован.
3: UID1000Numeric user ID. Это число kernel сравнивает с owner-полем inode.
4: GID (primary)1000Primary group ID. Новые файлы получают эту группу по умолчанию (если нет SGID).
5: GECOSLev Neganov,,,Comma-separated: full name, room, work phone, home phone. Историческое поле от General Electric Comprehensive Operating System. Сейчас обычно только полное имя.
6: home directory/home/levoКуда login помещает $HOME. Если директории нет, login всё равно сработает, но cd $HOME упадёт.
7: shell/bin/bashЧто запустить при login. /usr/sbin/nologin или /bin/false блокируют интерактивный вход.

Прочитать /etc/passwd может любой пользователь — это нормально. Там нет секретов, только маппинг. Поэтому getent passwd или cat /etc/passwd работают без sudo.

$ cat /etc/passwd | head -5
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync

Обрати внимание на daemon, bin, sys — это исторические UNIX-юзеры, которые сохранились ради совместимости. Все имеют shell /usr/sbin/nologin, чтобы никто не мог зайти под ними.

/etc/shadow: где живут пароли

Когда пароль был в /etc/passwd, его мог прочитать любой и подобрать через словарь — passwd-файл readable для всех. В 1987 году ввели shadow passwords: хеш переехал в /etc/shadow, доступный только для root и группы shadow.

$ sudo cat /etc/shadow | grep '^levo'
levo:$y$j9T$abc...$xyz...:19850:0:99999:7:::

9 полей через ::

Поля /etc/shadow

Хеш пароля плюс политика устаревания пароля.

1: usernamelevo
2: hash$y$j9T$...Префикс $y$ — yescrypt (новый default в Debian 12+). $6$ — SHA-512. $2y$ — bcrypt. Между $ — соль. После последнего $ — сам хеш. '!' или '*' — пароль не задан/аккаунт locked.
3: last change19850Дни с эпохи UNIX (1 января 1970), когда пароль менялся последний раз. 19850 ≈ 2024-05.
4: min age0Минимум дней между сменами пароля. 0 — менять можно когда угодно.
5: max age99999Через сколько дней потребуется смена. 99999 ≈ 273 года = практически 'никогда'.
6: warn days7За сколько дней предупреждать о необходимости смены.
7: inactiveСколько дней после истечения пароль ещё работает, прежде чем lock account.
8: expireАбсолютная дата истечения аккаунта (дни с 1970).
9: reservedЗарезервировано на будущее. Всегда пусто.

Хеш проверить можно через mkpasswd -m yescrypt 'pwd' -s "j9T$abc" — алгоритмы детерминированы при одинаковой соли.

/etc/group: множественные группы

Пользователь имеет одну primary group (поле 4 в /etc/passwd) и может состоять в множестве secondary groups через /etc/group.

$ getent group | head -5
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:syslog,levo

Поля: groupname:placeholder:GID:members. Последнее поле — список пользователей через запятую (это secondary members). Primary-членство в /etc/group не отображается: если у levo primary GID=1000 и группа levo имеет GID=1000, в группе levo:x:1000: поле members может быть пустым — членство неявное.

$ groups levo
levo : levo sudo users docker adm

Команда groups объединяет primary + secondary для удобства. То же показывает id.

Зачем secondary groups DE

  • docker — без неё придётся писать sudo docker run каждый раз
  • sudo или wheel — даёт право на sudo
  • adm или systemd-journal — позволяет читать journalctl без sudo
  • airflow — share-доступ к /var/log/airflow/ без chown каждого файла

Команды идентификации

Команды для identity-checks

Каждая отвечает на свой вопрос.

whoamiкто я (effective UID -> name)Возвращает имя effective UID. Внутри sudo вернёт 'root'. Самая лёгкая команда — просто getuid()+getpwuid().
idполная identity (uid, gid, groups)Системный вызов: getuid, getgid, getgroups. Возвращает реальный + effective + все secondary. -u только UID, -g только GID, -G все группы numeric.
groups [user]primary + secondary groupsЕсли без аргумента — для текущего user. С аргументом — для указанного.
whoкто сейчас залогинен (utmp)Читает /var/run/utmp — список активных tty/pts сессий. Показывает username, tty, host, login time.
wwho + что они делаютРасширенная who: добавляет JCPU (CPU всех процессов tty), PCPU (текущая команда), WHAT (имя процесса foreground).
lastистория логинов (wtmp)Читает /var/log/wtmp — журнал всех login/logout. Полезно для аудита: 'кто заходил на bastion в выходные?'
$ whoami
levo

$ sudo whoami
root

$ id -u
1000

$ id -nG
levo sudo users docker adm

$ w
 12:34:56 up 5 days,  4 users,  load average: 0.42, 0.55, 0.61
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
levo     pts/0    192.168.1.10     09:15    0.00s  1.23s  0.01s w
airflow  pts/1    -                10:42    1h    45.3s  45.3s python
UID, GID и credential-набор процесса

Реальный/effective UID

Есть realUID (ruid) — кто ты на самом деле, и effectiveUID (euid) — чьими правами ты сейчас действуешь. Они отличаются после sudo или для SUID-программы:

$ id -u    # real UID
1000

$ sudo id -u   # effective стал 0
0

$ sudo id -ur  # real тоже стал 0 (sudo делает setuid(0))
0

Внутри sudo оба UID становятся 0, но в окружении остаются переменные SUDO_USER=levo, SUDO_UID=1000 — чтобы скрипты могли узнать «кто меня вызвал». Подробнее про SUID будет в уроке 05.

Создание пользователей: useradd vs adduser

В Debian/Ubuntu есть две команды с похожими именами:

КомандаЧто этоКогда использовать
useraddНизкоуровневая утилита из shadow-utils. POSIX-стандарт.Скрипты, Dockerfile, CI/CD. Предсказуемо.
adduserВысокоуровневый Perl-wrapper Debian/Ubuntu. Интерактивная.Ручное создание на десктопе.
# useradd: явно всё указываем
$ sudo useradd -m -s /bin/bash -G sudo,docker -c "ETL Worker" etl
# -m создаёт home, -s shell, -G secondary groups, -c GECOS

# adduser: задаёт вопросы интерактивно
$ sudo adduser etl
Adding user `etl' ...
Adding new group `etl' (1001) ...
Adding new user `etl' (1001) with group `etl' ...
Creating home directory `/home/etl' ...
Copying files from `/etc/skel' ...
New password: ...

В CI и Dockerfile всегда useradd:

RUN useradd -m -s /bin/bash -u 1001 airflow && \
    mkdir -p /opt/airflow && \
    chown -R airflow:airflow /opt/airflow

USER airflow

Флаг -r создаёт system user (UID < 1000, без home, без shell):

$ sudo useradd -r -s /usr/sbin/nologin postgres

Так делают postinst-скрипты пакетов: apt install postgresql создаст user postgres именно через useradd -r.

/etc/skel: шаблон home-директории

Когда useradd -m создаёт /home/etl/, он копирует туда всё содержимое /etc/skel/. Обычно там лежат .bashrc, .profile, .bash_logout — дефолтные dotfiles. Это удобный механизм для админа задать default-окружение для всех новых пользователей.

$ ls -la /etc/skel/
-rw-r--r-- 1 root root  220 .bash_logout
-rw-r--r-- 1 root root 3771 .bashrc
-rw-r--r-- 1 root root  807 .profile

Если ты хочешь, чтобы каждый новый user имел кастомный .bashrc с твоими aliases — клади его в /etc/skel/.

Попробуй сам

  1. Посмотри своего пользователя в /etc/passwd:
    grep "^$(whoami):" /etc/passwd
  2. Покажи только UID и primary GID:
    id -u && id -g
  3. Найди все system users (UID < 1000):
    awk -F: '$3 < 1000 {print $1, $3}' /etc/passwd
  4. Кто состоит в группе sudo:
    getent group sudo
  5. Когда ты последний раз менял пароль (только под sudo):
    sudo chage -l "$(whoami)"

macOS-различия

  • /etc/passwd на macOS существует, но там нет реальных пользователей — только системные демоны. Реальные пользователи живут в Directory Services (dscl). Команда dscl . -list /Users или id всё ещё работает.
  • useradd и adduser на macOS отсутствуют или работают непредсказуемо — добавлять пользователей надо через sysadminctl или dscl.
  • /etc/shadow на macOS нет — хеши паролей хранятся в /var/db/dslocal/nodes/Default/users/.

Для Junior DE это редко критично — большинство работают в Linux-Docker-контейнерах даже с Mac-хоста.

Проверка знанийKnowledge check
Файл /etc/passwd содержит запись 'airflow:x:1001:1001::/opt/airflow:/usr/sbin/nologin'. Можно ли войти под этим пользователем по SSH с паролем?
ОтветAnswer
Нет. Shell '/usr/sbin/nologin' блокирует интерактивный логин: при попытке войти этот бинарь печатает 'This account is currently not available' и сразу exit с кодом 1. Даже если у пользователя есть пароль в /etc/shadow, sshd после успешной аутентификации запускает указанный shell — а тот сразу завершается. Это стандартная политика для service-аккаунтов. Войти как airflow можно через sudo -u airflow -s, потому что sudo использует свой shell, не login shell. Поле password 'x' тоже намекает: реальный хеш живёт в /etc/shadow, и для service-юзеров там обычно '!' (locked).

Главное

  • Пользователь для kernel — это число (UID), имя — это запись в /etc/passwd.
  • UID 0 = root, UID < 1000 — системные сервисы, UID ≥ 1000 — обычные люди.
  • /etc/passwd — публичная (7 полей), /etc/shadow — приватная (только root, хеши паролей).
  • Primary group в /etc/passwd, secondary — в /etc/group.
  • whoami, id, groups, who, w — базовый toolkit идентификации.
  • useradd для скриптов и Docker, adduser для интерактива.
  • /etc/skel/ — шаблон для новых home-директорий.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Какое из утверждений про UID в Linux верно?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5