Pular para o conteúdo
ecdsa.com
← Todos os artigos

ssh-keygen em 2026: tipos de chave, frase secreta e agente

Da versão 10.0 à 10.6, o OpenSSH mudou mais padrões do que a maioria das pessoas percebeu: troca de chaves pós-quântica, um tipo de assinatura híbrida com ML-DSA, mais rodadas de KDF, sockets do agente no seu diretório home. Todos os comandos abaixo foram executados no OpenSSH 10.6p1, e a saída mostrada é a real.

Resposta curta. Rode ssh-keygen -t ed25519 -C "you@host-year" e proteja a chave com uma frase secreta; o Ed25519 é o padrão desde o OpenSSH 9.5. Se você tem uma chave de segurança FIDO2, prefira -t ed25519-sk (ou -t ecdsa-sk quando o autenticador não oferece Ed25519), para que a chave privada nunca fique no disco. Use RSA apenas em sistemas que não aceitam outra coisa e, nesse caso, com 3072 bits ou mais: desde 14 de outubro de 2026, o GitHub recusa novas chaves RSA menores. Carregue as chaves no agente com um tempo de vida (ssh-add -t 8h), não encaminhe o agente para hosts que você não controla (use ProxyJump) e restrinja as chaves a destinos específicos com ssh-add -h. Em frotas de servidores, troque as entradas espalhadas de authorized_keys por certificados SSH de curta duração. A proteção pós-quântica da sessão já está ativa: o OpenSSH 10 negocia mlkem768x25519-sha256 por padrão e avisa quando o servidor não consegue fazer o mesmo. O novo tipo de assinatura híbrida ssh-mldsa44-ed25519 (OpenSSH 10.6) já vale um teste, mas ainda não vale implantá-lo como sua única chave.

Os comandos rodaram em debian:forky-20261005-slim com os pacotes Debian openssh-client e openssh-server 1:10.6p1-1, em 20 de outubro de 2026. Todas as chaves foram geradas para este artigo.

Qual tipo de chave

-tO que éQuando usar
ed25519 (padrão)Ed25519, chave pública de 32 bytes, assinaturas determinísticasQuase sempre
ed25519-sk, ecdsa-skChave FIDO2: o segredo fica no autenticador, e cada assinatura exige um toqueVocê tem uma chave de segurança e o servidor roda OpenSSH 8.2 ou posterior
ecdsaECDSA em P-256, P-384 ou P-521Uma política exige curvas NIST
rsaRSA, 3072 bits por padrão desde o OpenSSH 8.0Servidores antigos, appliances, alguns HSMs
mldsa44-ed25519Assinatura híbrida ML-DSA-44 + Ed25519, nova na 10.6Testes de autenticação pós-quântica

O DSA acabou: o OpenSSH 10.0 (abril de 2025) o removeu, “concluindo o processo de descontinuação iniciado em 2015”. As chaves RSA em si continuam boas; o que o OpenSSH 8.8 (setembro de 2021) desativou foi o algoritmo de assinatura ssh-rsa, que calcula o hash com SHA-1. A mesma chave RSA assina com rsa-sha2-256 ou rsa-sha2-512, e é por isso que o erro do servidor sobre ssh-rsa costuma ser resolvido atualizando o cliente, e não substituindo a chave. O GitHub segue a mesma lógica: ele vai remover as assinaturas ssh-rsa em 13 de janeiro de 2027, depois de desativações temporárias (brownouts) em 4 de novembro e 9 de dezembro de 2026, e desde 14 de outubro de 2026 só aceita novas chaves RSA a partir de 3072 bits.

Os tamanhos, conforme gravados pelo ssh-keygen 10.6 (a linha .pub inclui o comentário):

