Para: qualquer pessoa que alcance produção por SSH a partir de um ambiente efêmero — um pod de nuvem com GPU, um runner de CI, uma VM descartável. Nenhum passo de ataque — só tornar as chaves de menor privilégio para que um vazamento cause menos dano. Para o básico de separar chaves, veja o checklist de base.
A visão deste site: trate ambientes efêmeros como não confiáveis
Computação descartável costuma pular o fortalecimento — é um lugar que pode ser comprometido. Coloque ali uma chave de root de produção e o comprometimento desse ambiente vira o comprometimento da produção. Este site usa uma chave distinta por host, restringe cada uma a um propósito e remove chaves assim que ficam sem uso (→ chaves separadas para minimizar o dano). Tratar uma chave não como "uma conveniência", mas como "o ativo mais crítico, que dá acesso a todos os servidores se vazar" é, no fim, a abordagem mais segura.
✗ chave de root em um ambiente efêmero
ambiente comprometido → root em produção com aquela chave → alcança arquivos, segredos e outros serviços — tudo.
○ chave sem root restrita a comando
mesmo que a mesma chave vaze, ela só consegue rodar o único comando especificado. Sem shell, sem encaminhamento — o dano fica contido a uma operação.
Por que uma chave de root em um ambiente efêmero é perigosa
Ambientes efêmeros tendem a pular o fortalecimento ("vamos apagá-lo logo"), o que os torna um alvo fácil e um ponto de passagem conveniente para atacar a produção. Uma chave de root de produção ali torna o dano o maior possível.
Digamos que você suba um pod para processamento e, para trabalhar em produção a partir dele, cadastre uma chave no authorized_keys do root. Prático — mas se esse pod for comprometido, o atacante entra em produção como root com aquela chave. Quer o ataque comece com um RCE ou com um vazamento de chave, o resultado final é o mesmo: produção tomada com uma chave roubada (relacionado: uma chave roubada via RCE e usada em cobrança fraudulenta).
Três passos para chaves de menor privilégio
Mude de "conceder poder total porque é conveniente" para "limitar o que ela pode fazer ao mínimo".
Remova a chave de root do ambiente efêmero
~/.ssh/authorized_keys de produção. Se ociosas, removê-las não tem impacto. Primeiro, não deixe chaves sem uso no lugar.Mesmo que precise de novo, não volte para root
Restrinja a chave a uma única operação
command="..." e restrict à linha da chave no authorized_keys. Mesmo um login bem-sucedido só consegue rodar o único comando especificado, com encaminhamento de porta e shell desativados. Um vazamento fica contido àquela única operação.# Register a key restricted to ONE operation in a non-root user's authorized_keys.
# Logging in with it can run only the given command; forwarding and PTY are off.
command="/usr/local/bin/deploy-pull",restrict ssh-ed25519 AAAA...rest-of-public-key deploy@cirestrict desativa encaminhamento, encaminhamento de agente, PTY, X11 e mais de uma só vez; command="..." fixa a ação executável a uma só coisa. O movimento básico é uma chave restrita a um único propósito — só puxar um deploy, só rodar um script específico — criada por caso de uso.
Um cenário comum (perigoso)
- cadastrar uma chave no root de produção a partir de um pod/CI
- deixar chaves já cumpridas no lugar
- reutilizar uma chave em muitos hosts
- espalhar chaves que concedem um shell completo
O cenário de menor privilégio
- alcançar produção apenas como um usuário sem root
- chaves limitadas a uma operação (restritas a comando)
- separar chaves por host e propósito
- remover chaves do authorized_keys no momento em que estão sem uso
Trate uma chave reutilizada como seu ativo mais crítico
Pense em uma chave como "uma conveniência" e você a reutiliza e esquece de apagá-la. Em vez disso, trate-a como o ativo mais crítico, que dá acesso a todos os servidores se vazar. Separe por host e propósito, mantenha as chaves de produção fora de ambientes efêmeros e sempre remova-as após o uso. Só isso já impede que um vazamento se espalhe para tudo.
As principais restrições que você pode pôr em uma linha de chave
No OpenSSH, opções escritas no início de uma linha de chave no authorized_keys reduzem o que aquela chave pode fazer. As mais comuns:
| Opção | O que restringe | Quando usar |
|---|---|---|
command="..." | Logar com a chave roda só o comando especificado; qualquer comando enviado pelo cliente é ignorado | Chaves que devem fazer um único trabalho fixo, como puxar um deploy ou fazer um backup |
restrict | Desativa de uma vez encaminhamento de porta, de agente e de X11, alocação de PTY e a execução de ~/.ssh/rc (OpenSSH 7.2+) | Quase toda chave de automação; reative só o que precisar, por exemplo pty |
from="..." | Além da chave, o nome de host ou o endereço IP do cliente precisa constar na lista | CI ou servidores de trabalho com IP de origem fixo |
expiry-time="..." | A chave deixa de ser aceita depois da data/hora indicada (OpenSSH 7.7+) | Chaves que devem funcionar só para um trabalho temporário |
PermitRootLogin (no sshd_config) | Se o login direto como root é permitido; forced-commands-only permite root só para chaves com command= | no, a menos que você realmente precise de acesso direto como root |
As notas de versão do OpenSSH descrevem o restrict como incluindo "todas as restrições de chave atuais e futuras". Em vez de listar no-pty, no-port-forwarding e outros um a um, adicione restrict e reative só o que precisar, para que nada escape quando surgirem recursos novos.
# Also narrowing the source and the lifetime (the IP is a documentation address)
from="192.0.2.10",expiry-time="20261231",command="/usr/local/bin/deploy-pull",restrict ssh-ed25519 AAAA...rest-of-public-key deploy@ci-2026-10Se você gerencia acesso com prazo em muitas chaves, certificados do OpenSSH são outra opção (assine com ssh-keygen -s, defina a validade com -V e restrinja com force-command ou source-address). Para um cenário pequeno, as opções na linha da chave bastam para começar.
Como verificar o seu próprio ambiente
Estas verificações só leem as configurações e os logs de servidores que você administra. Ao mudar configurações, mantenha uma sessão SSH aberta, teste uma nova conexão a partir de outro terminal e só feche a sessão antiga quando souber que não ficou trancado do lado de fora.
1. Liste as chaves cadastradas
# Show the fingerprint and comment of each key registered for root and each user
sudo ssh-keygen -lf /root/.ssh/authorized_keys
sudo ssh-keygen -lf /home/deploy/.ssh/authorized_keysCada chave imprime uma linha como 256 SHA256:... deploy@ci (ED25519). Use o comentário (a parte deploy@ci no fim) para separar chaves de origem desconhecida, chaves de ambientes efêmeros que você já encerrou e chaves cadastradas no root. O nome de arquivo antigo authorized_keys2 também é lido por padrão; então, se ele existir, verifique-o da mesma forma.
2. Verifique a configuração que o sshd realmente usa
# Check the syntax, then print the settings actually in effect
sudo sshd -t
sudo sshd -T | grep -iE 'permitrootlogin|authorizedkeysfile|pubkeyauthentication|passwordauthentication'O sshd -T imprime os valores efetivos depois de ler os arquivos de configuração. Se permitrootlogin estiver como yes ou prohibit-password, qualquer pessoa com uma chave pode logar diretamente como root. Se authorizedkeysfile apontar para outro lugar que não o padrão, inclua esse local no passo 1.
3. Veja quais chaves são de fato usadas
Depois de um login por chave bem-sucedido, o sshd normalmente registra uma linha como Accepted publickey for deploy from 192.0.2.10 port 50022 ssh2: ED25519 SHA256:.... Leia-a em /var/log/auth.log no Debian e no Ubuntu, em /var/log/secure em sistemas da família Red Hat, ou com journalctl -u ssh em hosts com systemd (-u sshd em sistemas da família Red Hat).
Comparar essas impressões digitais com a lista do passo 1 mostra quais chaves ficam sem uso. O relatório do NIST sobre gestão de chaves SSH (NISTIR 7966) sugere acompanhar os logs por cerca de 6 a 12 meses antes de remover chaves sem uso, para não remover por engano chaves usadas raramente. Chaves que você sabe que já foram encerradas, como a de um ambiente efêmero, podem sair na hora.
4. Verifique o lado efêmero
- Há uma chave privada que alcança produção guardada nos segredos do CI ou no
~/.sshde um pod de GPU? - Você se conecta ao ambiente efêmero com
ssh -A(encaminhamento de agente) a caminho da produção? - Uma mesma chave é compartilhada entre vários sistemas de CI ou servidores?
Erros comuns e como corrigi-los
- Apagar a chave privada no lado efêmero e parar aí: se a chave privada já foi copiada, ela continua funcionando enquanto a chave pública ficar no servidor. Sempre remova a linha correspondente do
authorized_keysde produção. - Rodar o comando do cliente (a variável de ambiente
SSH_ORIGINAL_COMMAND) como está dentro do script chamado porcommand=: isso equivale a não ter restrição. Use o valor só quando ele corresponder exatamente a uma de um conjunto fixo de opções. - Trocar para um usuário sem root mas liberar sudo sem restrição: se esse usuário pode rodar qualquer coisa com sudo sem senha, ele é na prática root. Se o sudo for necessário, limite-o a um comando no sudoers.
- Entrar em um ambiente efêmero com
ssh -A: qualquer pessoa com privilégios suficientes ali pode usar as chaves carregadas no seu agente local por meio da conexão encaminhada (o manual do OpenSSH alerta sobre isso). Se precisar passar por um host, usessh -J(conexão via jump host). - Deixar chaves sem comentário: numa revisão você não consegue saber de onde vieram. Adicione o propósito e a data ao criá-las, por exemplo
ssh-keygen -C "deploy@ci-2026-10". - Compartilhar uma chave entre várias pessoas ou ambientes: o NISTIR 7966 também pede que se proíba compartilhar chaves privadas ou copiá-las para outros sistemas. Você não consegue rastrear quem a usou onde, e um vazamento obriga a substituí-la em todo lugar.
Um exemplo real: chaves SSH estavam entre o que uma ferramenta de CI comprometida coletou
Em março de 2026, apareceu uma versão maliciosa do scanner de vulnerabilidades de código aberto Trivy, e as tags dele no GitHub Actions foram reescritas. Segundo a desenvolvedora, Aqua Security, o código malicioso coletava credenciais dos runners de CI e as enviava para fora, e entre os alvos estavam chaves privadas em ~/.ssh, authorized_keys, known_hosts e chaves de host SSH. A Aqua pede que quem possa ter rodado uma versão afetada trate como exposto todo segredo que aquele pipeline conseguia ler, chaves SSH incluídas, e o rotacione imediatamente (detalhes: o comprometimento da cadeia de suprimentos do Trivy (março de 2026), em inglês).
No caso Codecov de 2021, um script executado em CI também foi alterado na origem e, por cerca de dois meses, segredos dos ambientes de CI de clientes foram enviados para fora (→ o ataque à cadeia de suprimentos da Codecov).
Os dois mostram que chaves dentro do CI podem ser levadas mesmo quando o seu próprio código está correto. Se uma chave levada estiver cadastrada no root de produção, a produção é entregue nesse momento. Com um usuário dedicado sem root, command= mais restrict e a origem restrita com from=, a mesma chave vazada só consegue fazer o único trabalho que você definiu, e conexões de qualquer outro lugar são recusadas.
O que este site faz por conta própria
Este site usa uma chave dedicada por servidor e nunca reutiliza chaves. Os deploys chegam em um usuário sem root, feito para esse fim, e produção é unidirecional — "ela recebe, não sai para buscar" (→ produção só recebe). Ela não deixa chaves permanentes de computação efêmera para dentro da produção; conecta-se só quando necessário, com menor privilégio. O motivo é exatamente o deste artigo: manter pequeno com antecedência o que cada chave pode fazer, para que um comprometimento não consiga se espalhar para tudo.
Leia a seguir
- Uma nova vulnerabilidade: OpenSSH 10.6p2 corrige um contorno da autenticação por senha no sshd em Linux com musl sem PAM (CVE-2026-123158)
- Fundamentos: o checklist de base de segurança (menor privilégio, proteção das contas de administrador)
- Operações: chaves separadas para minimizar o dano / produção só recebe · o playbook de resposta a vulnerabilidades
- Casos: o comprometimento da cadeia de suprimentos do Trivy (chaves SSH visadas no CI; em inglês) · o ataque à cadeia de suprimentos da Codecov
- Incidente: uma chave roubada via RCE e usada em cobrança fraudulenta · o vazamento de dados da Benesse (privilégio excessivo e abuso interno)
Fontes
- Manual do OpenBSD, "sshd(8)", AUTHORIZED_KEYS FILE FORMAT (command, restrict, from, expiry-time, SSH_ORIGINAL_COMMAND): man.openbsd.org
- Manual do OpenBSD, "sshd_config(5)", PermitRootLogin e AuthorizedKeysFile: man.openbsd.org
- Manual do OpenBSD, "ssh(1)", -A (alerta sobre encaminhamento de agente) e -J: man.openbsd.org
- Manual do OpenBSD, "ssh-keygen(1)", -l, -C e opções de certificado: man.openbsd.org
- Notas de versão do OpenSSH 7.2 (inclusão do restrict): openssh.org
- Notas de versão do OpenSSH 7.7 (inclusão do expiry-time): openssh.org
- NIST, "NISTIR 7966: Security of Interactive and Automated Access Management Using Secure Shell (SSH)" (outubro de 2015): csrc.nist.gov
- Wikibooks, "OpenSSH/Logging and Troubleshooting" (impressões digitais de chave nas linhas de login bem-sucedido): en.wikibooks.org
- Aqua Security, "Trivy Supply Chain Attack: What You Need to Know" (2026): aquasec.com
- Codecov, "Bash Uploader Security Update" (2021): about.codecov.io