Guides
Fundamentos ▾
Versionamento ▾
Deploy ▾
Inteligência Artificial ▾

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 opera na camada 7 (aplicação) sobre TCP porta 22

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.

1995
SSH-1 criado por Tatu Ylönen
Resposta direta a um sniffing attack que capturou senhas em plaintext (Telnet, rlogin, rsh). Substituiu esses protocolos inseguros.
1996
SSH-2 redesenhado
Arquitetura mais segura, corrigindo falhas estruturais do SSH-1. Separação em três sub-protocolos independentes.
1999
OpenSSH nasce
Fork open source do SSH-2, livre de patentes, integrado ao OpenBSD. Hoje é a implementação dominante no mundo.
2006
SSH-2 vira RFC oficial
RFCs 4251–4254 padronizam o protocolo formalmente.
Hoje
OpenSSH em todo lugar
Presente em Linux, macOS e Windows 10+. Padrão absoluto para acesso remoto seguro.

🏗️ Arquitetura do Protocolo

SSH-2 é composto por três sub-protocolos empilhados, cada um com responsabilidade distinta, rodando sobre TCP.

3
SSH Connection Protocol
Multiplexa channels: shell interativo, exec, port forwarding, SFTP, X11
RFC 4254
2
SSH User Auth Protocol
Autentica o usuário: publickey, password, keyboard-interactive
RFC 4252
1
SSH Transport Protocol
Criptografia, integridade, troca de chaves, verificação do servidor
RFC 4253
0
TCP · Porta 22
Transporte confiável
camada 4

Camada 1 — Transport: o que acontece na conexão

1
Negociação de algoritmos
Cliente e servidor trocam listas de algoritmos suportados (KEX, ciphers, MACs) e escolhem a melhor interseção.
2
Key Exchange (KEX)
Diffie-Hellman ou ECDH gera segredo compartilhado sem transmiti-lo pela rede. Matemática de curva elíptica.
3
Verificação do servidor (Host Key)
Servidor prova identidade com sua chave privada. Cliente verifica contra ~/.ssh/known_hosts. Previne man-in-the-middle.
4
Session Keys derivadas
Chaves simétricas derivadas do KEX. Todo tráfego restante da sessão é cifrado com essas chaves.

Camada 2 — User Auth: métodos de autenticação

MétodoComo funcionaUso
publickeyCliente assina challenge com chave privada; servidor verifica com pública cadastradarecomendado
keyboard-interactiveDesafio genérico — PAM, OTP, 2FAok
passwordSenha transmitida cifrada ao servidorevitar
hostbasedConfia em combinação host+usuário remotolegado
noneSem 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

AlgoritmoStatus
curve25519-sha256★ Recomendado
ecdh-sha2-nistp256/384/521OK
diffie-hellman-group14-sha256Aceitável
diffie-hellman-group1-sha1Obsoleto — desabilitar

Cifras Simétricas — para dados em trânsito

AlgoritmoStatus
chacha20-poly1305@openssh.com★ Recomendado
aes256-gcm@openssh.com★ Recomendado
aes128-gcm@openssh.comOK
aes256-ctr / aes128-ctrOK
3des-cbc / arcfourObsoleto — remover

MACs — garante integridade dos pacotes

AlgoritmoStatus
hmac-sha2-256-etm@openssh.com★ Encrypt-then-MAC
hmac-sha2-512-etm@openssh.com★ Recomendado
hmac-sha1Obsoleto

🗝️ Tipos de Chave

Usadas tanto como host keys (identidade do servidor) quanto como user keys (identidade do usuário).

ed25519 ★ Padrão
256 bits (curva elíptica)
Rápido, compacto, seguro. Use este para tudo novo.
ssh-keygen -t ed25519
ecdsa OK
256 / 384 / 521 bits
Curvas NIST. Funciona bem, mas curve25519 é preferível.
ssh-keygen -t ecdsa -b 521
rsa Legado
4096 bits mínimo
Ainda OK para compatibilidade com sistemas antigos. Use 4096 bits.
ssh-keygen -t rsa -b 4096
dsa Morto
1024 bits (fixo)
Removido do OpenSSH 7.0+. Nunca usar.
—

📂 Estrutura de Arquivos

Cliente (~/.ssh/)