Chaves RSA e ECDSA padrão, a híbrida e a chave Ed25519 da próxima seção
ssh-keygen -q -t rsa -N '' -f ~/rsa_default
ssh-keygen -q -t ecdsa -N '' -f ~/ecdsa_default
ssh-keygen -q -t mldsa44-ed25519 -N '' -f ~/.ssh/id_mldsa44_ed25519
for f in ~/rsa_default ~/ecdsa_default ~/.ssh/id_ed25519 ~/.ssh/id_mldsa44_ed25519; do
  ssh-keygen -l -f "$f.pub"
  printf '  public key line: %s bytes, private key file: %s bytes\n' "$(wc -c < "$f.pub")" "$(wc -c < "$f")"
done
Saída (OpenSSH 10.6p1)
3072 SHA256:NGv36ZHCwauN4GGrdKSDZPnKTn6nFuLSVRS01/eSXOs alice@59151e7fff6c (RSA)
  public key line: 572 bytes, private key file: 2602 bytes
256 SHA256:4ODqYFVTGSwjx7pfis5ZtZ02PKaSd15alII7RIHPhE8 alice@59151e7fff6c (ECDSA)
  public key line: 180 bytes, private key file: 513 bytes
256 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026 (ED25519)
  public key line: 99 bytes, private key file: 464 bytes
512 SHA256:oqHqur1575V136Khl2P7Gaa6rM+2dPT51B6YfjLSxB4 alice@59151e7fff6c (MLDSA44-ED25519)
  public key line: 1868 bytes, private key file: 3982 bytes

A linha da chave pública híbrida é 19 vezes maior que a de uma chave Ed25519. Isso pesa em arquivos authorized_keys, em certificados e em tudo o que guarda chaves numa coluna de banco de dados dimensionada para Ed25519. A comparação Ed25519 vs RSA trata do par clássico em detalhes.

Gerar uma chave

Gerar uma chave Ed25519 com um comentário que diz onde ela fica
ssh-keygen -t ed25519 -C "alice@laptop-2026" -N 'correct horse battery staple' -f ~/.ssh/id_ed25519
Saída (OpenSSH 10.6p1)
Created directory '/home/alice/.ssh'.
Generating public/private ed25519 key pair.
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026
The key's randomart image is:
+--[ED25519 256]--+
|     ..o*.....   |
| o  . .=... =.   |
|. o  .. +. + o.  |
| . . . o =. . ...|
|  o   + S ..   ..|
| . . o + B       |
|  . * = * o .    |
|   o E = o.+     |
|      o oo. .    |
+----[SHA256]-----+

O -N passa a frase secreta na linha de comando só porque o laboratório é automatizado por script; no uso interativo, omita a opção e o ssh-keygen pede a frase, que assim não vai parar no histórico do shell. O comentário é texto livre gravado na chave pública: nome, máquina e ano tornam possível auditar um authorized_keys anos depois. A impressão digital (SHA256:…) é o que os servidores registram em log, então anote-a sempre que cadastrar a chave em algum lugar.

Frase secreta e rodadas de KDF

Sem frase secreta, o arquivo da chave privada é a chave: um backup roubado, uma imagem do notebook ou uma pasta de sincronização mal configurada basta para entregá-la. Com frase secreta, o arquivo é criptografado com uma chave derivada pelo bcrypt_pbkdf. O formato de chave privada do OpenSSH registra a cifra, o KDF e o número de rodadas em um cabeçalho que qualquer pessoa consegue ler sem a frase secreta:

kdfinfo.py: ler a cifra, o KDF e as rodadas de uma chave privada OpenSSH
"""Print the cipher, KDF and bcrypt rounds from the header of an OpenSSH private key file (openssh-key-v1)."""
import base64
import struct
import sys

text = open(sys.argv[1]).read()
body = "".join(line for line in text.splitlines() if not line.startswith("-----"))
blob = base64.b64decode(body)
magic = b"openssh-key-v1\0"
assert blob.startswith(magic), "not an OpenSSH private key"
pos = len(magic)


