Файлы управления пользователями
TL;DR: Unix хранит информацию о пользователях в простых текстовых файлах.
/etc/passwd— учётные записи (uid, home, shell)./etc/shadow— хеши паролей (доступен только root)./etc/group— группы и их члены. Ядро работает только с числовыми uid/gid — имена пользователей существуют исключительно в пространстве пользователя.
Зачем это знать
Каждый процесс в Linux имеет числовой идентификатор пользователя (uid). Ядро не знает имён — оно оперирует числами. Файлы /etc/passwd и /etc/group — это маппинг между человекочитаемыми именами и числовыми идентификаторами. Понимание формата этих файлов объясняет:
- Почему
useraddбез-mне создаёт домашнюю директорию (это лишь запись в файле) - Откуда берётся UID при создании процесса
- Почему в контейнере пользователь видит
I have no name!(файл/etc/passwdне содержит маппинга для его uid) - Как работает аутентификация при логине
/etc/passwd
Основной файл учётных записей. Читаем всеми пользователями системы — поэтому паролей здесь нет (они вынесены в /etc/shadow).
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
john:x:1000:1000:John Doe:/home/john:/bin/bash
appuser:x:999:999::/opt/app:/usr/sbin/nologin
Каждая строка — одна учётная запись, 7 полей через ::
username:password:uid:gid:gecos:home:shell
| Поле | Описание | Пример |
|---|---|---|
username | Имя пользователя | john |
password | Заглушка (реальный хеш в /etc/shadow) | x — означает «смотри shadow» |
uid | Числовой ID пользователя | 1000 |
gid | Числовой ID основной группы | 1000 |
gecos | Комментарий (полное имя, контакты) | John Doe |
home | Домашняя директория | /home/john |
shell | Оболочка при логине | /bin/bash |
Диапазоны UID
| Диапазон | Назначение |
|---|---|
0 | root (суперпользователь) |
1–999 | Системные пользователи (сервисы: nginx, postgres, sshd) |
1000+ | Обычные пользователи |
65534 | nobody — пользователь без привилегий |
Конкретные границы определяются в /etc/login.defs (параметры UID_MIN, UID_MAX, SYS_UID_MIN, SYS_UID_MAX).
Поле shell
Оболочка определяет что происходит при логине. Для сервисных учётных записей задаётся /usr/sbin/nologin или /bin/false — обе запрещают интерактивный вход:
# nologin — выводит сообщение и отказывает
$ su - appuser
This account is currently not available.
# false — молча возвращает код ошибкиСписок допустимых оболочек: /etc/shells. Если shell пользователя не в этом файле, некоторые программы (например FTP-серверы) откажут в доступе.
Поле GECOS
Исторически — поле для информации из системы General Electric Comprehensive Operating System. Может содержать несколько значений через запятую: полное имя, номер комнаты, рабочий телефон, домашний телефон. Сейчас обычно только полное имя.
# Посмотреть
getent passwd john
# john:x:1000:1000:John Doe:/home/john:/bin/bash
# Изменить
sudo chfn john # интерактивно
sudo usermod -c "John A. Doe" john/etc/shadow
Хеши паролей и политика устаревания. Доступен только root (права 640, владелец root:shadow).
root:$6$rounds=5000$salt$hash...:19500:0:99999:7:::
john:$y$j9T$salt$hash...:19750:0:90:7:30::
appuser:!:19500:::::
locked:!*:19500:::::
9 полей через ::
username:hash:lastchange:min:max:warn:inactive:expire:reserved
| Поле | Описание | Пример |
|---|---|---|
username | Имя (совпадает с /etc/passwd) | john |
hash | Хеш пароля | $y$j9T$salt$hash... |
lastchange | Дата последней смены (дни с 1 января 1970) | 19750 |
min | Минимум дней между сменами | 0 |
max | Максимум дней до обязательной смены | 90 |
warn | За сколько дней предупреждать | 7 |
inactive | Дней после expire до блокировки | 30 |
expire | Дата блокировки (дни с epoch) | пусто = никогда |
reserved | Зарезервировано | пусто |
Формат хеша пароля
$id$salt$hash
| ID | Алгоритм | Актуальность |
|---|---|---|
$1$ | MD5 | Устаревший, не использовать |
$5$ | SHA-256 | Допустимый |
$6$ | SHA-512 | Стандарт для большинства дистрибутивов |
$y$ | yescrypt | Современный, по умолчанию в Debian 12+, Ubuntu 22.04+, Fedora 35+ |
Специальные значения поля hash
| Значение | Смысл |
|---|---|
$id$salt$hash | Нормальный хеш пароля |
! | Учётная запись заблокирована (пароль не задан) |
!$id$salt$hash | Заблокирована, но хеш сохранён (можно разблокировать) |
* | Вход по паролю запрещён (системные аккаунты) |
| пусто | Пароль не требуется (опасно!) |
# Заблокировать аккаунт (добавляет ! перед хешем)
sudo passwd -l john
# Разблокировать (убирает !)
sudo passwd -u john
# Проверить статус
sudo passwd -S john
# john P 2026-02-15 0 90 7 30 (P=password set, L=locked, NP=no password)
# Принудительная смена пароля при следующем логине
sudo chage -d 0 john
# Информация об устаревании
sudo chage -l john/etc/group
Группы и их члены.
root:x:0:
sudo:x:27:john
docker:x:998:john,deploy
developers:x:1001:john,alice,bob
4 поля через ::
groupname:password:gid:members
| Поле | Описание | Пример |
|---|---|---|
groupname | Имя группы | developers |
password | Пароль группы (практически не используется) | x |
gid | Числовой ID группы | 1001 |
members | Список членов через запятую | john,alice,bob |
Основная vs дополнительные группы
У каждого пользователя есть одна основная группа (поле gid в /etc/passwd) и ноль или более дополнительных (перечислены в /etc/group).
# john с uid=1000, gid=1000 (основная группа john)
# Дополнительные: sudo, docker, developers
$ id john
uid=1000(john) gid=1000(john) groups=1000(john),27(sudo),998(docker),1001(developers)Основная группа пользователя может не быть перечислена в /etc/group в поле members — принадлежность определяется полем gid в /etc/passwd.
Файлы, создаваемые пользователем, получают его основную группу:
$ touch newfile
$ ls -l newfile
-rw-r--r-- 1 john john 0 Feb 18 12:00 newfile
# ↑ ↑
# uid gid (основная группа)/etc/login.defs
Конфигурация поведения useradd, userdel, passwd и других утилит управления пользователями.
# Ключевые параметры
UID_MIN 1000 # минимальный UID для обычных пользователей
UID_MAX 60000 # максимальный UID
SYS_UID_MIN 100 # минимальный UID для системных
SYS_UID_MAX 999 # максимальный UID для системных
PASS_MAX_DAYS 99999 # максимум дней действия пароля
PASS_MIN_DAYS 0 # минимум дней между сменами
PASS_WARN_AGE 7 # предупреждение за N дней
CREATE_HOME yes # создавать ли home при useradd
ENCRYPT_METHOD SHA512 # алгоритм хеширования паролей/etc/nsswitch.conf — откуда брать данные
Name Service Switch определяет источники информации о пользователях и группах. Система не обязана читать именно файлы — данные могут приходить из LDAP, NIS, SSSD.
# /etc/nsswitch.conf (типичный)
passwd: files systemd
group: files systemd
shadow: files
# С LDAP (корпоративная среда)
passwd: files sss ldap
group: files sss ldap| Источник | Описание |
|---|---|
files | Локальные файлы (/etc/passwd, /etc/group) |
systemd | systemd-userdbd (динамические пользователи) |
sss | SSSD (кеширующий прокси для LDAP/AD) |
ldap | LDAP-каталог напрямую |
nis | NIS (устаревший, но встречается) |
Именно поэтому для чтения данных о пользователях правильнее использовать getent вместо прямого чтения файла — getent учитывает nsswitch:
# Правильно — ищет по всем настроенным источникам
getent passwd john
# Менее правильно — только локальный файл
grep john /etc/passwdКак это работает при логине
1. Пользователь вводит username + password
│
2. login/sshd/su ищет username в /etc/passwd
(через NSS → getpwnam())
│
3. Находит uid, gid, home, shell
│
4. Читает /etc/shadow → достаёт хеш и параметры устаревания
│
5. Хеширует введённый пароль тем же алгоритмом + salt
│
6. Сравнивает хеши
│
├── совпали → запускает shell с uid/gid пользователя
│ переходит в home, читает дополнительные
│ группы из /etc/group
└── не совпали → отказ
Важно: В современных системах этим занимается PAM (Pluggable Authentication Modules), а не программы напрямую. PAM добавляет гибкость: двухфакторная аутентификация, ограничения по времени, LDAP-бэкенды — всё без изменения login/sshd.
PAM (Pluggable Authentication Modules)
PAM — модульная система аутентификации. Вместо того чтобы каждая программа (login, sshd, su, sudo) сама проверяла пароли, они вызывают PAM, а PAM делегирует проверку цепочке модулей.
Конфигурация
/etc/pam.d/ # конфигурации для каждой программы
├── login # для login
├── sshd # для SSH
├── sudo # для sudo
├── su # для su
└── common-auth # общие правила аутентификации (Debian/Ubuntu)
Каждая строка конфига:
# тип контроль модуль аргументы
auth required pam_unix.so nullok
account required pam_nologin.so
password sufficient pam_unix.so sha512 shadow
session required pam_limits.so
| Тип | Что делает |
|---|---|
auth | Проверка личности (пароль, ключ, OTP) |
account | Проверка доступа (не истёк ли аккаунт, время входа) |
password | Смена пароля (требования сложности) |
session | Действия при входе/выходе (запись в лог, монтирование home) |
| Контроль | Поведение при ошибке |
|---|---|
required | Отказ, но продолжить проверку остальных (для логирования) |
requisite | Немедленный отказ |
sufficient | Успех → пропустить остальные модули этого типа |
optional | Результат учитывается только если это единственный модуль |
Частые модули
| Модуль | Назначение |
|---|---|
pam_unix.so | Проверка пароля через /etc/shadow |
pam_nologin.so | Блокирует вход если существует /etc/nologin |
pam_limits.so | Применяет лимиты из /etc/security/limits.conf |
pam_deny.so | Всегда отказывает (для блокировки) |
pam_permit.so | Всегда разрешает (осторожно!) |
pam_google_authenticator.so | 2FA через Google Authenticator |
getty и login
При текстовом входе в систему (консоль, не SSH) работает цепочка:
systemd → getty@tty1.service → agetty → показывает "login:"
→ пользователь вводит имя → login → PAM → проверка пароля → shell
agetty (alternative getty) — программа, которая открывает терминал и показывает приглашение login:. После ввода имени пользователя передаёт управление программе login, которая через PAM проверяет пароль и запускает shell.
# Активные getty (виртуальные терминалы)
systemctl list-units 'getty@*'
# getty@tty1.service active running Getty on tty1
# Переключение между виртуальными консолями
# Ctrl+Alt+F1..F6 — текстовые
# Ctrl+Alt+F7 — графическая (обычно)Подводные камни
| Проблема | Симптом | Решение |
|---|---|---|
Редактирование /etc/passwd вручную | Синтаксическая ошибка → никто не может залогиниться | Использовать vipw — валидирует синтаксис перед сохранением |
Редактирование /etc/shadow вручную | Аналогично | vipw -s для shadow |
Редактирование /etc/group вручную | Аналогично | vigr |
usermod -G без -a | Пользователь выпадает из всех групп кроме указанной | Всегда usermod -aG |
В контейнере I have no name! | uid процесса не найден в /etc/passwd | Добавить запись в /etc/passwd контейнера или использовать --user с существующим uid |
| Пустое поле hash в shadow | Вход без пароля (дыра в безопасности) | passwd -l user для блокировки |
getent passwd не показывает пользователя | nsswitch настроен не на files | Проверить /etc/nsswitch.conf |
Связанные материалы
- permissions-model — rwx, chmod, chown, SUID/SGID, sudo
- manage-users — useradd, usermod, группы, sudo, passwd
- harden-server — SSH, fail2ban, ограничение доступа