~/.ssh/
📄 config aliases e opções por host
📋 known_hosts fingerprints de servidores conhecidos
🔑 id_ed25519 chave PRIVADA (600)
🔓 id_ed25519.pub chave pública (644)
🔑 id_rsa chave PRIVADA RSA (600)
🔓 id_rsa.pub chave pública RSA (644)
📝 authorized_keys chaves que podem conectar aqui (600)
⚠️
Permissões incorretas = falha de autenticação

.ssh/ → 700 · chaves privadas → 600 · authorized_keys → 600

Servidor (/etc/ssh/)

/etc/ssh/
⚙️ sshd_config config principal do daemon
📁 sshd_config.d/ configs modulares (include)
🔑 ssh_host_ed25519_key host key privada
🔓 ssh_host_ed25519_key.pub host key pública
🔑 ssh_host_rsa_key host key RSA privada
🔓 ssh_host_rsa_key.pub host key RSA pública
ℹ️
Host keys identificam o servidor

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.

1
Cliente anuncia chave pública
Envia qual chave pública quer usar para autenticar.
2
Servidor verifica authorized_keys
Checa se a chave pública recebida está em ~/.ssh/authorized_keys.
3
Servidor gera e envia challenge
Número aleatório cifrado com a chave pública do cliente. Só quem tem a privada consegue decifrar.
4
Cliente decifra e assina resposta
Usa a chave privada para decifrar o challenge e assinar a resposta.
5
Servidor verifica assinatura → autenticado
Confirma que o cliente possui a chave privada correspondente. Acesso concedido.

Gerando par de chaves

bash
# 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

bash
# 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.

~/.ssh/config
# 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

HostName

IP ou FQDN real do servidor

User

Usuário padrão para conexão

Port

Porta SSH (padrão: 22)

IdentityFile

Chave privada específica para este host

ProxyJump

Conecta via outro host (bastion)

ForwardAgent

Encaminha ssh-agent ao servidor

LocalForward

Tunnel local → remoto

RemoteForward

Tunnel remoto → local

DynamicForward

Proxy SOCKS no host local

ServerAliveInterval

Keepalive: segundos entre pings

ControlMaster auto

Habilita multiplexação de conexões

ControlPersist 10m

Mantém master connection 10 minutos

IdentitiesOnly yes

Usa só chaves do IdentityFile (ignora agente)

StrictHostKeyChecking

yes / no / accept-new

AddKeysToAgent yes

Adiciona chave ao agente automaticamente

ControlPath

Caminho do socket de multiplexação

💻 Comandos de Conexão

bash
# 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.

FerramentaInstalaçãoMelhor paraRetoma?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.

bash — SCP
# 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.

ℹ️
-a = archive

Atalho para -rlptgoD: recursivo + preserva permissões, timestamps, symlinks, owner, group.

bash — RSYNC
# 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.

bash — conectar
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
sftp — comandos interativos
# 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.

bash — instalar
# Ubuntu / Debian
sudo apt install sshfs

# macOS
brew install macfuse sshfs
bash — usar
# 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.

bash — instalar e usar
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.

bash — instalar
# Script oficial
curl https://rclone.org/install.sh | sudo bash

# macOS
brew install rclone
bash — configurar e usar
# 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/
💡
Quando usar cada um?

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

localhost:8080
→
túnel SSH cifrado
→
servidor
→
:80
Você acessa localhost:8080 no seu navegador, e sai na porta 80 do servidor remoto
bash
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

localhost:3000
←
túnel SSH cifrado
←
servidor:9090
Quem acessa servidor:9090 chega na sua porta 3000 local. Útil para expor dev local na internet.
bash
ssh -R 9090:localhost:3000 user@host

Dynamic Forward (-D) — proxy SOCKS5

localhost:1080 (SOCKS5)
→
túnel SSH
→
qualquer destino
Configure o navegador para usar SOCKS5 localhost:1080. Todo tráfego sai pelo servidor remoto.
bash
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.

seu computador
→
bastion (público)
→
app-server (privado)
bash
# 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.

bash
# 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
⚠️
Agent Forwarding expõe o socket do agente no servidor remoto

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.

~/.ssh/config
Host *
    ControlMaster auto
    ControlPath   ~/.ssh/ctl/%r@%h:%p
    ControlPersist 10m
bash
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.

bash
# 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)

/etc/ssh/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
bash — gerenciar sshd
# 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

/etc/ssh/sshd_config
# 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

🗝️ authorized_keys — opções por chave

Cada linha pode ter opções que restringem o que aquela chave pode fazer.