def string():
    global pos
    (length,) = struct.unpack(">I", blob[pos : pos + 4])
    value = blob[pos + 4 : pos + 4 + length]
    pos += 4 + length
    return value


cipher = string().decode()
kdf = string().decode()
options = string()
line = f"cipher={cipher} kdf={kdf}"
if kdf == "bcrypt":
    (salt_len,) = struct.unpack(">I", options[:4])
    (rounds,) = struct.unpack(">I", options[4 + salt_len : 8 + salt_len])
    line += f" salt={salt_len} bytes rounds={rounds}"
print(line)
Rodadas padrão e, depois, o custo do desbloqueio com 32, 100 e 500 rodadas
python3 kdfinfo.py ~/.ssh/id_ed25519
for r in 32 100 500; do
  ssh-keygen -q -p -a $r -P 'correct horse battery staple' -N 'correct horse battery staple' -f ~/.ssh/id_ed25519 >/dev/null
  s=$(date +%s.%N); ssh-keygen -y -P 'correct horse battery staple' -f ~/.ssh/id_ed25519 >/dev/null; e=$(date +%s.%N)
  printf 'rounds=%s unlock=%.2fs\n' $r $(echo "$e - $s" | bc)
done
Saída (um núcleo arm64 no Docker em um Apple M4 Max)
cipher=aes256-ctr kdf=bcrypt salt=16 bytes rounds=32
rounds=32 unlock=0.16s
rounds=100 unlock=0.52s
rounds=500 unlock=2.59s

O padrão era de 16 rodadas até o OpenSSH 9.4, passou a 24 a partir da 9.4 e é de 32 desde a 10.6. O custo cresce linearmente com as rodadas, como observam as notas de versão da 10.6 (“ao contrário do bcrypt(3), que é exponencial”), então os números acima escalam de forma previsível: escolha o maior valor cujo atraso de desbloqueio você aceite, porque um invasor que copiou o arquivo paga o mesmo preço por tentativa. O ssh-keygen -p -a 100 -f ~/.ssh/id_ed25519 criptografa de novo uma chave existente; se você a carrega no agente uma vez por sessão, paga o atraso uma única vez. Desde a 10.6, o OpenSSH recusa chaves com mais de um milhão de rodadas, para que um arquivo de chave malicioso não consiga travar um serviço que o analisa.

A frase secreta protege o arquivo em repouso. Ela não adianta nada depois que a chave é descriptografada em um agente numa máquina comprometida, e é aí que entram as chaves em hardware.

Chaves em hardware: -sk

As chaves ed25519-sk e ecdsa-sk (OpenSSH 8.2 e posteriores) guardam o segredo em um autenticador FIDO2, como uma YubiKey ou um autenticador de plataforma. O arquivo ~/.ssh/id_ed25519_sk passa a conter apenas um handle da chave, de que o autenticador precisa para reconstruir a chave; sem o dispositivo, ele é inútil. Cada assinatura exige a presença do usuário (um toque) e, com -O verify-required, também um PIN. As opções que importam, citadas do ssh-keygen(1):

  • -O resident grava o handle da chave no autenticador, para que ssh-keygen -K ou ssh-add -K possam carregá-la em outro computador. O manual avisa que isso “aumenta a probabilidade de um invasor conseguir usar um autenticador roubado”, então combine a opção com um PIN.
  • -O verify-required exige a verificação do usuário (atualmente, um PIN) a cada assinatura; o servidor pode exigi-la com a opção verify-required no authorized_keys.
  • -O application=ssh:work separa várias chaves residentes no mesmo dispositivo; a string precisa começar com ssh:.
  • -O no-touch-required dispensa o toque, e o sshd recusa essas assinaturas, a menos que o authorized_keys as permita explicitamente.
  • -O write-attestation=path salva o atestado do autenticador, o que permite a uma organização provar, no cadastro, que a chave foi criada em hardware aprovado.
