A ilusão do `sshd_config`: como realmente garantir a segurança da autenticação SSH no cPanel/CloudLinux
Voltar para blog

A ilusão do `sshd_config`: como realmente garantir a segurança da autenticação SSH no cPanel/CloudLinux

07/06/2026 · 4 min · Infraestrutura

A ilusão do sshd_config: como realmente garantir a segurança da autenticação SSH no cPanel/CloudLinux#

Quem trabalha na trincheira da administração de sistemas de alto nível (SysAdmin / SRE) sabe que o dia a dia é repleto de falsas sensações de segurança. Recentemente, liderei uma auditoria de hardening (Evento de origem: #3104798) em nossos servidores cPanel executando CloudLinux. O objetivo era elementar: desativar a autenticação por senha (PasswordAuthentication no) e forçar o uso exclusivo de chaves criptográficas SSH.

O que parecia ser uma simples alteração de configuração revelou uma inconsistência brutal entre o que está declarado no arquivo /etc/ssh/sshd_config e a realidade operacional do daemon SSH em execução.

Quando o arquivo e as APIs enganam você#

Inicialmente, as alterações de configuração foram disparadas usando os utilitários de linha de comando nativos do cPanel via WHM API 1 (whmapi1):

# 1. Verificar a configuração do SSHD registrada pelo WHM
whmapi1 listsshdconfig

# 2. Desabilitar a autorização de senhas via API do WHM
whmapi1 setserviceconfig service=sshd key=PasswordAuthentication value=no

O Problema Técnico: Embora a chamada retorne sucesso e o arquivo principal /etc/ssh/sshd_config reflita a alteração, o servidor pode continuar aceitando conexões de senha. Isso ocorre devido a três fatores do ecossistema:

  1. Arquivos Drop-in (sshd_config.d/): Versões modernas do OpenSSH carregam de forma modular os arquivos contidos em /etc/ssh/sshd_config.d/*.conf. Se um arquivo (como 50-cloudlinux.conf ou diretrizes injetadas por provedores de cloud no bootstrap) declarar PasswordAuthentication yes, essa instrução sobrescreve a diretiva declarada no /etc/ssh/sshd_config principal dependendo da ordem do Include.
  2. Injeção via Cloud-Init: Serviços de provisionamento de nuvem reescrevem diretivas no boot, restaurando a autenticação por senha silenciosamente.
  3. Limitações da API WHM: O whmapi1 edita o arquivo básico, mas muitas vezes falha em varrer os drop-ins conflitantes ou reiniciar o serviço com o sinal de recarga (SIGHUP) adequado.

Como encontrar arquivos drop-in conflitantes#

Para auditar se existem arquivos de configuração ocultos interferindo nas regras globais do SSH:

# Listar todos os arquivos drop-in ativos
ls -la /etc/ssh/sshd_config.d/

# Buscar pela diretiva de autenticação em todos os arquivos de configuração do SSH
grep -r -i "PasswordAuthentication" /etc/ssh/sshd_config.d/

# Verificar a declaração da diretiva Include no arquivo principal
grep -i "^Include" /etc/ssh/sshd_config

# Script rápido para mapear os arquivos e seus valores declarados
for f in /etc/ssh/sshd_config.d/*.conf; do
    echo "=== Arquivo: $f ==="
    grep -i "PasswordAuthentication" "$f" 2>/dev/null || echo "(diretiva ausente)"
done

Procedimento de correção passo a passo#

Caso você identifique discrepâncias, siga o fluxo seguro de correção abaixo:

1. Backup de segurança obrigatório#

Antes de salvar qualquer alteração no daemon SSH, faça cópias de segurança de toda a árvore de configurações para evitar quebras graves que impeçam o acesso ao servidor:

# Backup do arquivo principal
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)

# Backup do diretório drop-in
sudo cp -r /etc/ssh/sshd_config.d/ /root/sshd_config.d.bak.$(date +%Y%m%d)/

# Backup unificado em tarball
sudo tar czf /root/ssh-backup-$(date +%Y%m%d).tar.gz /etc/ssh/

2. Configuração de chaves SSH (máquina local para o servidor)#

Antes de banir senhas, certifique-se de que sua chave pública está devidamente autorizada no servidor.

No seu computador pessoal (cliente):

# Gerar par de chaves usando o algoritmo seguro ED25519
ssh-keygen -t ed25519 -C "[email protected]"

# Copiar a chave pública gerada para o servidor remoto
ssh-copy-id -p 22 usuario@ip-do-servidor

Teste o login sem senha abrindo um terminal de testes:

ssh -p 22 usuario@ip-do-servidor

3. Limpeza de drop-ins e configurações conflitantes#

Acesse o servidor como root. Se encontrar ocorrências de PasswordAuthentication yes nos diretórios drop-in, edite-os definindo o valor correto ou remova-os se forem lixo redundante:

# Alterar todas as ocorrências de PasswordAuthentication nos drop-ins para "no"
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true

No arquivo principal /etc/ssh/sshd_config, garanta a desativação:

sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config

4. Hardening adicional de segurança do SSHD#

Aproveite para garantir que outras diretrizes essenciais de segurança estejam ativas:

# Desabilitar login direto do root por senha
PermitRootLogin prohibit-password

# Forçar autenticação por chave pública
PubkeyAuthentication yes

# Desativar autenticação interativa de teclado que burla o PasswordAuthentication
ChallengeResponseAuthentication no

# Limitar tentativas de login inválido por conexão
MaxAuthTries 3

# Tempo de tolerância para finalizar a autenticação
LoginGraceTime 30

5. Validação de sintaxe#

Nunca reinicie o serviço SSH sem validar a integridade da sintaxe:

sudo sshd -t

Se este comando retornar qualquer erro de configuração, não reinicie o SSH! Investigue a linha apontada no log.

6. Teste seguro em sessão separada (prevenção de lockout)#

Regra de Ouro do SysAdmin: Nunca feche a sessão SSH ativa atual. Com a sessão atual aberta, abra um novo terminal em sua máquina e execute o seguinte teste de conexão simulada:

# Forçar uma conexão de teste rápida via chave pública
ssh -o "BatchMode=yes" -o "ConnectTimeout=5" usuario@ip-do-servidor echo "Conexão Segura OK"

Se a resposta for "Conexão Segura OK", o seu acesso por chave está funcionando perfeitamente.

7. Aplicação e reinicialização do daemon#

Agora sim, reinicie o SSH para carregar a nova configuração em memória:

sudo systemctl restart sshd

Validando o estado efetivo em memória (one-liner correto)#

A forma definitiva de auditar o servidor é interrogar o daemon carregado em memória usando o utilitário sshd -T (modo de teste estendido). Ele resolve todos os includes recursivos de arquivos .conf e imprime o estado final operacional.

Use o one-liner Bash correto abaixo para validação:

# Validar se o PasswordAuthentication está desligado de fato
sshd -T | grep -qi '^passwordauthentication no$' && echo "CONFORME: Senhas desabilitadas." || echo "ATENÇÃO: Senhas ainda habilitadas!"

Para listar os parâmetros reais do SSHD associados à segurança:

sshd -T | grep -iE "^(passwordauthentication|pubkeyauthentication|permitrootlogin|challengeresponseauthentication|usepam)"

Verificação de logs do SSH#

Para certificar-se de que ataques de força bruta de senhas estão sendo bloqueados e depurar logins, monitore os logs de autenticação do sistema (/var/log/auth.log em distros Debian/Ubuntu ou /var/log/secure em RHEL/CloudLinux):

# Monitorar logs de autenticação do SSH em tempo real
tail -f /var/log/secure | grep sshd

# Listar as últimas 20 tentativas de login inválidas ou usuários inexistentes
sudo grep -i "failed\|invalid" /var/log/secure | tail -20

# Verificar conexões bem-sucedidas por chaves públicas
sudo grep -i "accepted publickey" /var/log/secure | tail -20

Procedimento de rollback de emergência#

Se por acaso você perder acesso ou o serviço SSH falhar na inicialização, acesse a VPS por meio do terminal de console de emergência do provedor (VNC/IPMI) e reverta a configuração:

# 1. Limpar arquivos de configuração do SSH modificados
sudo rm -rf /etc/ssh/sshd_config.d/
sudo rm -f /etc/ssh/sshd_config

# 2. Restaurar backups criados no início do procedimento
sudo cp /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config
sudo cp -r /root/sshd_config.d.bak.*/ /etc/ssh/sshd_config.d/

# 3. Validar sintaxe
sudo sshd -t

# 4. Iniciar o serviço
sudo systemctl restart sshd

Script de auditoria SSH completo#

Abaixo está o script completo para validação automática de conformidade SSH:

audit-ssh.sh — Script de auditoria avançada SSH
Gist ↗Ver código
#!/bin/bash
# audit-ssh.sh - Auditoria avançada de conformidade e segurança SSH

set -euo pipefail

# 0. Checagem e elevação de privilégios para leitura das configurações e chaves do SSH
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
    echo "⚠️  Aviso: Este script requer privilégios de root para inspecionar as chaves do host e drop-ins (/etc/ssh/)."
    if command -v sudo >/dev/null 2>&1; then
        echo "    Elevando execução com sudo..."
        exec sudo bash "$0" "$@"
    else
        echo "❌ Erro: sudo indisponível e usuário não é root. Execute como root." >&2
        exit 1
    fi
fi

echo "=== INICIANDO AUDITORIA SSH ==="
echo ""

# 1. Estado Efetivo em Memória
echo "[1] Verificando Parâmetros Efetivos (sshd -T):"
if SSHD_OUT=$(sshd -T 2>&1); then
    PASS_AUTH=$(echo "$SSHD_OUT" | grep -i "^passwordauthentication" | awk '{print $2}' || echo "desconhecido")
    if [ "$PASS_AUTH" = "no" ]; then
        echo "    ✅ PasswordAuthentication: NO (Seguro)"
    else
        echo "    ❌ PasswordAuthentication: $PASS_AUTH (Inseguro - Aceita senha)"
    fi

    ROOT_LOGIN=$(echo "$SSHD_OUT" | grep -i "^permitrootlogin" | awk '{print $2}' || echo "desconhecido")
    if [ "$ROOT_LOGIN" = "no" ] || [ "$ROOT_LOGIN" = "prohibit-password" ]; then
        echo "    ✅ PermitRootLogin: $ROOT_LOGIN (Seguro)"
    else
        echo "    ⚠️ PermitRootLogin: $ROOT_LOGIN (Inseguro - Recomenda-se desabilitar root por senha)"
    fi

    CHALLENGE=$(echo "$SSHD_OUT" | grep -i "^challengeresponseauthentication" | awk '{print $2}' || echo "desconhecido")
    if [ "$CHALLENGE" = "no" ]; then
        echo "    ✅ ChallengeResponseAuthentication: NO (Seguro)"
    else
        echo "    ⚠️ ChallengeResponseAuthentication: $CHALLENGE (Risco de bypass de senha via PAM)"
    fi
else
    echo "    ❌ Falha ao executar sshd -T:"
    echo "$SSHD_OUT" | sed 's/^/       /'
fi

# 2. Drop-ins e Conflitos em sshd_config.d/
echo ""
echo "[2] Verificando Arquivos Drop-in e Includes:"
DROPINS_COUNT=$(find /etc/ssh/sshd_config.d/ -maxdepth 1 -type f -name "*.conf" 2>/dev/null | wc -l | tr -d ' ' || echo 0)
echo "    Total de drop-ins ativos: $DROPINS_COUNT"

CONFLICT_LINES=$(grep -rnEI '^[[:space:]]*PasswordAuthentication' /etc/ssh/sshd_config.d/ 2>/dev/null || true)
if [ -n "$CONFLICT_LINES" ]; then
    CONFLICTS=$(echo "$CONFLICT_LINES" | wc -l | tr -d ' ')
    echo "    ⚠️ Encontrados $CONFLICTS conflitos de PasswordAuthentication nos drop-ins:"
    echo "$CONFLICT_LINES" | sed 's/^/       /'
else
    echo "    ✅ Nenhum conflito de diretiva de senha em drop-ins."
fi

echo ""
echo "=== AUDITORIA CONCLUÍDA ==="

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