Автоматизация создания пользователей и групп
Массово создавайте, изменяйте и проверяйте учётные записи с помощью useradd, chage и управления фрагментами sudoers
«Автоматизация создания пользователей и групп» — бесплатный урок DevOps Bootcamp на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения DevOps Bootcamp, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс DevOps Bootcamp содержит 4 уроков всего.
Зачем автоматизировать подготовку учетных записей пользователей?
Управление пользователями по одному с помощью useradd вполне подходит для нескольких учетных записей, но в корпоративных средах одновременно обычно подключаются десятки или сотни пользователей. Ручные команды приводят к ошибкам, несогласованности и невозможности провести аудит.
Сценарии Bash позволяют Вам:
- каждый раз создавать пользователей со стандартными настройками (оболочка, домашний каталог, политика паролей);
- читать CSV или текстовый файл с данными новых сотрудников и создавать учетные записи за один запуск;
- вести журнал каждого действия, чтобы иметь аудиторский след для целей соответствия требованиям;
- интегрироваться с конвейерами управления конфигурацией (Ansible, Chef, Jenkins).
В этом уроке Вы с нуля создадите готовый к эксплуатации сценарий подготовки учетных записей пользователей, рассмотрев useradd, chage, usermod, управление группами, фрагменты конфигурации sudoers и аудит после выполнения.
Чтение списка пользователей для массового создания
Канонический формат входных данных для массового создания учетных записей — текстовый файл с разделителями, по одной записи в строке. Типичный CSV может выглядеть так:
username,full_name,group,shell
alice,Alice Smith,developers,/bin/bash
bob,Bob Jones,ops,/bin/zshИспользуйте IFS и read внутри цикла while, чтобы безопасно разобрать файл. Пропуск строки заголовка с помощью tail -n +2 упрощает логику.
Основные защитные меры:
- удаляйте начальные и конечные пробелы в каждом поле;
- пропускайте пустые строки и строки комментариев, начинающиеся с
#; - проверяйте, что обязательные поля не пусты, прежде чем вызывать системные команды.
#!/usr/bin/env bash
# parse_users.sh — safely read a CSV of users
set -euo pipefail
USER_FILE="${1:-users.csv}"
[[ -f "$USER_FILE" ]] || { echo "ERROR: $USER_FILE not found"; exit 1; }
tail -n +2 "$USER_FILE" | while IFS=',' read -r username full_name group shell; do
# trim whitespace
username="${username// /}"
[[ -z "$username" || "$username" == \#* ]] && continue
echo "Parsed -> user=$username group=$group shell=$shell"
doneСоздание пользователей с помощью useradd
useradd — низкоуровневая утилита, записывающая данные в /etc/passwd, /etc/shadow и /etc/group. Наиболее важные параметры для сценариев:
-m— создать домашний каталог;-s— установить оболочку входа;-c— поле комментария GECOS (полное имя);-G— дополнительные группы (через запятую);-e— дата истечения срока действия учетной записи (YYYY-MM-DD).
Всегда проверяйте существование пользователя с помощью id перед вызовом useradd: при запуске для уже существующего пользователя команда возвращает код завершения 9 и выводит ошибку, которая может засорить журналы.
Примечание: useradd требует прав суперпользователя. В начале сценария добавьте проверку привилегий.
#!/usr/bin/env bash
# create_user.sh — idempotent single-user creation
set -euo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
USERNAME="$1"
FULL_NAME="${2:-}"
GROUP="${3:-staff}"
SHELL="${4:-/bin/bash}"
if id "$USERNAME" &>/dev/null; then
echo "[SKIP] User $USERNAME already exists"
else
useradd \
--create-home \
--shell "$SHELL" \
--comment "$FULL_NAME" \
--groups "$GROUP" \
"$USERNAME"
echo "[OK] Created $USERNAME"
fiБезопасная установка начальных паролей
Никогда не прописывайте пароли непосредственно в сценариях. Для массового создания учетных записей существуют два безопасных подхода:
- Сгенерировать случайный начальный пароль с помощью
openssl randили/dev/urandom, вывести его один раз и заставить пользователя сменить его при первом входе; - Установить предварительно хешированный пароль с помощью
usermod -p, используя хеш SHA-512, чтобы пароль в открытом виде никогда не появлялся в списке процессов.
chpasswd — рекомендуемый инструмент для установки паролей в сценариях: он читает пары username:password из стандартного ввода, поэтому пароль не появляется в аргументах командной строки (видимых через ps).
После установки пароля используйте chage -d 0, чтобы принудительно потребовать немедленную смену пароля при следующем входе.
#!/usr/bin/env bash
# set_temp_password.sh
set -euo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
USERNAME="$1"
# Generate a 16-char random password (alphanumeric only)
TMP_PASS=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16)
# Set password via chpasswd (password never in argv)
echo "${USERNAME}:${TMP_PASS}" | chpasswd
# Force password change on next login
chage -d 0 "$USERNAME"
echo "[OK] Temporary password for $USERNAME: $TMP_PASS"
echo "[OK] User must change password on first login"Управление сроком действия паролей с помощью chage
chage (изменение срока действия) управляет политикой старения паролей, хранящейся в /etc/shadow. Корпоративные политики безопасности обычно требуют:
- максимального срока действия пароля (например, 90 дней);
- минимального числа дней до следующей смены пароля;
- периода предупреждения до истечения срока действия;
- блокировки неактивной учетной записи после последнего использования пароля.
Основные параметры chage:
-M <days>— максимальный срок действия пароля;-m <days>— минимальный срок действия пароля;-W <days>— число дней для предупреждения до истечения срока;-I <days>— число дней бездействия до блокировки учетной записи;-E <date>— абсолютная дата истечения срока действия учетной записи;-l— показать текущие настройки пользователя.
#!/usr/bin/env bash
# apply_password_policy.sh — enforce org-wide ageing policy
set -euo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
# Policy constants
MAX_AGE=90
MIN_AGE=1
WARN_DAYS=14
INACTIVE_DAYS=30
apply_policy() {
local user="$1"
chage \
-M "$MAX_AGE" \
-m "$MIN_AGE" \
-W "$WARN_DAYS" \
-I "$INACTIVE_DAYS" \
"$user"
echo "[OK] Policy applied to $user"
}
# Apply to all non-system users (UID >= 1000)
awk -F: '$3 >= 1000 && $3 < 65534 { print $1 }' /etc/passwd | while read -r user; do
apply_policy "$user"
doneМассовое управление группами
Группы — основной механизм управления доступом к ресурсам. Сценарий подготовки учетных записей должен убедиться, что необходимые группы существуют, прежде чем добавлять в них пользователей: useradd -G nonexistent завершится ошибкой.
Используйте groupadd идемпотентно, проверяя код завершения: он возвращает 9, если группа уже существует. Идиома getent group <name> — переносимая и понятная альтернатива поиску с помощью grep в /etc/group.
gpasswd -a добавляет пользователя в группу, не заменяя уже существующие членства (в отличие от usermod -G, который заменяет список дополнительных групп).
#!/usr/bin/env bash
# ensure_groups.sh — create groups if missing, then add users
set -euo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
REQUIRED_GROUPS=(developers ops security auditors)
for grp in "${REQUIRED_GROUPS[@]}"; do
if getent group "$grp" &>/dev/null; then
echo "[SKIP] Group $grp already exists"
else
groupadd "$grp"
echo "[OK] Created group $grp"
fi
done
# Safely add a user to a group (append, don't replace)
add_to_group() {
local user="$1" group="$2"
gpasswd -a "$user" "$group" 2>/dev/null && echo "[OK] $user -> $group"
}Полный сценарий массового создания учетных записей
Соберем все вместе: один сценарий читает CSV, создает пользователей и группы, устанавливает политику паролей, записывает в журнал каждое действие и корректно обрабатывает ошибки, не останавливая весь пакет.
Важные проектные решения в приведенном ниже сценарии:
LOG_FILEс временными метками сохраняет все операции для аудита;- ошибки отдельных пользователей записываются в журнал, но не прерывают цикл (
|| log_error); - сценарий идемпотентен — его безопасно повторно запускать после частичных сбоев;
- весь вывод направляется одновременно в терминал и файл журнала с помощью
tee.
#!/usr/bin/env bash
# bulk_provision.sh — production user provisioning
set -uo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
USER_FILE="${1:-users.csv}"
LOG_FILE="/var/log/user_provision_$(date +%F).log"
log() { echo "[$(date '+%F %T')] $*" | tee -a "$LOG_FILE"; }
err() { log "ERROR: $*"; }
log "=== Provisioning started from $USER_FILE ==="
tail -n +2 "$USER_FILE" | while IFS=',' read -r username fullname group shell; do
username="${username// /}"
[[ -z "$username" || "$username" == \#* ]] && continue
group="${group:-staff}"
shell="${shell:-/bin/bash}"
# Ensure group exists
getent group "$group" &>/dev/null || groupadd "$group"
# Create user idempotently
if id "$username" &>/dev/null; then
log "[SKIP] $username exists"
else
useradd -m -s "$shell" -c "$fullname" -G "$group" "$username" || { err "useradd failed for $username"; continue; }
TMP="$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 14)"
echo "${username}:${TMP}" | chpasswd
chage -M 90 -m 1 -W 14 -I 30 -d 0 "$username"
log "[OK] $username created (group=$group) tmp_pass=$TMP"
fi
done
log "=== Provisioning complete ==="Управление фрагментами конфигурации sudoers
Прямое редактирование /etc/sudoers опасно: синтаксическая ошибка лишит всех доступа к sudo. Безопасный подход — использовать файлы-фрагменты в /etc/sudoers.d/, проверяя каждый из них с помощью visudo -c -f перед установкой.
Рекомендации для фрагментов sudoers:
- называйте файлы в соответствии с командой или ролью, права которой они предоставляют (например,
10-developers,20-ops); - используйте правила для групп (
%developers ALL=(ALL) NOPASSWD: /usr/bin/systemctl), а не строки для отдельных пользователей; - всегда устанавливайте права
0440и владельцаroot:root; - проверяйте конфигурацию с помощью
visudo -c— при любой синтаксической ошибке команда завершается с ненулевым кодом.
#!/usr/bin/env bash
# write_sudoers_fragment.sh
set -euo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
FRAGMENT_NAME="${1:-10-developers}"
SUDOERS_DIR="/etc/sudoers.d"
TMP_FILE="$(mktemp)"
# Write the fragment to a temp file first
cat > "$TMP_FILE" << 'EOF'
# Developers: restart services and view journals without full root
%developers ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/journalctl
%ops ALL=(ALL) NOPASSWD: ALL
EOF
# Validate BEFORE installing
if visudo -c -f "$TMP_FILE"; then
install -m 0440 -o root -g root "$TMP_FILE" "${SUDOERS_DIR}/${FRAGMENT_NAME}"
echo "[OK] Installed ${SUDOERS_DIR}/${FRAGMENT_NAME}"
else
echo "[ERROR] sudoers syntax check failed — fragment NOT installed"
rm -f "$TMP_FILE"
exit 1
fi
rm -f "$TMP_FILE"Аудит существующих учетных записей
После создания учетных записей и регулярно в дальнейшем следует проверять базу пользователей на наличие аномалий:
- Учетные записи с UID 0 — любая учетная запись с UID 0, кроме root, является критическим событием безопасности;
- Учетные записи без пароля — записи с пустым полем пароля или полем, содержащим
!, в/etc/shadow; - Истекшие, но все еще активные учетные записи — вывод
chage -lможно обработать массово; - Пользователи с оболочками, но без домашнего каталога — такая неправильная настройка нарушает вход в систему.
Создать структурированный отчет и отправить его по электронной почте команде безопасности несложно с помощью mail или добавив отчет в контролируемый путь журнала.
#!/usr/bin/env bash
# audit_users.sh — produce a security-relevant user report
set -uo pipefail
REPORT="/var/log/user_audit_$(date +%F).txt"
echo "=== User Audit Report $(date) ===" > "$REPORT"
echo "" >> "$REPORT"
echo "--- Accounts with UID 0 (should be root only) ---" >> "$REPORT"
awk -F: '$3 == 0 { print $1 }' /etc/passwd >> "$REPORT"
echo "" >> "$REPORT"
echo "--- Accounts with empty password field ---" >> "$REPORT"
awk -F: '($2 == "" || $2 == "!") && $3 >= 1000 { print $1 }' /etc/shadow 2>/dev/null >> "$REPORT" || echo " (requires root)" >> "$REPORT"
echo "" >> "$REPORT"
echo "--- Normal users (UID 1000-60000) ---" >> "$REPORT"
awk -F: '$3 >= 1000 && $3 < 60000 { printf "%-20s uid=%-6s shell=%s\n", $1, $3, $7 }' /etc/passwd >> "$REPORT"
cat "$REPORT"
echo "Report saved to $REPORT"Блокировка, разблокировка и удаление учетных записей
Вывод пользователя из системы не менее важен, чем его подключение. Когда пользователь покидает организацию, выполните следующие действия:
- Немедленно заблокируйте учетную запись (
usermod -L) — команда добавляет!перед хешем пароля в shadow, предотвращая вход без удаления данных; - Отзовите права sudo — удалите фрагмент sudoers пользователя, если он существует;
- Передайте владение его файлами руководителю или архивной учетной записи;
- Архивируйте домашний каталог в tar-архив перед удалением;
- Удалите учетную запись с помощью
userdel -r— команда удаляет домашний каталог и почтовый буфер.
usermod -U разблокирует учетную запись (удаляет префикс !); это удобно для временной приостановки.
#!/usr/bin/env bash
# offboard_user.sh — lock, archive, then optionally delete
set -euo pipefail
[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }
USERNAME="$1"
ARCHIVE_DIR="/srv/archived-homes"
mkdir -p "$ARCHIVE_DIR"
# 1. Lock account
usermod -L "$USERNAME"
echo "[OK] Account $USERNAME locked"
# 2. Remove sudoers fragment if present
SUDOERS_FILE="/etc/sudoers.d/${USERNAME}"
[[ -f "$SUDOERS_FILE" ]] && rm -f "$SUDOERS_FILE" && echo "[OK] Removed sudoers fragment"
# 3. Archive home directory
HOME_DIR="$(getent passwd "$USERNAME" | cut -d: -f6)"
if [[ -d "$HOME_DIR" ]]; then
tar -czf "${ARCHIVE_DIR}/${USERNAME}_$(date +%F).tar.gz" -C "$(dirname "$HOME_DIR")" "$(basename "$HOME_DIR")"
echo "[OK] Home archived to ${ARCHIVE_DIR}/${USERNAME}_$(date +%F).tar.gz"
fi
echo "[NOTICE] Review archive, then run: userdel -r $USERNAME"Тестирование сценария в режиме пробного запуска
Сценарии подготовки учетных записей для эксплуатации должны быть пригодны для тестирования без побочных эффектов. Реализуйте режим пробного запуска с помощью флага DRY_RUN, заменяющего все изменяющие команды заглушками echo.
Шаблон прост: определите вспомогательную функцию run(), которая в зависимости от флага либо выполняет команду, либо выводит ее. Такой подход означает, что:
- при тестировании выполняется каждый путь кода;
- вывод точно показывает, что произошло бы при реальном запуске;
- конвейеры CI могут проверять логику без доступа суперпользователя.
Дополните пробный запуск специальным префиксом тестовых пользователей (например, test_), чтобы их было легко удалить после интеграционных тестов.
#!/usr/bin/env bash
# provision_with_dryrun.sh
set -euo pipefail
DRY_RUN="${DRY_RUN:-false}"
# Wrapper: execute or echo
run() {
if [[ "$DRY_RUN" == "true" ]]; then
echo "[DRY-RUN] $*"
else
"$@"
fi
}
create_user() {
local user="$1" group="$2"
if id "$user" &>/dev/null; then
echo "[SKIP] $user exists"
return
fi
run useradd -m -s /bin/bash -G "$group" "$user"
run chage -M 90 -m 1 -W 14 -d 0 "$user"
echo "[OK] $user provisioned (dry=$DRY_RUN)"
}
# Test run
DRY_RUN=true create_user testuser developers
echo "---"
create_user realuser developers 2>/dev/null || trueКакую команду следует использовать, чтобы добавить пользователя в дополнительную группу, не удаляя его членство в существующих группах?
В сценарии массового создания учетных записей Вам нужно добавить существующего пользователя в группу auditors. Пользователь уже входит в группы developers и staff. Какая команда сохранит все существующие членства и добавит новое?
Повторение урока: автоматизация создания пользователей и групп
В этом уроке Вы создали полный готовый к эксплуатации набор инструментов для подготовки учетных записей пользователей. Основные выводы:
- Безопасно разбирайте входные данные — используйте циклы
IFS/read, пропускайте пустые строки и строки комментариев, проверяйте поля перед любым системным вызовом; - Основы
useradd— всегда используйте-m(домашний каталог),-s(оболочка),-c(комментарий) и-G(группы); сначала проверяйте существование с помощьюidдля обеспечения идемпотентности; - Пароли — задавайте через стандартный ввод
chpasswd, чтобы пароль в открытом виде не попадал в аргументы процесса; принудительно требуйте смену при первом входе с помощьюchage -d 0; chageдля политики — унифицируйте максимальный срок действия (-M), количество дней предупреждения (-W) и блокировку после бездействия (-I) для всех несистемных учетных записей;- Членство в группах — используйте
gpasswd -aилиusermod -aG(с флагом-a), чтобы добавлять членства, а не заменять их; - Фрагменты sudoers — записывайте их в
/etc/sudoers.d/, проверяйте с помощьюvisudo -c -fперед установкой и задавайте права0440 root:root; - Вывод пользователя из системы — заблокируйте учетную запись (
usermod -L), архивируйте домашний каталог, затем удалите учетную запись; никогда не пропускайте архивирование; - Режим пробного запуска — оборачивайте изменяющие команды во вспомогательную функцию
run(), чтобы конвейеры могли проверять логику без побочных эффектов, требующих прав суперпользователя.
Объединение этих шаблонов дает Вам воспроизводимый, проверяемый и безопасный уровень автоматизации управления удостоверениями Linux в любом масштабе.
Часто задаваемые вопросы
Урок «Автоматизация создания пользователей и групп» бесплатный?
Да — полный текст урока «Автоматизация создания пользователей и групп» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс DevOps Bootcamp, подпишись на CoddyKit PRO. Курс DevOps Bootcamp содержит 4 уроков всего.
Чему я научусь в уроке «Автоматизация создания пользователей и групп»?
Массово создавайте, изменяйте и проверяйте учётные записи с помощью useradd, chage и управления фрагментами sudoers Ты практикуешь DevOps Bootcamp с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать DevOps Bootcamp?
Предыдущий опыт не требуется. DevOps Bootcamp на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Автоматизация создания пользователей и групп»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке DevOps Bootcamp?
Да. Каждый урок DevOps Bootcamp включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Автоматизация создания пользователей и групп
- Управление службами systemd и создание файлов модулей
- Автоматизация дисков, файловых систем и монтирования
- Создание скриптов проверки состояния системы и оповещений