Cadastro típico de uma chave residente protegida por PIN (exige um autenticador FIDO2)
ssh-keygen -t ed25519-sk -O resident -O verify-required -O application=ssh:work -C "alice@yubikey-2026"

Não executamos este comando: o contêiner não tem autenticador, e uma transcrição sem ele só mostraria o erro. Alguns autenticadores mais antigos implementam apenas P-256; para eles, use ecdsa-sk. Chaves de plataforma também funcionam, mas chaves guardadas no hardware seguro de um notebook têm suas próprias vantagens e desvantagens, descritas em chaves em hardware.

Pós-quântico: troca de chaves agora, assinaturas depois

As duas metades do SSH têm prazos diferentes. As chaves de sessão vêm da troca de chaves; se ela for quebrada mais tarde, o tráfego gravado pode ser descriptografado (coletar agora, descriptografar depois). As assinaturas de host e de usuário só importam no momento da conexão: um futuro computador quântico não consegue voltar no tempo e forjar um login que já aconteceu. Por isso, o OpenSSH mudou primeiro a troca de chaves:

  • sntrup761x25519-sha512 está ativo por padrão desde o OpenSSH 9.0 (2022);
  • mlkem768x25519-sha256, o ML-KEM-768 combinado com o X25519, é o padrão desde o OpenSSH 10.0 (abril de 2025) e agora está especificado na RFC 10042 (informativa, 2026);
  • desde a 10.1, o cliente exibe um aviso quando a sessão recorre a uma troca clássica, e desde a 10.6 o servidor registra isso em log.
ssh -v localhost true, configurações padrão nos dois lados (filtrado com grep)
debug1: kex: algorithm: mlkem768x25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: Server host key: ssh-ed25519 SHA256:Qw4tNHnCo8UwS2qNXROrEm8RP+d+ccaVbwAzv8lLX+I
debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c agent
debug1: Server accepts key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c agent
Authenticated to localhost ([::1]:22) using "publickey".

Com um servidor restrito a KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256, o cliente com a configuração padrão exibiu:

Saída do cliente quando o servidor não oferece troca de chaves pós-quântica
** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html

Observamos dois detalhes: o cliente fica em silêncio quando você restringe KexAlgorithms a um método clássico (o aviso é dirigido aos servidores), e o servidor registra em log cada sessão desse tipo, por exemplo connection from ::1 port 38814 is not using a post-quantum key exchange algorithm: "curve25519-sha256" [preauth]. WarnWeakCrypto no-pq-kex dentro de um bloco Match host silencia o cliente para um host que você não consegue corrigir, como sugere a página openssh.com/pq.html. O GitHub anunciou mlkem768x25519-sha256 para o github.com a partir de 14 de outubro de 2026; em 20 de outubro, nosso cliente 10.6 o negociou com git@github.com.

As assinaturas são o segundo passo. O OpenSSH 10.4 adicionou uma assinatura composta experimental de ML-DSA-44 e Ed25519; a 10.6 a ativou com o nome ssh-mldsa44-ed25519, especificado no rascunho do grupo de trabalho SSHM draft-ietf-sshm-composite-sigs. Chaves criadas com o código experimental da 10.4 precisam ser geradas de novo. No pacote 10.6 do Debian, o ssh-keygen -A criou ssh_host_mldsa44_ed25519_key ao lado das chaves de host RSA, ECDSA e Ed25519, e o tipo fica no fim da lista padrão de HostKeyAlgorithms, então os clientes continuam escolhendo Ed25519. Pedir o tipo explicitamente funciona de ponta a ponta:

ssh -v -o HostKeyAlgorithms=ssh-mldsa44-ed25519 -o IdentitiesOnly=yes -i ~/.ssh/id_mldsa44_ed25519 (filtrado)
debug1: kex: host key algorithm: ssh-mldsa44-ed25519
debug1: Server host key: ssh-mldsa44-ed25519 SHA256:UVOUu+csMH8i8Zd/oWzokAGfzRYFetOncVzB4vYeMgQ
debug1: Server accepts key: /home/alice/.ssh/id_mldsa44_ed25519 MLDSA44-ED25519 SHA256:oqHqur1575V136Khl2P7Gaa6rM+2dPT51B6YfjLSxB4 explicit
Authenticated to localhost ([::1]:22) using "publickey".

