0Pricing
DevOps Bootcamp · Aula

Automação do provisionamento de usuários e grupos

Crie, modifique e audite contas em massa usando useradd, chage e o gerenciamento de fragmentos do sudoers.

Automação do provisionamento de usuários e grupos é uma aula grátis de DevOps Bootcamp no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de DevOps Bootcamp, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de DevOps Bootcamp inclui 4 aulas no total.

Por que automatizar o provisionamento de usuários?

Gerenciar usuários um por vez com useradd funciona bem para algumas contas, mas ambientes empresariais normalmente incorporam dezenas ou centenas de usuários simultaneamente. Comandos manuais tornam-se propensos a erros, inconsistentes e difíceis de auditar.

A criação de scripts Bash permite:

  • Criar usuários sempre com configurações padronizadas (shell, diretório pessoal, política de senhas)
  • Ler um arquivo CSV ou de texto com os novos funcionários e provisioná-los em uma única execução
  • Registrar cada ação para manter uma trilha de auditoria para fins de conformidade
  • Integrar-se a pipelines de gerenciamento de configuração (Ansible, Chef, Jenkins)

Nesta lição, você aprenderá a criar do zero um script de provisionamento de usuários pronto para produção, abrangendo useradd, chage, usermod, gerenciamento de grupos, arquivos adicionais do sudoers e auditoria posterior à execução.

Lendo uma lista de usuários em massa

O formato de entrada canônico para provisionamento em massa é um arquivo de texto delimitado — um registro por linha. Um CSV típico pode ser semelhante a:

username,full_name,group,shell
alice,Alice Smith,developers,/bin/bash
bob,Bob Jones,ops,/bin/zsh

Use IFS e read dentro de um loop while para analisá-lo com segurança. Ignorar a linha de cabeçalho com tail -n +2 mantém a lógica limpa.

Principais práticas defensivas:

  • Remover espaços em branco no início e no fim de cada campo
  • Ignorar linhas vazias e linhas de comentário que começam com #
  • Validar se os campos obrigatórios não estão vazios antes de chamar qualquer comando do sistema
#!/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

Criando usuários com useradd

useradd é o utilitário de baixo nível que grava em /etc/passwd, /etc/shadow e /etc/group. As opções mais importantes para scripts são:

  • -m — criar o diretório pessoal
  • -s — definir o shell de login
  • -c — campo de comentário GECOS (nome completo)
  • -G — grupos suplementares (separados por vírgulas)
  • -e — data de expiração da conta (YYYY-MM-DD)

Sempre verifique se o usuário já existe com id antes de chamar useradd; executá-lo para um usuário existente retorna o código de saída 9 e exibe um erro que pode poluir os registros.

Observação: useradd exige privilégios de root. Envolva o script com uma verificação de privilégios no início.

#!/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

Definindo senhas iniciais com segurança

Nunca inclua senhas diretamente nos scripts. Duas abordagens seguras para provisionamento em massa são:

  • Gerar uma senha inicial aleatória com openssl rand ou /dev/urandom, exibi-la uma vez e exigir que o usuário a altere no primeiro login
  • Definir uma senha previamente derivada usando usermod -p com um hash SHA-512, para que o texto simples nunca apareça na lista de processos

chpasswd é a ferramenta recomendada para definir senhas em scripts — ela lê pares username:password da entrada padrão, portanto a senha nunca aparece nos argumentos da linha de comando (visíveis por meio de ps).

Depois de definir a senha, use chage -d 0 para forçar uma redefinição imediata da senha no próximo login.

#!/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"

Gerenciando o envelhecimento de senhas com chage

chage (alterar idade) controla a política de envelhecimento de senhas armazenada em /etc/shadow. As políticas de segurança empresariais normalmente exigem:

  • Idade máxima da senha (por exemplo, 90 dias)
  • Número mínimo de dias antes que uma senha possa ser alterada novamente
  • Período de aviso antes da expiração
  • Bloqueio da conta por inatividade após o último uso da senha

Principais opções de chage:

  • -M <days> — idade máxima da senha
  • -m <days> — idade mínima da senha
  • -W <days> — dias de aviso antes da expiração
  • -I <days> — dias de inatividade antes do bloqueio da conta
  • -E <date> — expiração absoluta da conta
  • -l — listar as configurações atuais de um usuário
#!/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

Gerenciamento de grupos em massa

Os grupos são o principal mecanismo para controlar o acesso aos recursos. Um script de provisionamento deve garantir que os grupos necessários existam antes de adicionar usuários a eles — useradd -G nonexistent falhará.

Use groupadd de forma idempotente, verificando o código de saída: ele retorna 9 se o grupo já existir. A expressão getent group <name> é uma alternativa portável e legível ao uso de grep em /etc/group.

gpasswd -a adiciona um usuário a um grupo sem substituir as associações existentes (ao contrário de usermod -G, que substitui a lista de grupos suplementares).

#!/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"
}

Script completo de provisionamento em massa

Reunindo tudo: um único script lê um CSV, cria usuários e grupos, define a política de senhas, registra cada ação e trata os erros adequadamente sem interromper todo o lote.

Decisões importantes de projeto no script abaixo:

  • Um LOG_FILE com marcas de tempo registra todas as operações para auditoria
  • Os erros de usuários individuais são registrados, mas não interrompem o loop (|| log_error)
  • O script é idempotente — é seguro executá-lo novamente após falhas parciais
  • Toda a saída vai tanto para o terminal quanto para o arquivo de registro por meio de 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 ==="

Gerenciamento de fragmentos adicionais do sudoers

Editar /etc/sudoers diretamente é perigoso — um erro de sintaxe impede todos de usar sudo. A abordagem segura é usar arquivos adicionais em /etc/sudoers.d/, cada um validado com visudo -c -f antes de ser colocado em seu local.

