SSH Secure Shell
Protocolo de rede criptográfico para acesso remoto seguro. Tudo que um desenvolvedor sênior precisa saber.
Confidencialidade
Dados trafegam 100% cifrados. Nenhum intermediário consegue ler.
Integridade
MACs detectam qualquer adulteração dos dados em trânsito.
Autenticação
Garante identidade do servidor e do cliente. Ambos os lados provam quem são.
SSH-1 está obsoleto e deve ser desabilitado. Em produção, apenas SSH-2 existe.
📅 História
SSH surgiu de um ataque real — não de teoria. Em 1995, um sniffer capturou senhas de root trafegando em plaintext via Telnet na rede da Universidade de Helsinki.
🏗️ Arquitetura do Protocolo
SSH-2 é composto por três sub-protocolos empilhados, cada um com responsabilidade distinta, rodando sobre TCP.
Camada 1 — Transport: o que acontece na conexão
~/.ssh/known_hosts. Previne man-in-the-middle.Camada 2 — User Auth: métodos de autenticação
| Método | Como funciona | Uso |
|---|---|---|
publickey | Cliente assina challenge com chave privada; servidor verifica com pública cadastrada | recomendado |
keyboard-interactive | Desafio genérico — PAM, OTP, 2FA | ok |
password | Senha transmitida cifrada ao servidor | evitar |
hostbased | Confia em combinação host+usuário remoto | legado |
none | Sem autenticação (acesso anônimo controlado) | raro |
Camada 3 — Connection: o que roda dentro da sessão
Shell interativo
Terminal remoto em tempo real
Exec
Comando único sem shell persistente
Port Forwarding
Tunnels local, remoto e dinâmico (SOCKS)
SFTP
Transferência de arquivos via subsystem
X11 Forwarding
Interface gráfica remota via tunnel
Multiplex
Vários channels em uma TCP connection
🔐 Criptografia
SSH negocia algoritmos dinamicamente. Conhecer o status de cada um evita configurações inseguras.
Troca de Chaves (KEX) — como o segredo é estabelecido
| Algoritmo | Status |
|---|---|
curve25519-sha256 | ★ Recomendado |
ecdh-sha2-nistp256/384/521 | OK |
diffie-hellman-group14-sha256 | Aceitável |
diffie-hellman-group1-sha1 | Obsoleto — desabilitar |
Cifras Simétricas — para dados em trânsito
| Algoritmo | Status |
|---|---|
chacha20-poly1305@openssh.com | ★ Recomendado |
aes256-gcm@openssh.com | ★ Recomendado |
aes128-gcm@openssh.com | OK |
aes256-ctr / aes128-ctr | OK |
3des-cbc / arcfour | Obsoleto — remover |
MACs — garante integridade dos pacotes
| Algoritmo | Status |
|---|---|
hmac-sha2-256-etm@openssh.com | ★ Encrypt-then-MAC |
hmac-sha2-512-etm@openssh.com | ★ Recomendado |
hmac-sha1 | Obsoleto |
🗝️ Tipos de Chave
Usadas tanto como host keys (identidade do servidor) quanto como user keys (identidade do usuário).
ssh-keygen -t ed25519
ssh-keygen -t ecdsa -b 521
ssh-keygen -t rsa -b 4096
—
📂 Estrutura de Arquivos
Cliente (~/.ssh/)
.ssh/ → 700 · chaves privadas → 600 · authorized_keys → 600
Servidor (/etc/ssh/)
Geradas automaticamente na instalação. Fingerprint vai para known_hosts do cliente na primeira conexão.
🪪 Autenticação por Chave Pública
Método mais seguro. A chave privada nunca sai do cliente — apenas uma assinatura criptográfica é transmitida.
~/.ssh/authorized_keys.Gerando par de chaves
# Ed25519 — padrão recomendado ssh-keygen -t ed25519 -C "seu@email.com" # RSA 4096 — para compatibilidade com legado ssh-keygen -t rsa -b 4096 -C "seu@email.com" # Com nome customizado (ex: chave só para GitHub) ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github -C "github"
Copiando chave pública para o servidor
# Automático — recomendado ssh-copy-id user@host ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host # Manual via pipe cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
⚙️ SSH Config (~/.ssh/config)
Evita repetir flags na linha de comando. Define aliases, chaves, portas e comportamentos por host.
# Defaults para todos os hosts Host * ServerAliveInterval 60 ServerAliveCountMax 3 AddKeysToAgent yes IdentitiesOnly yes # Servidor de produção Host prod HostName 203.0.113.10 User deploy Port 2222 IdentityFile ~/.ssh/id_ed25519_prod # Acesso a servidor interno via bastion Host app-server HostName 10.0.1.50 User ubuntu ProxyJump bastion Host bastion HostName bastion.example.com User alfredo IdentityFile ~/.ssh/id_ed25519 # GitHub Host github.com User git IdentityFile ~/.ssh/id_ed25519_github # Padrão para hosts internos Host *.internal User admin IdentityFile ~/.ssh/id_ed25519_internal
Diretivas mais úteis
HostNameIP ou FQDN real do servidor
UserUsuário padrão para conexão
PortPorta SSH (padrão: 22)
IdentityFileChave privada específica para este host
ProxyJumpConecta via outro host (bastion)
ForwardAgentEncaminha ssh-agent ao servidor
LocalForwardTunnel local → remoto
RemoteForwardTunnel remoto → local
DynamicForwardProxy SOCKS no host local
ServerAliveIntervalKeepalive: segundos entre pings
ControlMaster autoHabilita multiplexação de conexões
ControlPersist 10mMantém master connection 10 minutos
IdentitiesOnly yesUsa só chaves do IdentityFile (ignora agente)
StrictHostKeyCheckingyes / no / accept-new
AddKeysToAgent yesAdiciona chave ao agente automaticamente
ControlPathCaminho do socket de multiplexação
💻 Comandos de Conexão
# Conexão básica ssh user@host ssh -p 2222 user@host # porta customizada ssh prod # usando alias do ~/.ssh/config ssh -i ~/.ssh/id_ed25519 user@host # especificar chave # Executar comando remoto sem abrir shell ssh user@host "ls -la /var/log" ssh user@host "sudo systemctl status nginx" # Enviar script local para rodar no servidor ssh user@host 'bash -s' < script.sh # Pseudo-TTY: necessário para sudo interativo ssh -t user@host "sudo htop"
📦 Transferência de Arquivos
Seis ferramentas para transferência via SSH — cada uma com caso de uso diferente.
| Ferramenta | Instalação | Melhor para | Retoma? | Só o que mudou? |
|---|---|---|---|---|
scp |
incluso no OpenSSH | Cópia rápida de arquivo único | ❌ | ❌ |
rsync |
geralmente pré-instalado | Sync de diretórios, backups | ✅ | ✅ |
sftp |
incluso no OpenSSH | Sessão interativa, browse remoto | ❌ | ❌ |
sshfs |
apt install sshfs | Montar fs remoto como local | — | — |
lftp |
apt install lftp | Mirror avançado, scripting | ✅ | ✅ |
rclone |
instalação separada | SFTP + cloud (S3, GCS, Dropbox…) | ✅ | ✅ |
SCP — cópia simples
Incluso no OpenSSH. Sintaxe parecida com cp. Não retoma transferências interrompidas — para isso use rsync.
# Local → remoto scp arquivo.txt user@host:/destino/ scp -r pasta/ user@host:/destino/ # recursivo # Remoto → local scp user@host:/caminho/arquivo.txt ./local/ scp -r user@host:/var/log/ ./logs-backup/ # Flags scp -P 2222 arquivo.txt user@host:/tmp/ # porta customizada scp -C arquivo.txt user@host:/tmp/ # compressão em trânsito scp -l 5000 arquivo.txt user@host:/tmp/ # limitar banda: 5000 Kbit/s scp -q arquivo.txt user@host:/tmp/ # silencioso (sem barra) scp -i ~/.ssh/id_ed25519 arquivo.txt user@host:/tmp/ # chave específica # Copiar entre dois servidores remotos (passa pelo local) scp -3 user1@host1:/arquivo.txt user2@host2:/destino/ # Via bastion scp -J bastion user@interno:/arquivo.txt .
RSYNC — sincronização eficiente
Transfere só o que mudou. Suporta retomada, exclusões, dry-run, limite de banda. Preferível ao SCP para diretórios e backups.
Geralmente pré-instalado. Se não estiver: apt install rsync — precisa estar instalado nos dois lados da conexão.
Atalho para -rlptgoD: recursivo + preserva permissões, timestamps, symlinks, owner, group.
# Básico rsync -avz --progress pasta/ user@host:/destino/ # Espelhar — apaga no destino o que não existe na origem rsync -avz --delete pasta/ user@host:/destino/ # Porta customizada / chave específica rsync -avz -e "ssh -p 2222" pasta/ user@host:/destino/ rsync -avz -e "ssh -i ~/.ssh/key -p 2222" pasta/ user@host:/destino/ # Simular sem executar (ver o que seria feito) rsync -avz --dry-run --delete pasta/ user@host:/destino/ # Retomar transferência interrompida rsync -avz --partial --progress pasta/ user@host:/destino/ rsync -avz --append-verify pasta/ user@host:/destino/ # Limitar banda: 500 KB/s rsync -avz --bwlimit=500 pasta/ user@host:/destino/ # Excluir padrões rsync -avz --exclude='*.log' --exclude='.git/' pasta/ user@host:/destino/ rsync -avz --exclude-from='rsync-exclude.txt' pasta/ user@host:/destino/ # Verificar por checksum em vez de timestamp+tamanho rsync -avz --checksum pasta/ user@host:/destino/ # Backup: salva versão anterior antes de sobrescrever rsync -avz --backup --backup-dir=/backup/$(date +%Y%m%d) pasta/ user@host:/destino/ # Estatísticas ao final rsync -avz --stats pasta/ user@host:/destino/
SFTP — sessão interativa
Protocolo próprio (não é SCP). Permite browse, rename, mkdir, chmod no servidor remoto. Incluso no OpenSSH.
sftp user@host sftp -P 2222 user@host # porta customizada sftp -i ~/.ssh/id_ed25519 user@host # chave específica sftp -b comandos.txt user@host # modo batch (não interativo) # Batch sem arquivo echo "put arquivo.txt /remoto/" | sftp user@host
# Navegação ls / lls # listar remoto / listar local cd / lcd # mudar dir remoto / local pwd / lpwd # dir atual remoto / local # Download get arquivo.txt # baixar arquivo get arquivo.txt outro-nome.txt # baixar com nome diferente get -r pasta/ # baixar diretório recursivo mget *.log # múltiplos (wildcard) # Upload put local.txt # enviar arquivo put local.txt /remoto/outro.txt # enviar com nome diferente put -r pasta/ # enviar diretório recursivo mput *.csv # múltiplos (wildcard) # Gerenciamento remoto mkdir /remoto/nova-pasta rmdir /remoto/pasta-vazia rm arquivo.txt rename antigo.txt novo.txt chmod 600 arquivo.txt ln -s alvo link # symlink remoto df -h # espaço em disco remoto exit / quit / bye
SSHFS — montar filesystem remoto apt install sshfs
Monta diretório remoto localmente via FUSE. Edite arquivos remotos direto no seu editor local, como se fossem arquivos locais.
# Ubuntu / Debian sudo apt install sshfs # macOS brew install macfuse sshfs
# Criar ponto de montagem mkdir -p ~/mnt/servidor # Montar sshfs user@host:/caminho/remoto ~/mnt/servidor sshfs -p 2222 user@host:/var/www ~/mnt/www # porta customizada sshfs -o IdentityFile=~/.ssh/id_ed25519 user@host:/ ~/mnt/servidor # Opções úteis sshfs -o reconnect,ServerAliveInterval=15 user@host:/remoto ~/mnt/servidor sshfs -o allow_other user@host:/remoto ~/mnt/servidor # outros usuários locais sshfs -o ro user@host:/remoto ~/mnt/servidor # read-only # Desmontar fusermount -u ~/mnt/servidor # Linux umount ~/mnt/servidor # macOS # Montagem persistente (/etc/fstab) # user@host:/remoto /mnt/servidor fuse.sshfs defaults,_netdev,reconnect,uid=1000,gid=1000 0 0
lftp — mirror avançado apt install lftp
Mais poderoso que o sftp interativo. Mirror bidirecional, transferências paralelas, filas, scripting.
sudo apt install lftp # Conectar via SFTP lftp sftp://user@host lftp sftp://user@host:2222 # porta customizada # Dentro da sessão: mirror download mirror /remoto/pasta ./local/pasta # Mirror reverso (upload) mirror -R ./local/pasta /remoto/pasta # Mirror com opções mirror --exclude='\.log$' /remoto/ ./local/ mirror --parallel=4 /remoto/ ./local/ # 4 conexões simultâneas mirror --continue /remoto/ ./local/ # retomar interrompido # Comandos inline (sem sessão interativa) lftp -e "mirror /remoto/ ./local/; bye" sftp://user@host lftp -e "put arquivo.txt; bye" sftp://user@host
rclone — SFTP + cloud instalação separada
Ferramenta universal de sync: SFTP, S3, GCS, Azure, Dropbox e 40+ provedores com a mesma interface.
# Script oficial curl https://rclone.org/install.sh | sudo bash # macOS brew install rclone
# Configurar remote SFTP (interativo) rclone config # → n (new remote) → nome → tipo: sftp → host, user, port, key file # Listar rclone ls meuservidor:/var/www # Copiar local → remoto rclone copy ./pasta meuservidor:/destino/ # Sync (espelha — deleta no destino o que não existe na origem) rclone sync ./pasta meuservidor:/destino/ # Sync remoto → local rclone sync meuservidor:/var/www ./backup/ # Dry run + progresso + log rclone sync --dry-run -P --log-file=rclone.log ./pasta meuservidor:/destino/
Arquivo único rápido → scp · Sync de diretório / backup → rsync · Browse e gerenciar remoto → sftp · Editar remotamente no editor local → sshfs · Mirror com paralelo/script → lftp · Backup para cloud + SFTP → rclone
🔀 Port Forwarding / Tunneling
SSH pode criar túneis TCP por dentro da conexão criptografada. Três modalidades:
Local Forward (-L) — acessa serviço remoto localmente
ssh -L 8080:localhost:80 user@host ssh -L 5432:db-server:5432 user@bastion # acessa DB interno via bastion
Remote Forward (-R) — expõe serviço local no servidor
ssh -R 9090:localhost:3000 user@host
Dynamic Forward (-D) — proxy SOCKS5
ssh -D 1080 user@host # Sem abrir shell (tunnel em background) ssh -fN -L 5432:localhost:5432 user@db-host # Múltiplos tunnels simultâneos ssh -L 8080:localhost:80 -L 5432:localhost:5432 -N user@host
Jump Hosts / Bastion
Acessa servidor interno passando por um bastion host público.
# Flag direto ssh -J bastion.example.com user@app-server-interno ssh -J bastion1,bastion2 user@destino # múltiplos saltos # Copiar arquivo via bastion scp -J bastion user@interno:/arquivo.txt . # Via config (preferível) Host app-server ProxyJump bastion
🤖 ssh-agent
Mantém chaves privadas decifradas em memória. Você digita a passphrase uma vez — o agente autentica nas conexões seguintes.
# Iniciar agente eval "$(ssh-agent -s)" # Adicionar chave (pede passphrase uma vez) ssh-add ~/.ssh/id_ed25519 ssh-add -t 3600 ~/.ssh/id_ed25519 # expira em 1h # Listar chaves carregadas ssh-add -l # Remover ssh-add -d ~/.ssh/id_ed25519 # uma chave ssh-add -D # todas # Agent Forwarding — leva o agente para o servidor remoto ssh -A user@bastion # de dentro do bastion, pode autenticar em outros hosts # usando as chaves do seu computador local
Se o servidor for comprometido, alguém pode usar seu agente para autenticar em outros hosts. Use só em servidores confiáveis. Prefira ProxyJump quando possível.
⚡ Multiplexação de Conexões
Reutiliza a TCP connection existente. Segunda conexão ao mesmo host é instantânea — sem renegociar KEX, sem nova autenticação.
Host * ControlMaster auto ControlPath ~/.ssh/ctl/%r@%h:%p ControlPersist 10m
mkdir -p ~/.ssh/ctl # Verificar se master está ativo ssh -O check user@host # Encerrar master ssh -O stop user@host ssh -O exit user@host
📋 known_hosts
Armazena fingerprints dos servidores já visitados. Protege contra man-in-the-middle alertando quando a chave do servidor muda.
# Ver fingerprint de um host antes de conectar ssh-keyscan -t ed25519 hostname ssh-keyscan -p 2222 hostname # Adicionar host manualmente ssh-keyscan hostname >> ~/.ssh/known_hosts # Remover host (servidor trocou chave, ou foi rebuiltado) ssh-keygen -R hostname ssh-keygen -R [hostname]:2222 # Ver fingerprint de chave ssh-keygen -lf ~/.ssh/id_ed25519.pub ssh-keygen -lv -f ~/.ssh/id_ed25519.pub # formato visual (randomart)
🖥️ Configuração do Servidor (sshd_config)
# Protocolo Protocol 2 # Host keys — manter apenas modernos HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key # Autenticação PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys PermitEmptyPasswords no # Restrições MaxAuthTries 3 MaxSessions 10 LoginGraceTime 30 # Keepalive ClientAliveInterval 300 ClientAliveCountMax 2 # Desabilitar o que não usa X11Forwarding no AllowAgentForwarding no AllowTcpForwarding no # mudar para yes se precisar de tunnels GatewayPorts no PermitTunnel no # Algoritmos modernos KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com # Restringir por usuário AllowUsers deploy alfredo # SFTP Subsystem sftp /usr/lib/openssh/sftp-server
# Validar config ANTES de reiniciar (não derruba sessões ativas) sshd -t # Ver config efetiva sshd -T # Recarregar sem derrubar sessões systemctl reload sshd
Blocos Match — regras condicionais
# Regras por usuário Match User deploy AllowTcpForwarding yes ForceCommand /usr/bin/deploy-shell # Regras por grupo — chroot SFTP Match Group sftp-only ChrootDirectory /var/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no # Regras por IP Match Address 10.0.0.0/8 PasswordAuthentication yes
📜 Certificados SSH
Alternativa ao authorized_keys para escala. Uma CA central assina chaves — servidores confiam na CA, não em chaves individuais.
Problema com authorized_keys em escala
100 servidores + 50 devs = gerenciar 5000 entradas. Revogar uma chave = atualizar todos os servidores.
Solução com Certificados
CA assina a chave do dev. Todos os servidores confiam na CA. Revogar = invalidar o certificado em um lugar.
# 1. Criar CA (é um par de chaves normal) ssh-keygen -t ed25519 -f ssh_ca -C "My SSH CA" # 2. Assinar chave de usuário (-V: validade, -n: principals) ssh-keygen -s ssh_ca -I "alfredo@empresa" -n "alfredo,deploy" -V +52w id_ed25519.pub # gera: id_ed25519-cert.pub # 3. Assinar host key do servidor ssh-keygen -s ssh_ca -I "prod-server" -h -V +52w /etc/ssh/ssh_host_ed25519_key.pub # 4. Servidor confia na CA (sshd_config) TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub # 5. Cliente confia em hosts assinados pela CA (known_hosts) @cert-authority *.example.com ssh-ed25519 AAAA... SSH CA
Revogação centralizada
Sem tocar authorized_keys em cada servidor.
Expiração nativa
Certificados expiram automaticamente. Sem chaves eternas.
Auditoria
Campo key ID aparece nos logs de autenticação.
⌨️ Escape Sequences
Durante uma sessão SSH interativa, ~ é o escape character. Permite controlar a conexão sem fechar o terminal.
~ literalAbre prompt ssh> onde você pode digitar -L 8080:localhost:80 para adicionar um tunnel em uma sessão já aberta.
🔧 Recursos Avançados
SSH sobre HTTPS (porta 443)
Útil quando porta 22 está bloqueada em redes corporativas ou firewalls restritivos.
Host github.com
HostName ssh.github.com
Port 443
User git
Gerenciamento avançado de chaves
# Mudar passphrase de chave existente ssh-keygen -p -f ~/.ssh/id_ed25519 # Extrair chave pública a partir da privada ssh-keygen -y -f ~/.ssh/id_ed25519 # Assinar arquivo com chave SSH (OpenSSH 8.0+) ssh-keygen -Y sign -f ~/.ssh/id_ed25519 -n file documento.txt ssh-keygen -Y verify -f allowed_signers -I user@email -n file -s documento.txt.sig < documento.txt
ProxyCommand customizado
# Via proxy SOCKS5 (netcat) Host interno ProxyCommand nc -X 5 -x proxy:1080 %h %p # Via proxy HTTP CONNECT (corkscrew) Host interno ProxyCommand corkscrew proxy 3128 %h %p
🔍 Debug e Diagnóstico
# Verbose no cliente (até -vvv) ssh -v user@host ssh -vvv user@host # máximo detalhe # Ver config efetiva do servidor sshd -T sshd -T -C user=alfredo # config para usuário específico # Logs do servidor journalctl -u sshd -f tail -f /var/log/auth.log # Debian/Ubuntu tail -f /var/log/secure # RHEL/CentOS # Verificar qual chave foi aceita ssh -v user@host 2>&1 | grep "Offering\|Accepted" # Corrigir permissões chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519 chmod 600 ~/.ssh/authorized_keys chmod 644 ~/.ssh/id_ed25519.pub
Checklist de troubleshooting
-
Permissões de
~/.ssh/(700) eauthorized_keys(600) no servidor -
authorized_keyscontém a chave pública correta — sem quebra de linha no meio -
sshd_configtemPubkeyAuthentication yes -
StrictModes yes— home dir do usuário não pode ser writable por outros -
SELinux / AppArmor não bloqueando acesso ao
.ssh/ -
Firewall permitindo a porta SSH
-
ssh -vvv— mostra exatamente onde a autenticação falha
🛡️ Segurança — Boas Práticas
Reduz logs de ruído (scanners automáticos), mas qualquer atacante com foco vai encontrar a porta nova. Não substitui autenticação forte.
⚡ Referência Rápida
Referências
OpenSSH
man ssh · man sshd_config · man ssh_config · man ssh-keygen