As duas metades assinam a mesma mensagem com separação de domínio, e “a falha de qualquer uma das operações de verificação DEVE fazer a verificação da assinatura composta falhar”, então hoje a híbrida não é mais fraca que a Ed25519. O custo está no tamanho (uma assinatura de 2.484 bytes por autenticação, segundo o rascunho) e na compatibilidade: servidores, plataformas de hospedagem de código, bastiões e bibliotecas que não conhecem o tipo não vão aceitar a chave. Gere uma, teste-a nos hosts que você administra e mantenha sua chave Ed25519 cadastrada ao lado dela.

O agente e o encaminhamento do agente

O ssh-agent guarda chaves descriptografadas e assina quando solicitado; os programas chegam até ele pelo socket indicado em SSH_AUTH_SOCK. Desde o OpenSSH 10.1, esse socket fica em ~/.ssh/agent, e não em /tmp. Adicione as chaves com um tempo de vida, para que uma sessão esquecida não as mantenha desbloqueadas para sempre:

Iniciar um agente e adicionar a chave por oito horas (o laboratório fornece a frase secreta via SSH_ASKPASS)
eval "$(ssh-agent -s)" >/dev/null
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
ssh-add -t 8h ~/.ssh/id_ed25519
ssh-add -l
Saída
SSH_AUTH_SOCK=/home/alice/.ssh/agent/s.eaeHp0xOjD.local.660.o5M944i4eW
Identity added: /home/alice/.ssh/id_ed25519 (alice@laptop-2026)
Lifetime set to 08:00:00
256 SHA256:I72RDcR38Z+glA2IhaHUj/h844afNwkK9siDEGHv24c alice@laptop-2026 (ED25519)

O AddKeysToAgent no ~/.ssh/config faz o mesmo no primeiro uso e aceita um tempo de vida (AddKeysToAgent 8h) ou confirm, que pede confirmação antes de cada assinatura, como o ssh-add -c.

O encaminhamento do agente (ssh -A, ForwardAgent yes) expõe esse socket no host remoto. O ssh_config(5) descreve o risco sem rodeios: “um invasor não consegue obter material de chave do agente, mas consegue executar operações com as chaves”. Quem tem root no host remoto consegue fazer login como você em qualquer lugar onde suas chaves funcionam, enquanto você continuar conectado. Dois hábitos melhores:

  • Use um salto em vez de encaminhar. ssh -J bastion target (ou ProxyJump bastion na configuração) abre a segunda conexão a partir da sua máquina, por um fluxo TCP encaminhado; o bastião nunca vê seu agente.
  • Restrinja as chaves. O ssh-add -h (OpenSSH 8.9 e posteriores) vincula uma chave a destinos identificados pelas chaves de host do known_hosts e, quando você encaminha o agente mesmo assim, a saltos (bastion>target).
dest.sh (trecho): uma chave que só funciona para prod-host
ssh-add -h prod-host ~/agent_only_key
ssh -o BatchMode=yes prod-host 'echo signed in on prod-host'
ssh -v -o BatchMode=yes build-host true 2>&1 | grep -iE 'agent|Offering|Permission denied|Authenticated|identity'
Saída (encurtada: as linhas de sondagem dos arquivos de identidade foram omitidas)
Identity added: /home/alice/agent_only_key (alice@laptop)
signed in on prod-host
debug1: get_agent_identities: bound agent to hostkey
debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities
debug1: Offering public key: /home/alice/.ssh/id_ed25519 ED25519 SHA256:MA2nEhBnMlCkX3pWWgPtff90dRZF9D9k8i2svCUK1II
alice@127.0.0.2: Permission denied (publickey,password).

