Onde as ACLs de revendedores ficam salvas no WHM: análise técnica, source of truth e troubleshooting em produção
Voltar para blog

Onde as ACLs de revendedores ficam salvas no WHM: análise técnica, source of truth e troubleshooting em produção

07/06/2026 · 4 min · Infraestrutura

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:

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:

  1. ACL foi criada em Edit Reseller Nameservers and Privileges.
  2. Nome da ACL foi informado no campo de nova lista.
  3. A GUI mostrou feedback parcial de sucesso.
  4. 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:

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:

  1. Selecionar todas as permissões da ACL alvo.
  2. Informar nome da nova ACL.
  3. Finalizar obrigatoriamente com Save All Settings.
  4. Aguardar refresh completo da página.
  5. 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:


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#

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:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários