0Pricing
DevOps Bootcamp · Lekcja

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/zsh

Proszę 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"
done

Tworzenie 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"
fi

Bezpieczne 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 rand lub /dev/urandom, wyświetlenie go jeden raz i wymuszenie zmiany przy pierwszym logowaniu
  • Ustawienie hasła w postaci gotowego skrótu za pomocą usermod -p z 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"
done

Zbiorcze 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_FILE ze 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ę na root: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 -l moż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:

  1. Natychmiast zablokować konto (usermod -L) — polecenie dodaje ! przed skrótem hasła w pliku shadow, uniemożliwiając logowanie bez usuwania danych
  2. Odebrać uprawnienia sudo — usunąć fragment sudoers użytkownika, jeśli taki istnieje
  3. Przekazać własność jego plików przełożonemu lub kontu archiwizacyjnemu
  4. Zarchiwizować katalog domowy jako archiwum tar przed usunięciem
  5. 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 || true

Któ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
  • chage do 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 -a lub usermod -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 -f przed instalacją i ustawiać uprawnienia 0440 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

  1. Automatyzacja tworzenia użytkowników i grup
  2. Sterowanie usługami systemd i pisanie plików jednostek
  3. Automatyzacja dysków, systemów plików i montowania
  4. Tworzenie skryptów do kontroli kondycji systemu i alertów
← Powrót do DevOps Bootcamp