Como configurar um bastion SSH com chaves e autenticação de dois fatores (2FA) no Ubuntu Server 22.04

Linux & Sistemas · Por · Publicado em · Atualizado em · 8 min de leitura

Baias frontais de um dispositivo de armazenamento em rack, foco nos compartimentos de disco
Detalhe de unidades de armazenamento em um dispositivo de rack, representando infraestrutura de servidores Foto: Jakub Zerdzicki / Pexels

Este guia mostra como configurar um bastion SSH com chaves e autenticação de dois fatores no Ubuntu Server 22.04. Você terá um jump host que exige chave pública e TOTP, reduzindo o risco de acessos indevidos e mantendo auditoria simples do tráfego SSH.

Pré-requisitos e arquitetura do bastion SSH

Um bastion SSH é um servidor de salto centralizado. Ele concentra acessos administrativos a redes internas e aplica políticas rígidas. Aqui, vamos exigir chave pública e TOTP (2FA) para logar no bastion.

Antes de começar, garanta estes pontos. Mudanças em SSH podem bloquear seu acesso. Mantenha uma sessão aberta até tudo funcionar e tenha acesso de console para emergências.

Se você ainda não instalou o sistema, veja o passo a passo em como instalar o Ubuntu Server.

  • Ubuntu Server 22.04 atualizado, com IP público.
  • Acesso sudo ao servidor e backup recente da configuração de SSH.
  • Chave SSH do seu computador já criada (ed25519 de preferência).
  • Aplicativo TOTP no celular (Aegis, Google Authenticator, Authy, etc.).
  • Lista dos hosts internos que você acessará via bastion.
  • Firewall planejado para expor apenas a porta 22 do bastion.

Atualize o sistema, crie o usuário de acesso e instale pacotes

Vamos criar um usuário dedicado ao bastion, instalar o OpenSSH e o módulo de 2FA. Também ativaremos sincronismo de tempo, essencial para TOTP.

Substitua o valor de PUBLIC_KEY pela sua chave real. Não cole chaves de exemplo.

Para endurecimento de firewall detalhado, veja também como configurar firewall no Ubuntu com UFW.

# 1) Atualize e instale pacotes
sudo apt update && sudo apt -y upgrade
sudo apt install -y openssh-server libpam-google-authenticator qrencode

# 2) Habilite o serviço SSH e NTP
timedatectl set-ntp true
sudo systemctl enable --now ssh

# 3) Crie usuário dedicado (ajuste o nome, se quiser)
USER=bastion
sudo adduser --disabled-password --gecos "" "$USER"
sudo usermod -aG sudo "$USER"

# 4) Adicione sua chave pública ao usuário (substitua pela sua)
PUBLIC_KEY='ssh-ed25519 AAAA... cole_sua_chave_aqui'
sudo -u "$USER" mkdir -p "/home/$USER/.ssh"
echo "$PUBLIC_KEY" | sudo tee "/home/$USER/.ssh/authorized_keys" >/dev/null
sudo chown -R "$USER:$USER" "/home/$USER/.ssh"
sudo chmod 700 "/home/$USER/.ssh"
sudo chmod 600 "/home/$USER/.ssh/authorized_keys"

Habilite TOTP com Google Authenticator via PAM

Vamos criar o segredo TOTP do usuário e integrar o PAM para solicitar o código ao conectar via SSH. Faça para cada administrador que acessará o bastion.

O comando abaixo é interativo. Guarde os códigos de recuperação. Quem perder o app e esses códigos pode ficar sem acesso.

Depois, inserimos a linha do módulo no PAM do sshd. Fazemos backup antes da alteração.

# 1) Gere o segredo e códigos TOTP para o usuário (interativo)
sudo -u bastion -H bash -lc 'google-authenticator'

# 2) Faça backup e habilite o módulo no PAM do sshd
sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak
# Insere a linha na primeira linha do arquivo PAM
sudo sed -i '1iauth required pam_google_authenticator.so' /etc/pam.d/sshd

# Valide que o arquivo não ficou corrompido (visual)
sed -n '1,10p' /etc/pam.d/sshd

Exigir chave + 2FA no OpenSSH e aplicar hardening

Agora forçaremos que o login use chave pública E TOTP. Também aplicaremos ajustes de segurança recomendados no sshd.

Criaremos um arquivo de inclusão em sshd_config.d. Não feche a sessão atual até testar com outra conexão.

Veja abaixo os parâmetros e o motivo de cada um. Ajuste AllowUsers com os usuários autorizados.

Parâmetro Efeito Por quê
PasswordAuthentication no Desativa senha no SSH Evita ataques de brute force a senhas
AuthenticationMethods publickey,keyboard-interactive:pam Exige chave + TOTP Fator duplo obrigatório
PermitRootLogin no Bloqueia root remoto Reduz impacto de credenciais vazadas
MaxAuthTries 3 Limita tentativas Dificulta brute force
LoginGraceTime 20s Janela curta de login Reduz sessões pendentes
AllowUsers bastion Restringe a usuários Superfície de ataque menor
X11Forwarding no / AgentForwarding no Bloqueia repasses desnecessários Menos vetores de pivô
AllowTcpForwarding yes Permite ProxyJump Necessário para bastion como jump host
# 1) Arquivo de hardening (incluído pelo sshd)
cat <<'EOF' | sudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null
KbdInteractiveAuthentication yes
UsePAM yes
PubkeyAuthentication yes
PasswordAuthentication no
AuthenticationMethods publickey,keyboard-interactive:pam
PermitRootLogin no
AllowUsers bastion
MaxAuthTries 3
LoginGraceTime 20s
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding yes
GatewayPorts no
PermitTunnel no
#Banner /etc/issue.net
EOF