Práticas recomendadas para fragmentos do sudoers:

  • Nomeie os arquivos de acordo com a equipe ou função que eles autorizam (por exemplo, 10-developers, 20-ops)
  • Use regras baseadas em grupos (%developers ALL=(ALL) NOPASSWD: /usr/bin/systemctl) em vez de linhas específicas para cada usuário
  • Sempre defina as permissões como 0440 e o proprietário como root:root
  • Valide com visudo -c — o comando retorna um valor diferente de zero para qualquer erro de sintaxe
#!/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"

Auditando contas existentes

Após o provisionamento (e em uma programação regular), você deve auditar o banco de dados de usuários em busca de anomalias:

  • Contas com UID 0 — qualquer conta com UID 0 além de root é uma descoberta crítica de segurança
  • Contas sem senha — entradas com um campo de senha vazio ou com ! em /etc/shadow
  • Contas expiradas ainda ativas — a saída de chage -l pode ser analisada em massa
  • Usuários com shell, mas sem diretório pessoal — configuração incorreta que impede o login

Gerar um relatório estruturado e enviá-lo por e-mail à equipe de segurança é simples com mail ou acrescentando o relatório a um caminho de registro monitorado.

#!/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"

Bloqueando, desbloqueando e removendo contas

O desligamento é tão importante quanto a integração. Quando um usuário sai, a sequência correta é:

  1. Bloquear a conta imediatamente (usermod -L) — adiciona ! ao início do hash da senha no shadow, impedindo o login sem excluir os dados
  2. Revogar o sudo — remover o fragmento do sudoers, caso exista
  3. Transferir a propriedade dos arquivos para um gerente ou uma conta de arquivamento
  4. Arquivar o diretório pessoal como um arquivo tar antes da exclusão
  5. Excluir com userdel -r — remove o diretório pessoal e a fila de e-mails

usermod -U desbloqueia uma conta (remove o prefixo !), o que é útil para uma suspensão temporária.

#!/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"

Testando o script com um modo de simulação

Os scripts de provisionamento de produção devem poder ser testados sem efeitos colaterais. Implemente um modo de simulação usando uma opção DRY_RUN que substitua todos os comandos que alteram o sistema por comandos echo.

O padrão é simples: defina um auxiliar run() que execute ou exiba o comando, dependendo da opção. Essa abordagem significa que:

  • Todos os caminhos do código são exercitados durante os testes
  • A saída mostra exatamente o que aconteceria em uma execução real
  • Os pipelines de CI podem validar a lógica sem acesso root

Complemente a simulação com um prefixo de usuário de teste dedicado (por exemplo, test_) que facilite a limpeza após os testes de integração.

#!/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

Qual comando você deve usar para adicionar um usuário a um grupo suplementar sem remover as associações existentes?

Em um script de provisionamento em massa, você precisa atribuir um usuário existente ao grupo auditors. O usuário já é membro de developers e staff. Qual comando preserva todas as associações existentes ao adicionar a nova?

Recapitulação da lição: automatizando o provisionamento de usuários e grupos

Nesta lição, você criou um conjunto completo de ferramentas de provisionamento de usuários pronto para produção. Estes são os principais pontos:

  • Analisar a entrada de forma defensiva — use loops com IFS/read, ignore linhas vazias e de comentário e valide os campos antes de qualquer chamada ao sistema
  • Essenciais do useradd — use sempre -m (diretório pessoal), -s (shell), -c (comentário) e -G (grupos); verifique primeiro a existência com id para garantir a idempotência
  • Senhas — defina-as pela entrada padrão do chpasswd para manter o texto simples fora dos argumentos do processo; exija a redefinição no primeiro login com chage -d 0
  • chage para a política — padronize a idade máxima (-M), os dias de aviso (-W) e o bloqueio por inatividade (-I) em todas as contas que não sejam do sistema
  • Associação a grupos — use gpasswd -a ou usermod -aG (com a opção -a) para acrescentar, em vez de substituir, as associações
  • Arquivos adicionais do sudoers — grave em /etc/sudoers.d/, valide com visudo -c -f antes da instalação e defina as permissões 0440 root:root
  • Desligamento — bloqueie (usermod -L), arquive o diretório pessoal e depois exclua; nunca pule a etapa de arquivamento
  • Modo de simulação — envolva os comandos que alteram o sistema em um auxiliar run() para que os pipelines possam verificar a lógica sem efeitos colaterais que exijam root

A combinação desses padrões oferece uma camada de automação repetível, auditável e segura para o gerenciamento de identidades Linux em qualquer escala.

Perguntas Frequentes

A aula “Automação do provisionamento de usuários e grupos” é grátis?

Sim — o texto completo de “Automação do provisionamento de usuários e grupos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de DevOps Bootcamp, atualize para CoddyKit PRO. O curso de DevOps Bootcamp inclui 4 aulas no total.

O que vou aprender em “Automação do provisionamento de usuários e grupos”?

Crie, modifique e audite contas em massa usando useradd, chage e o gerenciamento de fragmentos do sudoers. Você pratica DevOps Bootcamp com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar DevOps Bootcamp?

Nenhuma experiência prévia é necessária. DevOps Bootcamp no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Automação do provisionamento de usuários e grupos”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de DevOps Bootcamp?

Sim. Cada aula de DevOps Bootcamp inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Automação do provisionamento de usuários e grupos
  2. Controle de serviços do systemd e criação de arquivos de unidade
  3. Automação de discos, sistemas de arquivos e montagem
  4. Criação de scripts de verificação e alerta da integridade do sistema
← Voltar para DevOps Bootcamp