O agente vinculou a sessão à chave de host do build-host e depois não listou nenhuma identidade para ela: a chave existe, mas não para esse destino. O manual é cuidadoso quanto ao limite: uma restrição “não impede que um invasor com acesso a um SSH_AUTH_SOCK remoto o encaminhe de novo e o use em outro host (mas só para um destino permitido)”.

Certificados em vez de authorized_keys

Copiar chaves públicas para o authorized_keys de cada servidor não escala e transforma a revogação num problema de busca. Um certificado SSH é uma chave pública assinada por uma chave de CA junto com uma identidade, principals, um número de série e uma janela de validade. Os servidores confiam na CA uma única vez (TrustedUserCAKeys) e consultam uma lista de revogação (RevokedKeys):

Assinar uma chave de usuário por 8 horas, fazer login, revogá-la pelo número de série e tentar de novo (executado como root no servidor do laboratório)
ssh-keygen -s /etc/ssh/user_ca -I "alice@example.com 2026-10-20" -n alice -V +8h -z 1042 /home/alice/.ssh/id_cert_user.pub
ssh-keygen -L -f /home/alice/.ssh/id_cert_user-cert.pub
su - alice -c 'ssh -o IdentitiesOnly=yes -o IdentityAgent=none -i ~/.ssh/id_cert_user localhost "echo logged in with certificate"'
echo "serial: 1042" > /tmp/revoke.txt
ssh-keygen -k -u -s /etc/ssh/user_ca.pub -f /etc/ssh/revoked.krl /tmp/revoke.txt
ssh-keygen -Q -f /etc/ssh/revoked.krl /home/alice/.ssh/id_cert_user-cert.pub
su - alice -c 'ssh -o IdentitiesOnly=yes -o IdentityAgent=none -o BatchMode=yes -i ~/.ssh/id_cert_user localhost true'
Saída (o sshd roda com TrustedUserCAKeys /etc/ssh/user_ca.pub e RevokedKeys /etc/ssh/revoked.krl)
Signed user key /home/alice/.ssh/id_cert_user-cert.pub: id "alice@example.com 2026-10-20" serial 1042 for alice valid from 2026-10-20T14:33:00 to 2026-10-20T22:34:33
/home/alice/.ssh/id_cert_user-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:eVstR5lK6VBztjl2AYyWcv8C6xwNahEEVSrQpe7Y/LE
        Signing CA: ED25519 SHA256:+URM6AMiGUu+gv/gxoQgpOhHP4CUN1fznXWDlVxorbY (using ssh-ed25519)
        Key ID: "alice@example.com 2026-10-20"
        Serial: 1042
        Valid: from 2026-10-20T14:33:00 to 2026-10-20T22:34:33
        Principals: 
                alice
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc
logged in with certificate
Revoking from /tmp/revoke.txt
/home/alice/.ssh/id_cert_user-cert.pub (alice@ci-runner): REVOKED
alice@localhost: Permission denied (publickey).

O sshd registrou key ED25519-CERT SHA256:eVst… revoked by file /etc/ssh/revoked.krl. Repare nas extensões padrão: um certificado permite o encaminhamento do agente e de portas, a menos que você assine com -O clear e adicione de volta só o necessário (-O permit-pty). Mantenha a chave da CA offline ou em um HSM e emita certificados por horas, não por anos: com validades curtas, a maioria das revogações se torna desnecessária. Os certificados de host (-h ao assinar, @cert-authority no known_hosts) eliminam da mesma forma a pergunta de confiança no primeiro uso.

