Como configurar um bastion SSH com chaves e autenticação de dois fatores (2FA) no Ubuntu Server 22.04
Linux & Sistemas · Por Kevin Marcondes · Publicado em · Atualizado em · 8 min de leitura
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 LinuxVeja também
- tutorial: implementar Canary releases com Traefik em Docker Compose usando headers e weight routing para deploys graduais de aplicações PHP
- Tutorial: configurar HAProxy com Let's Encrypt e healthchecks para balanceamento de tráfego entre containers Docker em VPS (passo a passo)
- Tutorial prático: implementar mTLS entre Nginx e microserviços usando smallstep CA em Docker Compose
- Tutorial: configurar cgroup v2 e systemd ResourceControl para limitar CPU, memória e I/O de containers Docker no Debian