# 2) Teste a configuração e reinicie
sudo sshd -t && sudo systemctl restart ssh

# 3) Teste em um novo terminal antes de encerrar esta sessão

Firewall UFW e proteção contra tentativas

Limite a exposição da porta 22 e aplique rate limiting. Se puder, permita apenas origens conhecidas. Opcionalmente, use Fail2ban para bloquear IPs após falhas repetidas.

Para outras regras e cenários, consulte o guia de UFW já linkado. Se VPN for opção, um bastion atrás de WireGuard road‑warrior aumenta a segurança.

# 1) UFW: permitir e aplicar rate limit
sudo ufw allow OpenSSH
sudo ufw limit OpenSSH
# Opcional: restrinja a IPs conhecidos (substitua 203.0.113.10)
# sudo ufw delete allow OpenSSH
# sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
sudo ufw enable
sudo ufw status verbose

# 2) Fail2ban básico para sshd
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[sshd]
enabled = true
bantime = 1h
findtime = 10m
maxretry = 4
EOF
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

Configure ProxyJump no cliente SSH

Use ProxyJump para acessar hosts internos através do bastion de forma transparente. Assim, você autentica no bastion e o SSH encaminha para o destino.

Crie um bloco para o bastion e outro para seus servidores. Ajuste HostName, User e IdentityFile conforme seu ambiente.

  • ProxyJump simplifica: um comando acessa a máquina interna.
  • Funciona com chaves e 2FA no bastion sem expor hosts internos.
# No seu computador, configure o SSH
mkdir -p ~/.ssh && chmod 700 ~/.ssh
cat <<'EOF' >> ~/.ssh/config
Host bastion
  HostName 198.51.100.10        # IP ou DNS do bastion
  User bastion                   # usuário no bastion
  IdentityFile ~/.ssh/id_ed25519
  IdentitiesOnly yes
  ServerAliveInterval 60

Host app-interno
  HostName 10.0.0.20             # IP interno do destino
  User ubuntu                    # usuário no host interno
  IdentityFile ~/.ssh/id_ed25519
  ProxyJump bastion
EOF
chmod 600 ~/.ssh/config

# Teste o salto
ssh app-interno
# Ou explicitamente:
# ssh -J bastion [email protected]

Como confirmar que funcionou e solução de problemas

Use os comandos abaixo para verificar autenticação, logs e tempo. A maioria dos problemas de TOTP envolve horário incorreto ou ordem de métodos no sshd.

Se algo der errado, mantenha o acesso de console. Evite aplicar mudanças sem janela de teste.

  • Teste com verbosidade: veja se pede chave e depois TOTP.
  • Verifique horário com timedatectl; ajuste se necessário.
  • Checar logs do sshd ao vivo ajuda a identificar falhas PAM.
  • Valide a sintaxe: sshd -t antes de reiniciar.
  • Fail2ban mostra banimentos e contadores.
# Testes de conexão e diagnóstico
ssh -vvv app-interno

# Logs do serviço SSH no bastion
sudo journalctl -u ssh -f

# Validação da configuração
sudo sshd -t

# Sincronismo de tempo
timedatectl status

# Status do Fail2ban
sudo fail2ban-client status sshd

Perguntas frequentes

Como recuperar acesso se eu perder meu app TOTP?

Use um dos códigos de emergência gerados pelo google-authenticator durante a configuração. Eles funcionam como backup de uso único. Se você também perdeu os códigos, será necessário acesso de console para reverter temporariamente as mudanças do PAM/SSHD ou cadastrar um novo segredo no arquivo do usuário.

Posso habilitar 2FA apenas para alguns usuários?

Sim. Use a opção nullok no PAM para tornar o TOTP opcional e controle quem tem o arquivo ~/.google_authenticator. Porém, para máxima segurança, prefira exigir 2FA de todos e usar AllowUsers para listar quem pode acessar o bastion.

Funciona com YubiKey ou outros tokens?

Sim, mas a configuração muda. Em vez de TOTP via google-authenticator, você pode integrar PAM a métodos como WebAuthn/U2F. O processo envolve módulos PAM específicos. Este guia foca em TOTP por ser simples e amplamente compatível com clientes SSH.

Por que meu TOTP é rejeitado mesmo digitando certo?

Normalmente é diferença de horário entre servidor e celular. Verifique o timedatectl e habilite NTP. Confirme também se a ordem de autenticação está correta no sshd_config e se o módulo pam_google_authenticator está carregando no /etc/pam.d/sshd.

Como auditar quem acessou pelos saltos?

No bastion, use logs do SSH e, se necessário, ative logs estruturados e retenção centralizada. Combine com ProxyJump definido por usuário, sem compartilhamento de contas. Você pode correlacionar sessões por chaves públicas e IPs de origem para rastreabilidade.

Devo desabilitar o AgentForwarding no bastion?

Em geral, sim. Desabilitar AgentForwarding reduz risco de uso indevido das suas chaves em hosts comprometidos. ProxyJump não depende de agent forwarding. Habilite apenas se houver necessidade comprovada e com restrições adicionais.

Continue elevando a segurança do seu Linux

Aplique as mesmas práticas em outros serviços: firewall, VPN e monitoramento. Veja os guias relacionados e fortaleça seu ambiente.

Ver mais guias Linux

Veja também