~/.ssh/authorized_keys
# Formato: [opções] <tipo> <chave> [comentário]

# Deploy key: só permite executar git-shell
command="/usr/bin/git-shell -c \"$SSH_ORIGINAL_COMMAND\"",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... github-deploy

# Restringir a IPs específicos
from="203.0.113.10,10.0.0.0/8" ssh-ed25519 AAAA... restricted-key

# Forçar PTY + restringir tudo mais
restrict,pty ssh-ed25519 AAAA...

# Com expiração (OpenSSH 8.2+)
expiry-time="20261231" ssh-ed25519 AAAA...

📜 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.

bash
# 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.

~.
Fechar conexão (força)
~C
Prompt de comando SSH (adicionar tunnel em sessão ativa)
~#
Listar conexões encaminhadas
~?
Listar todos os escape codes
~Z
Suspender conexão (coloca em background)
~~
Enviar ~ literal
💡
~C é especialmente útil

Abre 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.

~/.ssh/config
Host github.com
    HostName ssh.github.com
    Port 443
    User git

Gerenciamento avançado de chaves

bash
# 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

~/.ssh/config
# 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

bash
# 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

  • 1
    Permissões de ~/.ssh/ (700) e authorized_keys (600) no servidor
  • 2
    authorized_keys contém a chave pública correta — sem quebra de linha no meio
  • 3
    sshd_config tem PubkeyAuthentication yes
  • 4
    StrictModes yes — home dir do usuário não pode ser writable por outros
  • 5
    SELinux / AppArmor não bloqueando acesso ao .ssh/
  • 6
    Firewall permitindo a porta SSH
  • 7
    ssh -vvv — mostra exatamente onde a autenticação falha

🛡️ Segurança — Boas Práticas

✅
PermitRootLogin no Sempre. Sem exceção.
✅
PasswordAuthentication no Autenticação só por chave pública.
✅
Passphrase nas chaves privadas Sempre. Use ssh-agent para não digitar toda hora.
✅
ed25519 por padrão RSA 4096 só quando precisa de compatibilidade com legado.
✅
Chave separada por contexto Uma para GitHub, outra para prod, outra para pessoal.
✅
fail2ban ou sshguard Bloqueia brute force automaticamente.
✅
AllowUsers / AllowGroups Restringe quem pode conectar no servidor.
✅
Atualizar OpenSSH Vulnerabilidades surgem. Manter atualizado é obrigatório.
✅
Auditar authorized_keys Remover chaves de ex-funcionários e obsoletas periodicamente.
✅
ssh-add -t 3600 Limitar tempo de vida das chaves no agente.
✅
Certificados SSH em escala Revogação centralizada, expiração nativa, auditoria.
✅
ProxyJump > Agent Forwarding Para bastions, prefira ProxyJump — não expõe o agente.
🚨
Mudar a porta 22 NÃO é segurança

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

🔌 Conexão
básica
ssh user@host
ssh -p 2222 user@host
com chave específica
ssh -i ~/.ssh/key user@host
comando remoto
ssh user@host "cmd"
com TTY
ssh -t user@host "sudo cmd"
📦 Arquivos
copiar arquivo
scp src user@host:dst
sincronizar diretório
rsync -avz src/ user@host:dst/
com remoção de extras
rsync -avz --delete src/ user@host:dst/
🗝️ Chaves
gerar
ssh-keygen -t ed25519
copiar para servidor
ssh-copy-id user@host
carregar no agente
ssh-add ~/.ssh/id_ed25519
listar no agente
ssh-add -l
🔀 Tunnels
local
ssh -L lport:host:rport user@host
remoto
ssh -R rport:host:lport user@host
SOCKS5
ssh -D 1080 user@host
background sem shell
ssh -fN -L 5432:localhost:5432 user@host
🔍 Debug
verbose
ssh -vvv user@host
testar config sshd
sshd -t
config efetiva
sshd -T
remover host de known_hosts
ssh-keygen -R hostname
🏗️ Bastion
conectar via jump host
ssh -J bastion user@destino
múltiplos saltos
ssh -J b1,b2 user@destino
scp via bastion
scp -J bastion user@host:/file .

Referências

📖

RFCs

RFC 4251 · 4252 · 4253 · 4254

📚

OpenSSH

man ssh · man sshd_config · man ssh_config · man ssh-keygen

🦊

Mozilla Guidelines

infosec.mozilla.org/guidelines/openssh