Rotação de chaves

  • Chaves de usuário. Gere a chave nova, adicione a chave pública dela ao lado da antiga em todos os lugares (servidores, plataformas de hospedagem de código, segredos de CI), conecte com -i new_key -o IdentitiesOnly=yes para confirmar que ela funciona e só então remova a linha antiga. Um comentário com data mostra qual linha é a antiga.
  • Chaves de host. O UpdateHostKeys está ativo por padrão desde o OpenSSH 8.5 (a menos que você altere o UserKnownHostsFile ou ative o VerifyHostKeyDNS): depois da autenticação, o servidor anuncia todas as suas chaves de host e o cliente registra as novas, então um servidor pode publicar uma substituta antes de aposentar a chave antiga. Clientes que raramente se conectam perdem essa janela; os certificados de host evitam o problema.
  • Algoritmos. O mesmo mecanismo serve para uma migração: adicione uma chave de host Ed25519 (e, mais tarde, uma híbrida), deixe os clientes a conhecerem e então remova a chave RSA.
  • Inventário. O ssh-keygen -l -f authorized_keys imprime uma impressão digital por linha; compare o resultado com as linhas Accepted publickey … SHA256: do log do sshd para encontrar chaves que ninguém usa.

Erros comuns

  • Um arquivo de chave legível por todos. O ssh se recusa a usá-lo e imprime WARNING: UNPROTECTED PRIVATE KEY FILE!. Aplique chmod 600 na chave e 700 no diretório .ssh.
  • Frase secreta errada ou chave convertida. incorrect passphrase supplied to decrypt private key e error in libcrypto parecem semelhantes; a segunda mensagem costuma indicar que o arquivo está danificado ou em um formato que o build não consegue ler. As bibliotecas precisam receber a frase secreta explicitamente, como mostra o erro this private key is passphrase protected do Go.
  • Chaves demais no agente. O sshd desiste depois de MaxAuthTries (6) tentativas falhas e desconecta com Too many authentication failures, e cada chave que o cliente testa pode consumir uma tentativa (servidores OpenSSH 10.6 permitem seis consultas extras do tipo “você aceitaria esta chave?”, PubkeyOptions max-pk-ok). Defina IdentityFile e IdentitiesOnly yes por host. Se nenhuma chave oferecida estiver cadastrada, você recebe Permission denied (publickey).
  • O agente se recusa. agent refused operation significa que o servidor aceitou a chave, mas o agente não quis assinar: uma chave FIDO que não foi tocada a tempo, uma confirmação que ele não consegue exibir, um token bloqueado ou um arquivo de chave no disco que não corresponde mais ao que o agente guarda.
  • Servidores antigos. no matching host key type found. Their offer: ssh-rsa significa que o servidor só consegue assinar com SHA-1. Atualize o servidor; um HostKeyAlgorithms +ssh-rsa por host é uma exceção temporária, nunca uma configuração global.
  • Ignorar uma chave de host alterada. REMOTE HOST IDENTIFICATION HAS CHANGED é ou uma rotação planejada que você pode confirmar por outro canal, ou exatamente o ataque para o qual a verificação existe. Remova a linha antiga com ssh-keygen -R host só depois de saber qual dos dois é.

Lista de verificação

  1. ssh-keygen -t ed25519 (ou -t ed25519-sk com uma chave de segurança), uma frase secreta e um comentário com dono, máquina e ano.
  2. Aumente as rodadas de KDF até o atraso que você aceita (aqui, -a 100 custa cerca de meio segundo).
  3. Uma chave por dispositivo; nunca copie chaves privadas entre máquinas.
  4. Agente com tempos de vida; IdentitiesOnly yes por host; ProxyJump em vez de ForwardAgent; ssh-add -h quando o encaminhamento for inevitável.
  5. Frotas: certificados de usuário e de host com validade curta, chave da CA offline e uma KRL em cada servidor.
  6. Procure kex: algorithm: mlkem768x25519-sha256 na saída do ssh -v; trate o aviso pós-quântico como um chamado para atualizar o servidor.
  7. Teste chaves mldsa44-ed25519 nos seus próprios servidores; mantenha uma chave clássica cadastrada até que todos os sistemas do outro lado aceitem a híbrida.

Fontes