Entendendo o Hardening de SSH e por que é Crítico
O SSH (Secure Shell) é o protocolo padrão para administração remota de servidores, mas também é um dos alvos mais comuns de ataques em infraestruturas conectadas à internet. Um servidor com SSH mal configurado pode ser comprometido em horas, não dias. O hardening de SSH consiste em aplicar um conjunto de práticas e configurações que reduzem significativamente a superfície de ataque, eliminando vulnerabilidades conhecidas e fechando comportamentos padrão perigosos.
A maioria dos ataques contra SSH exploram configurações fracas: uso de senhas frágeis, permissão de login root direto, portas padrão que facilitam scanning, ou ausência de autenticação multifator. Quando você implementa hardening corretamente, você não apenas torna o servidor mais seguro, mas também reduz o ruído de tentativas de força bruta nos logs, facilitando a detecção de ataques reais. Este artigo vai te guiar pelas três camadas essenciais: configurações seguras do daemon SSH, autenticação baseada em certificados e o padrão de acesso através de Bastion Host.
Configurações Seguras do SSH: O Arquivo sshd_config
O arquivo /etc/ssh/sshd_config é a base de todo hardening SSH. Cada linha que você adiciona ou modifica aqui representa uma decisão de segurança. Vou mostrar as configurações que realmente fazem diferença, não as que aparecem em checklists genéricos.
Desabilitando Autenticação por Senha
A autenticação por senha é o ponto fraco mais óbvio. Ela permite força bruta, é vulnerável a phishing quando usada em contextos de VPN, e não deixa auditoria clara de quem fez o quê. Substitua-a por autenticação baseada em chave pública desde o início.
# /etc/ssh/sshd_config
# Desabilita autenticação por senha completamente
PasswordAuthentication no
# Desabilita autenticação por teclado interativo (que simula senha)
KbdInteractiveAuthentication no
# Mantém apenas autenticação por chave pública
PubkeyAuthentication yes
# Define onde procurar as chaves autorizadas do usuário
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
Após essa mudança, qualquer tentativa de login sem chave privada será rejeitada na camada de protocolo. Isso elimina instantaneamente 99% dos ataques de força bruta que você vê nos logs.
Restrições de Acesso e Portas
Executar SSH na porta padrão 22 é como deixar a porta da frente da sua casa aberta durante o dia. Mudanças simples aqui reduzem significativamente o ruído de scanning:
# /etc/ssh/sshd_config
# Muda para uma porta acima de 1024 (não requer root)
Port 2222
# Escuta apenas em uma interface específica, não em todas
ListenAddress 10.0.1.50
# Define qual versão do protocolo aceitar (SSH2 é obrigatório hoje)
Protocol 2
# Rejeita conexões muito rápidas da mesma origem (rate limiting)
StartupTimeout 120
LoginGraceTime 30
# Número máximo de tentativas de autenticação antes de desconectar
MaxAuthTries 3
# Número máximo de sessões simultâneas por conexão
MaxSessions 5
# Desabilita login root direto (aprenderemos como acessar root depois)
PermitRootLogin no
# Desabilita usuários vazios
PermitEmptyPasswords no
Mudar de porta 22 para 2222 parece trivial, mas reduz drasticamente o volume de tentativas automatizadas. A maioria dos scanners não persegue portas aleatórias — eles querem alvos fáceis.
Configurações de Timeout e Keep-Alive
Conexões SSH esquecidas abertas são uma falha de segurança. Alguém pode deixar um terminal aberto e sair do escritório, deixando uma sessão ativa:
# /etc/ssh/sshd_config
# Envia um keep-alive a cada 300 segundos (5 minutos)
ClientAliveInterval 300
# Desconecta se não receber resposta após 3 keep-alives
ClientAliveCountMax 3
# Conexões idle são desconectadas após 15 minutos
TCPKeepAlive yes
# Timeout para a negociação de chave do SSH (30 segundos é padrão, mantém assim)
LoginGraceTime 30
Isso garante que você nunca tenha uma sessão SSH aberta indefinidamente. Depois de 15 minutos de inatividade, a conexão é encerrada automaticamente.
Configuração de Criptografia e Algoritmos
O SSH suporta múltiplos algoritmos de criptografia, e nem todos são igualmente seguros. Você deve ser explícito sobre quais aceitar:
# /etc/ssh/sshd_config
# Define os algoritmos de troca de chaves permitidos (deixe apenas os modernos)
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
# Algoritmos de criptografia simétrica
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
# Algoritmos para autenticação de mensagens (HMAC)
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
# Desabilita algoritmos frágeis completamente
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
Esses algoritmos são recomendados por autoridades como Mozilla e NIST. Você está explicitamente dizendo "aceitamos apenas o que sabemos ser seguro hoje".
Validando a Configuração
Depois de editar o arquivo, sempre teste antes de aplicar:
# Valida a sintaxe sem aplicar
sudo sshd -t
# Se retornar sem erros, recarrega o serviço
sudo systemctl reload ssh
# Testa a nova porta sem desconectar
ssh -p 2222 user@servidor
# Apenas depois de confirmar, reinicia a sessão antiga
exit
Nunca reinicie o SSH sem validar a configuração. Um
sshd -tlevará segundos e pode economizar horas de trabalho perdido.
Autenticação baseada em Certificados SSH
Chaves públicas são melhores que senhas, mas certificados SSH vão além. Eles permitem autenticação automática, auditoria clara de quem fez o quê, e expiração temporal. Grandes organizações usam isso há anos; é o padrão industrial.
Diferença entre Chaves e Certificados
Uma chave pública SSH é simplesmente um arquivo de texto que você coloca no authorized_keys. Um certificado SSH é uma chave pública assinada por uma autoridade central, com metadados como validade temporal, quem pode usar, e para qual propósito. Isso habilita auditorias melhores e controle centralizado.
# Estrutura de uma chave pública SSH (sem certificado)
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@laptop
# Estrutura de um certificado SSH (com atributos)
ssh-ed25519-cert-v01@openssh.com AAAAIGe2bYnWN9h9c... user@laptop
# Este certificado contém: chave pública, identidade, timestamp, validade, permissões
Gerando Chaves Ed25519 (O Padrão Moderno)
Ed25519 é o algoritmo recomendado hoje. É mais rápido, mais compacto e mais seguro que RSA de 2048 bits. Sempre prefira Ed25519 para novas chaves:
# No seu laptop/máquina local (NUNCA no servidor)
ssh-keygen -t ed25519 -C "seu_email@company.com" -f ~/.ssh/id_ed25519
# Saída esperada:
# Generating public/private ed25519 key pair.
# Enter passphrase (empty for no passphrase): [ENTRADA_IMPORTANTE]
# ...
# Your public key has been saved in /home/user/.ssh/id_ed25519.pub
# SEMPRE defina uma passphrase para proteger a chave privada no disco
# Se alguém roubar seu laptop, ainda precisa da passphrase para usar a chave
A chave privada nunca deixa seu computador. A chave pública é copiada para o servidor:
# Copia apenas a CHAVE PÚBLICA para o servidor
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@servidor
# Ou manualmente, se preferir:
cat ~/.ssh/id_ed25519.pub | ssh -p 2222 user@servidor "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# No servidor, valide que foi adicionada
cat ~/.ssh/authorized_keys
Implementando Certificados SSH com CA (Autoridade Certificadora)
Para ambientes mais robustos, você cria uma CA SSH interna que assina chaves dos usuários. Isso é o que grandes empresas fazem:
# PASSO 1: Criar a Chave da CA (em uma máquina segura, tipo offline)
ssh-keygen -t ed25519 -C "CA" -f ca_key -N ""
# Isso gera: ca_key (privada) e ca_key.pub (pública)
# PASSO 2: No servidor, adicione a chave pública da CA ao sshd_config
# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca_key.pub
# PASSO 3: Copie ca_key.pub para o servidor
sudo cp ca_key.pub /etc/ssh/ca_key.pub
sudo chmod 644 /etc/ssh/ca_key.pub
# PASSO 4: Assine o certificado de um usuário (válido por 30 dias)
ssh-keygen -s ca_key \
-I "user@company.com" \
-n "user" \
-V +30d \
-z 001 \
~/.ssh/id_ed25519.pub
# Isso gera: ~/.ssh/id_ed25519-cert.pub (certificado assinado)
# PASSO 5: Copie o certificado para o servidor
scp -P 2222 ~/.ssh/id_ed25519-cert.pub user@servidor:~/.ssh/
# PASSO 6: Configure o cliente para usar o certificado
# No seu ~/.ssh/config
Host servidor
HostName 10.0.1.50
Port 2222
User user
IdentityFile ~/.ssh/id_ed25519
IdentityFile ~/.ssh/id_ed25519-cert.pub
AddKeysToAgent yes
Agora teste a conexão:
# Seu cliente SSH vai usar automaticamente o certificado se estiver válido
ssh servidor
# Você pode ver detalhes do certificado com:
ssh-keygen -Lf ~/.ssh/id_ed25519-cert.pub
Com certificados, você tem:
- Validade temporal: O certificado expira automaticamente, você não precisa deletar chaves manualmente
- Auditoria: Você sabe exatamente quem foram os signatários
- Controle centralizado: Uma única CA para toda a infraestrutura
- Revogação: Você pode listar certificados revogados (KRL)
Bastion Host: O Modelo de Acesso Seguro
Um Bastion Host (ou Jump Host) é um servidor intermediário que você usa como ponto de entrada para acessar outros servidores. É a arquitetura padrão em organizações que levam segurança a sério: você não acessa servidores internos diretamente da internet, você passa por um bastion primeiro.
Por que usar Bastion Host?
Servidores internos nunca devem ter SSH exposto na internet. Um bastion é um firewall aplicacional: ele filtra, autentica, e registra tudo que passa por ele. Se alguém quiser acessar um servidor web interno, ele precisa passar pelo bastion primeiro, deixando um rastro auditável.
[Seu Laptop] --- internet ---> [Bastion Host] --- rede interna ---> [Servidores Internos]
O bastion é o único servidor com SSH acessível de fora. Ele é "hardened" ao máximo porque recebe todo o tráfego inicial.
Configurando SSH ProxyJump no Cliente
A forma moderna de usar bastion é com ProxyJump no cliente SSH. Isso cria um túnel automático:
# ~/.ssh/config
# Configuração do Bastion Host
Host bastion
HostName bastion.example.com
Port 2222
User admin
IdentityFile ~/.ssh/id_ed25519
AddKeysToAgent yes
# Log de tudo que passa pelo bastion
LogLevel VERBOSE
# Qualquer servidor interno que route através do bastion
Host servidor-interno
HostName 10.0.1.50
Port 2222
User admin
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion
# Não expõe em público, só acessível através do bastion
# Usando wildcard para toda uma rede interna
Host 10.0.*
User admin
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion
Agora, quando você conecta a um servidor interno:
# Isso funciona mesmo que 10.0.1.50 não tenha SSH público
ssh servidor-interno
# Internamente, o SSH faz:
# 1. Conecta ao bastion.example.com:2222
# 2. Cria um túnel para 10.0.1.50:2222 através do bastion
# 3. Autentica no servidor interno
# 4. Abre a sessão
Configuração do Bastion Host (lado servidor)
O bastion é um servidor como qualquer outro, mas com regras mais estritas:
# /etc/ssh/sshd_config (no bastion)
Port 2222
ListenAddress 0.0.0.0 # Exposto na internet, mas sécuro
# Apenas chaves, sem senhas
PasswordAuthentication no
PubkeyAuthentication yes
# Negar root direto (usaremos sudo depois)
PermitRootLogin no
# Limitar drasticamente o número de conexões
MaxStartups 10:30:100 # Começa rejeitando após 10, rejeita 30% das novas depois de 100
MaxAuthTries 2 # Apenas 2 tentativas antes de desconectar
# Desabilitar X11 e port forwarding (não precisa, aumenta risco)
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
# Permitir apenas usuários específicos (whitelist)
AllowUsers admin deployer
# Logging detalhado para auditoria
SyslogFacility AUTH
LogLevel VERBOSE
Exemplo Prático: Escalando para Root via Sudo
Você conecta como usuário comum no bastion, depois usa sudo para operações que precisam root. Isso deixa um rastro auditável de quem fez o quê:
# SSH conecta como 'admin' (sem root)
ssh bastion
# No bastion, você pode usar sudo com auditoria
sudo systemctl restart service-x
# Nos logs do bastion (/var/log/auth.log):
# May 15 14:23:01 bastion sudo: admin : TTY=pts/0 ; PWD=/home/admin ; USER=root ; COMMAND=/bin/systemctl restart service-x
Configure o sudoers para permitir isto sem pedir senha (já que você está autenticado por chave SSH):
# /etc/sudoers (editar com 'visudo', nunca diretamente)
# Permite que o usuário 'admin' execute commands específicos sem senha
admin ALL=(ALL) NOPASSWD: /bin/systemctl, /usr/bin/apt-get, /bin/journalctl
# Ou permita qualquer comando (menos seguro, mas comum em dev):
admin ALL=(ALL) NOPASSWD: ALL
Auditoria e Registro de Tudo que Passa pelo Bastion
Configure o bastion para registrar todas as conexões em arquivo centralizado. Muitas organizações usam syslog remoto para isto:
# /etc/ssh/sshd_config (bastion)
# Verbose logging de tudo
LogLevel VERBOSE
# Registra também as chaves que tentam conectar (para auditoria)
SyslogFacility AUTH
# Opcional: registra também as chaves que conseguem conectar (útil para debug)
AuthorizedKeysCommand /usr/local/bin/log-authorized-keys.sh
AuthorizedKeysCommandUser nobody
Se um invasor conseguir acessar o bastion (improvável com as configurações acima), você terá logs completos de tudo que ele fez, porque a auditoria do sudo registra cada comando.
Checklist de Implementação Prática
Você agora tem o conhecimento. Aqui está a sequência exata que eu recomendo para implementar em um servidor real:
-
Gere suas chaves Ed25519 localmente (nunca no servidor)
bash ssh-keygen -t ed25519 -C "seu_email@company.com" -f ~/.ssh/id_servidor -
Copie a chave pública para o servidor
bash ssh-copy-id -i ~/.ssh/id_servidor.pub -p 22 user@server -
Edite
/etc/ssh/sshd_configcom as configurações do artigo -
Valide com
sshd -tantes de aplicar -
Recarregue o SSH:
sudo systemctl reload ssh -
Teste a nova configuração EM OUTRA SESSÃO antes de desconectar
-
Apenas depois de confirmar que funciona, desabilite PasswordAuthentication
-
Implemente bastion host se tiver múltiplos servidores
-
Configure certificados SSH para equipes maiores
Conclusão
Hardening de SSH não é sobre lembrar de uma longa lista de configurações — é sobre entender por que cada mudança existe. A maioria dos ataques contra SSH exploram defaults perigosos: você deixou PasswordAuthentication ligado, deixou PermitRootLogin ativo, ou manteve a porta 22 aberta para o mundo. Quando você fecha essas portas, você não apenas bloqueia ataques, você elimina ruído dos logs e deixa claramente visível quando algo genuinamente suspeito acontece. A segunda camada é autenticação forte: chaves Ed25519 com passphrases são virtualmente impossíveis de quebrar por força bruta, e certificados SSH escalam isso para dezenas ou milhares de usuários sem perder controle. A terceira camada é arquitetura: um bastion host garante que servidores internos nunca recebem tráfego SSH direto da internet, reduzindo dramaticamente a superfície de ataque.
Referências
- OpenSSH Official Documentation — Documentação oficial completa do sshd_config
- Mozilla SSH Guidelines — Recomendações de hardening de autoridades em segurança
- SSH Academy - Certificate-based Authentication — Guia aprofundado sobre certificados SSH
- NIST Cybersecurity Framework SSH Best Practices — Padrões oficiais de segurança do governo americano
- Linux Foundation - SSH Jump Host Setup — Documentação prática sobre bastion hosts