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/zshUse 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"
doneCriando 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"
fiDefinindo 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 randou/dev/urandom, exibi-la uma vez e exigir que o usuário a altere no primeiro login - Definir uma senha previamente derivada usando
usermod -pcom 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"
doneGerenciamento 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_FILEcom 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
0440e o proprietário comoroot: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 -lpode 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 é:
- Bloquear a conta imediatamente (
usermod -L) — adiciona!ao início do hash da senha no shadow, impedindo o login sem excluir os dados - Revogar o sudo — remover o fragmento do sudoers, caso exista
- Transferir a propriedade dos arquivos para um gerente ou uma conta de arquivamento
- Arquivar o diretório pessoal como um arquivo tar antes da exclusão
- 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 || trueQual 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 comidpara garantir a idempotência - Senhas — defina-as pela entrada padrão do
chpasswdpara manter o texto simples fora dos argumentos do processo; exija a redefinição no primeiro login comchage -d 0 chagepara 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 -aouusermod -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 comvisudo -c -fantes da instalação e defina as permissões0440 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
- Automação do provisionamento de usuários e grupos
- Controle de serviços do systemd e criação de arquivos de unidade
- Automação de discos, sistemas de arquivos e montagem
- Criação de scripts de verificação e alerta da integridade do sistema