Em operação com cPanel/WHM, controle de privilégios de revendedor é um ponto de segurança de primeira linha. O problema é que a interface nem sempre reflete, de forma imediata e consistente, o estado real em disco.
Neste artigo, documento um incidente real onde uma ACL nomeada criada pela GUI não persistia como esperado, além do fluxo técnico que usei para diagnosticar, validar e padronizar a criação dessas ACLs com confiabilidade operacional.
⚠️ Backup obrigatório antes de qualquer mudança#
# Backup do arquivo de resellers com timestamp
cp -p /var/cpanel/resellers /var/cpanel/resellers.$(date +%F-%H%M%S).bak
# Verificar que o backup foi criado e tem o mesmo tamanho
ls -lh /var/cpanel/resellers /var/cpanel/resellers.*.bak 2>/dev/null | tail -5
# Backup completo do diretório cPanel (para janelas de manutenção críticas)
tar czf /root/cpanel-backup-$(date +%Y%m%d-%H%M).tar.gz /var/cpanel/
echo "Backup criado: $(ls -lh /root/cpanel-backup-*.tar.gz | tail -1)"
1) Anatomia das ACLs no WHM#
No contexto de revenda, o cPanel trabalha com dois modelos:
- ACL ad hoc por usuário revendedor.
- ACL nomeada (template reutilizável para múltiplos revendedores).
As permissões representam capacidades operacionais como criação de contas, gestão DNS, SSL, quotas, entre outras.
2) Source of truth: onde fica salvo#
Na prática de campo, o ponto central para ACL de revendedores é:
/var/cpanel/resellers
Validação direta:
cat /var/cpanel/resellers
Cada linha representa associação de privilégios para usuário/template, com flags separadas por vírgula. Quando a ACL não aparece nesse arquivo, a persistência não foi concluída no backend.
Verificação completa de permissões do arquivo#
# Verificar permissões detalhadas (forma legível)
ls -la /var/cpanel/resellers
# Verificar owner, group e modo octal (formato compacto)
stat -c "%U:%G %a %n" /var/cpanel/resellers
# Saída esperada: root:root 644 /var/cpanel/resellers
# Verificar versão do WHM antes de qualquer operação
cat /usr/local/cpanel/version
# Se permissões estiverem incorretas, corrigir:
sudo chown root:root /var/cpanel/resellers
sudo chmod 644 /var/cpanel/resellers
# Validar correção:
stat -c "%U:%G %a %n" /var/cpanel/resellers
Validação de sintaxe do arquivo#
# Verificar linhas em branco (não devem existir)
grep -c "^$" /var/cpanel/resellers
# Saída esperada: 0
# Verificar caracteres especiais indesejados
cat -A /var/cpanel/resellers | grep -vE "^[a-zA-Z0-9,=:/_\.\-]+\$$"
# Saída esperada: nenhuma linha (arquivo limpo)
# Exibir as primeiras 20 linhas para inspeção visual
head -20 /var/cpanel/resellers
3) Sintoma observado: ACL "sumindo" após criação#
No caso real:
- ACL foi criada em
Edit Reseller Nameservers and Privileges. - Nome da ACL foi informado no campo de nova lista.
- A GUI mostrou feedback parcial de sucesso.
- Após refresh/reabertura, ACL não estava disponível para reaplicação.
No backend, a entrada também não estava consolidada no /var/cpanel/resellers.
4) Causa operacional mais comum#
Falha de commit no fluxo da interface, geralmente quando:
- a lista é nomeada, mas o operador não finaliza com o botão principal de persistência;
- o fluxo de página não completa refresh final;
- sessão/latência causa estado inconsistente entre UI e gravação real.
Em outras palavras: salvar nome da lista sem concluir o commit global pode não materializar a ACL no estado final do servidor.
5) Checklist de diagnóstico senior (SSH)#
Quando houver suspeita de ACL fantasma, execute:
5.1 estado via API#
whmapi1 listacls --output=jsonpretty
Se a ACL nomeada não aparece no retorno, considere não persistida.
5.2 verificar conflitos de ACL#
# Listar todas as ACLs nomeadas existentes
whmapi1 listacls --output=jsonpretty | jq -r '.data.acllists[].acllist'
# Detectar ACLs duplicadas (não deveria haver)
whmapi1 listacls --output=jsonpretty | jq -r '.data.acllists[].acllist' | sort | uniq -d
# Saída esperada: vazia (sem duplicatas)
# Inspecionar conteúdo de uma ACL específica (ex: jvx_n1)
whmapi1 listacls --output=jsonpretty | jq '.data.acllists[] | select(.acllist=="jvx_n1")'
# Verificar se uma permissão específica está habilitada na ACL
whmapi1 listacls --output=jsonpretty | \
jq '.data.acllists[] | select(.acllist=="jvx_n1") | {"acl-list-accts": .["acl-list-accts"], "acl-ssl": .["acl-ssl"]}'
5.3 busca de referência no diretório cPanel#
grep -R "nome_da_acl" /var/cpanel/
Útil para confirmar se houve rastro parcial em arquivos auxiliares.
5.4 integridade básica do arquivo#
ls -l /var/cpanel/resellers
stat /var/cpanel/resellers
Verificar owner, group e modo. Em ambiente padrão, manter controle estrito com root e permissões consistentes.
5.5 verificar versão do WHM#
# Versão do cPanel/WHM instalada
cat /usr/local/cpanel/version
# Verificar se há atualização disponível
/usr/local/cpanel/scripts/upcp --status
# Verificar versão específica do cpanel
cat /usr/local/cpanel/cpanel.version 2>/dev/null || echo "Arquivo de versão não encontrado"
5.6 logs do WHM para diagnóstico#
# Erros recentes do WHM
tail -100 /usr/local/cpanel/logs/error_log
# Log de acesso à API e interface
tail -100 /usr/local/cpanel/logs/access_log
# Log principal do cPanel
tail -100 /usr/local/cpanel/logs/cpanel.log
# Filtrar apenas erros e falhas dos últimos logs
grep -iE "error|fail|denied" /usr/local/cpanel/logs/error_log | tail -20
5.7 verificar conectividade da API WHM#
# Teste básico da API (deve retornar versão do WHM)
whmapi1 version
# Verificar se a porta WHM está aberta e em escuta
ss -lntp | grep -E "2083|2087"
# Saída esperada: 0.0.0.0:2087 e/ou 0.0.0.0:2083 com LISTEN
# Testar via curl (usando accesshash)
curl -sk "https://localhost:2087/execute/version" \
-H "Authorization: whm root:$(cat /root/.accesshash 2>/dev/null | tr -d '\n')" \
| python3 -m json.tool 2>/dev/null | grep version
6) Fluxo correto via GUI (quando usar interface)#
Fluxo seguro que adotei:
- Selecionar todas as permissões da ACL alvo.
- Informar nome da nova ACL.
- Finalizar obrigatoriamente com Save All Settings.
- Aguardar refresh completo da página.
- Revalidar por API (
listacls) e por arquivo (cat /var/cpanel/resellers).
Sem essa validação pós-save, você opera no escuro.
7) Fluxo recomendado para produção: WHM API 1#
Para previsibilidade e automação, padronizei criação por CLI/API:
whmapi1 saveacllist \
acllist=jvx_n1 \
acl-list-accts=1 \
acl-park-dns=1 \
acl-ssl=1 \
acl-wp-toolkit=1
Depois, aplicar em usuário revendedor:
whmapi1 setacls reseller=usuario_exemplo acllist=jvx_n1
Esse caminho reduz erro humano e remove dependência de estado da GUI.
8) Verificação do revendedor e análise de impacto#
Antes de alterar ACLs, valide o escopo da mudança:
# Listar todos os revendedores cadastrados
whmapi1 listresellers --output=jsonpretty | jq -r '.data.resellers[].reseller'
# Verificar se um revendedor específico existe
whmapi1 listresellers --output=jsonpretty | \
jq '.data.resellers[] | select(.reseller=="usuario_exemplo")'
# Saída vazia = revendedor não existe
# Verificar detalhes de um revendedor (ACL aplicada, quotas)
whmapi1 listresellers user=usuario_exemplo --output=jsonpretty
# Análise de impacto: quais revendedores usam a ACL que será alterada?
whmapi1 listresellers --output=jsonpretty | \
jq -r '.data.resellers[] | select(.acllist=="jvx_n1") | .reseller'
# Liste TODOS antes de alterar a ACL nomeada
# Detectar revendedores sem ACL aplicada (risco de permissão padrão)
whmapi1 listresellers --output=jsonpretty | \
jq '.data.resellers[] | select(.acllist=="" or .acllist==null) | .reseller'
9) Validação pós-aplicação (obrigatória)#
Após saveacllist + setacls, validar:
whmapi1 listacls --output=jsonpretty
whmapi1 listresellers --output=jsonpretty
grep -R "jvx_n1" /var/cpanel/resellers
E, quando necessário, testar comportamento efetivo com login do revendedor:
- checar se menus proibidos não aparecem;
- confirmar que operações permitidas executam sem erro de ACL.
10) Boas práticas de segurança e operação#
10.1 backup antes de qualquer mudança#
cp -p /var/cpanel/resellers /var/cpanel/resellers.$(date +%F-%H%M%S).bak
10.2 evitar edição manual direta#
Embora possível, editar /var/cpanel/resellers manualmente aumenta risco de sintaxe inválida e efeitos colaterais em múltiplos revendedores.
10.3 tratar ACL como código operacional#
- manter catálogo de ACLs nomeadas;
- versionar comandos
whmapi1 saveacllistem repositório interno; - usar runbook de validação pós-change.
10.4 auditoria de mudanças#
Registrar quem criou/alterou ACL, horário e finalidade operacional. Em incidentes de permissão indevida, essa trilha reduz MTTR.
11) Runbook rápido para incidente de ACL fantasma#
# 1) verificar se ACL existe de fato
whmapi1 listacls --output=jsonpretty | grep -i "jvx_n1"
# 2) confirmar estado em disco
grep -R "jvx_n1" /var/cpanel/resellers
# 3) recriar ACL por API (idempotência operacional)
whmapi1 saveacllist acllist=jvx_n1 acl-list-accts=1 acl-park-dns=1 acl-ssl=1 acl-wp-toolkit=1
# 4) reaplicar ao revendedor
whmapi1 setacls reseller=usuario_exemplo acllist=jvx_n1
# 5) validar novamente
whmapi1 listacls --output=jsonpretty | grep -i "jvx_n1"
12) Checklist consolidado de gerenciamento de ACLs#
Fase 1 - pré-mudança#
- [ ] Backup: `cp -p /var/cpanel/resellers /var/cpanel/resellers.$(date +%F-%H%M%S).bak`
- [ ] Verificar versão WHM: `cat /usr/local/cpanel/version`
- [ ] Verificar permissões do arquivo: `stat -c "%U:%G %a %n" /var/cpanel/resellers`
- [ ] Verificar conectividade da API: `whmapi1 version`
- [ ] Listar ACLs existentes: `whmapi1 listacls --output=jsonpretty`
- [ ] Confirmar que o revendedor existe: `whmapi1 listresellers user=USUARIO`
- [ ] Analisar impacto: quais revendedores usam a ACL alvo?
Fase 2 - criar ACL#
- [ ] Criar via API: `whmapi1 saveacllist acllist=NOME acl-list-accts=1 ...`
- [ ] Verificar criação: `whmapi1 listacls | jq '.data.acllists[] | select(.acllist=="NOME")'`
- [ ] Confirmar em disco: `grep NOME /var/cpanel/resellers`
- [ ] Verificar ausência de duplicatas: `whmapi1 listacls | jq -r '.data.acllists[].acllist' | sort | uniq -d`
Fase 3 - aplicar ACL#
- [ ] Aplicar ao revendedor: `whmapi1 setacls reseller=USUARIO acllist=NOME`
- [ ] Verificar aplicação: `whmapi1 listresellers user=USUARIO --output=jsonpretty`
Fase 4 - validação#
- [ ] Verificar permissões da ACL via jq
- [ ] Testar login do revendedor
- [ ] Confirmar menus/opções disponíveis (proibidos ausentes, permitidos funcionando)
- [ ] Verificar logs por erros: `grep -iE "error|fail" /usr/local/cpanel/logs/error_log | tail -20`
Fase 5 - pós-mudança#
- [ ] Documentar alteração (quem, o quê, quando, por quê)
- [ ] Notificar equipe se impacto em múltiplos revendedores
- [ ] Monitorar logs por 24h após mudança crítica
Considerações práticas#
Quando ACL "desaparece" no WHM, o problema quase sempre é persistência incompleta no fluxo da interface, não ausência de funcionalidade do backend.
O ponto-chave é tratar /var/cpanel/resellers como fonte da verdade operacional e adotar API (saveacllist/setacls) como padrão de produção. Isso aumenta previsibilidade, reduz erro manual e mantém governança de acesso em nível profissional. O backup antes de qualquer operação e a análise de impacto em outros revendedores completam o runbook de um SRE sênior.
Este artigo foi útil?
Deixe uma reação rápida para apoiar o conteúdo:
Este post está licenciado sob CC BY-NC.



Comentários
Participe da discussão abaixo.
0 comentários