Automatyzacja tworzenia użytkowników i grup
Twórz, modyfikuj i kontroluj zbiorczo konta, używając useradd, chage oraz zarządzania fragmentami sudoers.
Automatyzacja tworzenia użytkowników i grup to bezpłatna lekcja DevOps Bootcamp na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej DevOps Bootcamp, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs DevOps Bootcamp zawiera 4 lekcji w sumie.
Dlaczego warto automatyzować tworzenie kont użytkowników?
Zarządzanie użytkownikami pojedynczo za pomocą useradd sprawdza się w przypadku kilku kont, jednak w środowiskach korporacyjnych regularnie dodaje się jednocześnie dziesiątki lub setki użytkowników. Ręczne polecenia stają się podatne na błędy, niespójne i niemożliwe do odpowiedniego audytowania.
Skrypty Bash pozwalają Państwu:
- za każdym razem tworzyć użytkowników ze standardowymi ustawieniami (powłoka, katalog domowy, zasady haseł)
- odczytywać plik CSV lub tekstowy z danymi nowych pracowników i tworzyć ich konta podczas jednego uruchomienia
- rejestrować każdą operację, uzyskując ścieżkę audytową na potrzeby zgodności
- integrować się z potokami zarządzania konfiguracją (Ansible, Chef, Jenkins)
W tej lekcji krok po kroku zbudują Państwo gotowy do użycia skrypt tworzenia kont użytkowników, obejmujący useradd, chage, usermod, zarządzanie grupami, fragmenty drop-in sudoers oraz audyt po wykonaniu skryptu.
Odczytywanie zbiorczej listy użytkowników
Standardowym formatem danych wejściowych przy zbiorczym tworzeniu kont jest rozdzielany plik tekstowy — jeden rekord w każdym wierszu. Typowy plik CSV może wyglądać następująco:
username,full_name,group,shell
alice,Alice Smith,developers,/bin/bash
bob,Bob Jones,ops,/bin/zshProszę używać IFS i read wewnątrz pętli while, aby bezpiecznie go analizować. Pominięcie wiersza nagłówka za pomocą tail -n +2 pozwala zachować przejrzystość logiki.
Najważniejsze praktyki defensywne:
- usuwać początkowe i końcowe białe znaki z każdego pola
- pomijać puste wiersze oraz wiersze komentarzy zaczynające się od
# - sprawdzać, czy wymagane pola nie są puste, zanim zostaną wywołane polecenia systemowe
#!/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"
doneTworzenie użytkowników za pomocą useradd
useradd to niskopoziomowe narzędzie zapisujące dane do plików /etc/passwd, /etc/shadow i /etc/group. Najważniejsze opcje przy skryptowaniu to:
-m— utworzenie katalogu domowego-s— ustawienie powłoki logowania-c— pole komentarza GECOS (imię i nazwisko)-G— grupy dodatkowe (rozdzielane przecinkami)-e— data wygaśnięcia konta (YYYY-MM-DD)
Przed wywołaniem useradd należy zawsze sprawdzić za pomocą id, czy użytkownik już istnieje; uruchomienie polecenia dla istniejącego użytkownika zwraca kod zakończenia 9 i wyświetla błąd, który może niepotrzebnie zaśmiecać dzienniki.
Uwaga: useradd wymaga uprawnień administratora. Na początku skryptu należy umieścić sprawdzenie uprawnień.
#!/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"
fiBezpieczne ustawianie haseł początkowych
Nigdy nie należy umieszczać haseł na stałe w skryptach. Dwa bezpieczne sposoby zbiorczego tworzenia kont to:
- Wygenerowanie losowego hasła początkowego za pomocą
openssl randlub/dev/urandom, wyświetlenie go jeden raz i wymuszenie zmiany przy pierwszym logowaniu - Ustawienie hasła w postaci gotowego skrótu za pomocą
usermod -pz użyciem skrótu SHA-512, dzięki czemu tekst jawny nie pojawia się na liście procesów
chpasswd jest zalecanym narzędziem do ustawiania haseł w skryptach — odczytuje ze standardowego wejścia pary username:password, więc hasło nie pojawia się w argumentach wiersza poleceń (widocznych za pomocą ps).
Po ustawieniu hasła należy użyć chage -d 0, aby wymusić jego natychmiastową zmianę przy następnym logowaniu.
#!/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"Zarządzanie okresem ważności haseł za pomocą chage
chage (change age) kontroluje zasady starzenia haseł przechowywane w /etc/shadow. Zasady bezpieczeństwa obowiązujące w przedsiębiorstwach zazwyczaj wymagają:
- maksymalnego okresu ważności hasła (np. 90 dni)
- minimalnej liczby dni, po których można ponownie zmienić hasło
- okresu ostrzegania przed wygaśnięciem
- blokady konta po okresie nieaktywności od ostatniego użycia hasła
Najważniejsze opcje chage:
-M <days>— maksymalny okres ważności hasła-m <days>— minimalny okres ważności hasła-W <days>— liczba dni ostrzegania przed wygaśnięciem-I <days>— liczba dni nieaktywności przed zablokowaniem konta-E <date>— bezwzględna data wygaśnięcia konta-l— wyświetlenie bieżących ustawień użytkownika
#!/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"
doneZbiorcze zarządzanie grupami
Grupy są podstawowym mechanizmem kontrolowania dostępu do zasobów. Skrypt tworzący konta musi upewnić się, że wymagane grupy istnieją, zanim doda do nich użytkowników — useradd -G nonexistent zakończy się niepowodzeniem.
Proszę używać groupadd w sposób idempotentny, sprawdzając kod zakończenia: polecenie zwraca 9, jeśli grupa już istnieje. Konstrukcja getent group <name> jest przenośną i czytelną alternatywą dla wyszukiwania w pliku /etc/group za pomocą grep.
gpasswd -a dodaje użytkownika do grupy bez zastępowania istniejących członkostw (w przeciwieństwie do usermod -G, które zastępuje listę grup dodatkowych).
#!/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"
}Kompletny skrypt zbiorczego tworzenia kont
Połączmy wszystkie elementy: pojedynczy skrypt odczytuje plik CSV, tworzy użytkowników i grupy, ustawia zasady haseł, rejestruje każdą operację i poprawnie obsługuje błędy bez zatrzymywania całej partii.
Ważne decyzje projektowe zastosowane w poniższym skrypcie:
- plik
LOG_FILEze znacznikami czasu rejestruje wszystkie operacje na potrzeby audytu - błędy dotyczące pojedynczych użytkowników są rejestrowane, ale nie przerywają pętli (
|| log_error) - skrypt jest idempotentny — można go bezpiecznie uruchomić ponownie po częściowych niepowodzeniach
- całe wyjście trafia jednocześnie do terminala i pliku dziennika za pośrednictwem
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 ==="Zarządzanie fragmentami drop-in sudoers
Bezpośrednia edycja pliku /etc/sudoers jest niebezpieczna — błąd składni może pozbawić wszystkich dostępu do sudo. Bezpiecznym rozwiązaniem jest używanie plików drop-in w katalogu /etc/sudoers.d/, z których każdy należy sprawdzić za pomocą visudo -c -f przed umieszczeniem go we właściwym miejscu.
Najlepsze praktyki dotyczące fragmentów sudoers:
- nazywać pliki zgodnie z zespołem lub rolą, której uprawnienia przyznają (np.
10-developers,20-ops) - używać reguł opartych na grupach (
%developers ALL=(ALL) NOPASSWD: /usr/bin/systemctl) zamiast wpisów dla poszczególnych użytkowników - zawsze ustawiać uprawnienia na
0440, a właściciela i grupę naroot:root - sprawdzać poprawność za pomocą
visudo -c— polecenie zwraca niezerowy kod zakończenia przy każdym błędzie składni
#!/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"Audyt istniejących kont
Po utworzeniu kont, a także zgodnie z regularnym harmonogramem, należy przeprowadzać audyt bazy użytkowników w celu wykrycia nieprawidłowości:
- konta z UID 0 — każde konto z UID 0 inne niż root stanowi krytyczne zagrożenie bezpieczeństwa
- konta bez hasła — wpisy z pustym polem hasła lub polem zawierającym
!w pliku/etc/shadow - wygasłe, ale nadal aktywne konta — dane wyjściowe
chage -lmożna analizować zbiorczo - użytkownicy z powłokami, ale bez katalogów domowych — błędna konfiguracja uniemożliwiająca logowanie
Wygenerowanie ustrukturyzowanego raportu i wysłanie go pocztą elektroniczną do zespołu bezpieczeństwa jest proste za pomocą mail lub przez dopisywanie danych do monitorowanej ścieżki dziennika.
#!/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"Blokowanie, odblokowywanie i usuwanie kont
Proces odejścia użytkownika jest równie ważny jak jego wdrożenie. Gdy użytkownik odchodzi, właściwa kolejność działań jest następująca:
- Natychmiast zablokować konto (
usermod -L) — polecenie dodaje!przed skrótem hasła w pliku shadow, uniemożliwiając logowanie bez usuwania danych - Odebrać uprawnienia sudo — usunąć fragment sudoers użytkownika, jeśli taki istnieje
- Przekazać własność jego plików przełożonemu lub kontu archiwizacyjnemu
- Zarchiwizować katalog domowy jako archiwum tar przed usunięciem
- Usunąć konto za pomocą
userdel -r— polecenie usuwa katalog domowy i skrzynkę pocztową
usermod -U odblokowuje konto (usuwa prefiks !), co jest przydatne przy tymczasowym zawieszeniu konta.
#!/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"Testowanie skryptu w trybie symulacji
Produkcyjne skrypty tworzenia kont muszą umożliwiać testowanie bez skutków ubocznych. Należy zaimplementować tryb symulacji za pomocą flagi DRY_RUN, która zastępuje wszystkie polecenia modyfikujące atrapami echo.
Wzorzec jest prosty: należy zdefiniować funkcję pomocniczą run(), która w zależności od flagi wykonuje polecenie albo je wyświetla. Takie podejście oznacza, że:
- podczas testów wykonywana jest każda ścieżka kodu
- dane wyjściowe pokazują dokładnie, co wydarzyłoby się podczas rzeczywistego uruchomienia
- potoki CI mogą sprawdzać logikę bez dostępu do uprawnień administratora
Tryb symulacji warto uzupełnić specjalnym prefiksem użytkowników testowych (np. test_), który ułatwia sprzątanie po testach integracyjnych.
#!/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 || trueKtórego polecenia należy użyć, aby dodać użytkownika do grupy dodatkowej bez usuwania istniejących członkostw?
W skrypcie zbiorczego tworzenia kont należy przypisać istniejącego użytkownika do grupy auditors. Użytkownik jest już członkiem grup developers i staff. Które polecenie zachowa wszystkie istniejące członkostwa i jednocześnie doda nowe?
Podsumowanie lekcji: automatyzacja tworzenia kont użytkowników i grup
W tej lekcji zbudowali Państwo kompletny, gotowy do użycia w środowisku produkcyjnym zestaw narzędzi do tworzenia kont użytkowników. Najważniejsze wnioski:
- Bezpiecznie analizować dane wejściowe — używać pętli z
IFS/read, pomijać puste wiersze i komentarze oraz sprawdzać pola przed każdym wywołaniem systemowym - Najważniejsze elementy
useradd— zawsze używać-m(katalog domowy),-s(powłoka),-c(komentarz) i-G(grupy); najpierw sprawdzać istnienie za pomocąid, aby zapewnić idempotencję - Hasła — ustawiać za pośrednictwem standardowego wejścia
chpasswd, aby tekst jawny nie trafiał do argumentów procesu; wymuszać zmianę przy pierwszym logowaniu za pomocąchage -d 0 chagedo egzekwowania zasad — ujednolicać maksymalny okres ważności (-M), liczbę dni ostrzegania (-W) i blokadę z powodu nieaktywności (-I) dla wszystkich kont niebędących kontami systemowymi- Członkostwo w grupach — używać
gpasswd -alubusermod -aG(z flagą-a), aby dodawać członkostwa zamiast je zastępować - Fragmenty drop-in sudoers — zapisywać je w
/etc/sudoers.d/, sprawdzać za pomocąvisudo -c -fprzed instalacją i ustawiać uprawnienia0440 root:root - Proces odejścia użytkownika — zablokować konto (
usermod -L), zarchiwizować katalog domowy, a następnie usunąć konto; nigdy nie pomijać archiwizacji - Tryb symulacji — opakować polecenia modyfikujące w funkcję pomocniczą
run(), aby potoki mogły sprawdzać logikę bez skutków ubocznych wymagających uprawnień administratora
Połączenie tych wzorców zapewnia powtarzalną, możliwą do audytowania i bezpieczną warstwę automatyzacji zarządzania tożsamością w systemie Linux, niezależnie od skali.
Często zadawane pytania
Czy lekcja „Automatyzacja tworzenia użytkowników i grup” jest bezpłatna?
Tak — pełny tekst „Automatyzacja tworzenia użytkowników i grup” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu DevOps Bootcamp, przejdź na CoddyKit PRO. Kurs DevOps Bootcamp zawiera 4 lekcji w sumie.
Co nauczysz się w „Automatyzacja tworzenia użytkowników i grup”?
Twórz, modyfikuj i kontroluj zbiorczo konta, używając useradd, chage oraz zarządzania fragmentami sudoers. Ćwiczysz DevOps Bootcamp z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć DevOps Bootcamp?
Nie wymagamy żadnego doświadczenia. DevOps Bootcamp w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Automatyzacja tworzenia użytkowników i grup”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji DevOps Bootcamp?
Tak. Każda lekcja DevOps Bootcamp zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Automatyzacja tworzenia użytkowników i grup
- Sterowanie usługami systemd i pisanie plików jednostek
- Automatyzacja dysków, systemów plików i montowania
- Tworzenie skryptów do kontroli kondycji systemu i alertów