14 out 2026 · segurança, linux, ssh · 6 min
Como parar de digitar a senha da chave a cada comando
Com chave protegida por senha, cada ssh novo pede a senha de novo. O ssh-agent guarda a chave ja decifrada em memoria enquanto a sessao dura e o ssh usa essa copia sozinho. O truque do script abaixo e o -t: a chave nao fica no agente para sempre, e sim pelo tempo que voce pediu.
O que acontece sem isso
Testei com uma chave ed25519 nova, protegida por senha, contra um servidor de teste escutando em 127.0.0.1:22222. Com BatchMode=yes, que proibe o cliente de perguntar qualquer coisa, o acesso falha com codigo 255 e o motivo e o mesmo nos dois casos: nao ha chave carregada para o cliente oferecer.
Com o agente no lugar, ssh-add -l passa a listar a identidade e o mesmo comando entra sem perguntar nada.
Repare que o acesso com agente e com -o BatchMode=yes. Se o script roda em um lugar sem senha para digitar, e assim que a automacao descobre que o agente resolve o problema.
O script
Salve como ssh-agente.sh. Ele nao instala nada, nao cria servico e nao mexe em /etc/ssh: cada execucao sobe um agente proprio e ele morre sozinho no fim do prazo.
#!/usr/bin/env bash
# ssh-agente.sh: sobe um ssh-agent com prazo, carrega a chave uma vez so
# e mostra o que conferir depois. Nao instala nada e nao cria servico.
#
# CHAVE=/caminho/minha.chave DURACAO=3600 bash ssh-agente.sh github.com
set -uo pipefail
DURACAO="${DURACAO:-3600}" # segundos que a chave fica carregada
CHAVE="${CHAVE:-$HOME/.ssh/id_ed25519}" # chave que entra no agente
DESTINO="${1:-github.com}" # host usado so para conferir a configuracao
BASE="${XDG_RUNTIME_DIR:-/tmp}" # onde mora o socket do agente
echo "== ssh-agente.sh =="
# 0. o que existe nesta maquina
faltando=""
for prog in ssh-agent ssh-add ssh-keygen ssh; do
command -v "$prog" >/dev/null 2>&1 || faltando="$faltando $prog"
done
if [ -n "$faltando" ]; then
tem_cliente=0
echo "aqui nao tem:$faltando (em Debian e Ubuntu isso e o pacote openssh-client)"
else
tem_cliente=1
echo "cliente ssh encontrado, versao $(ssh -V 2>&1 | cut -d' ' -f1)"
fi
# 1. a chave precisa existir. Sem senha nao ha nada para o agente guardar.
if [ ! -f "$CHAVE" ]; then
echo "chave $CHAVE ainda nao existe"
if [ "$tem_cliente" = 1 ] && [ -t 0 ]; then
mkdir -p "$(dirname "$CHAVE")" 2>/dev/null
ssh-keygen -t ed25519 -a 100 -C "$(id -un)@$(hostname 2>/dev/null || echo exemplo)" -f "$CHAVE"
else
echo "gere na mao: ssh-keygen -t ed25519 -a 100 -f $CHAVE"
fi
fi
# 2. sobe o agente, se ainda nao houver um vivo neste caminho
# SSH_AGENT_DIR deixa o socket num lugar escolhido, para nao disputar
# /run/user/1001 com o desktop e para o script poder rodar em lote.
SOCK_DIR="${SSH_AGENT_DIR:-$BASE}"
SOCK="$SOCK_DIR/ssh-agente-$(id -u).sock"
mkdir -p "$SOCK_DIR" 2>/dev/null
export SSH_AUTH_SOCK="$SOCK"
if [ -S "$SOCK" ] && ssh-add -l >/dev/null 2>&1; then
echo "agente ja responde em $SOCK"
elif [ "$tem_cliente" = 1 ]; then
[ -e "$SOCK" ] && rm -f "$SOCK" # socket deixado por uma sessao que morreu
ssh-agent -a "$SOCK" -t "$DURACAO" >/dev/null
echo "agente novo em $SOCK, expira sozinho em ${DURACAO}s"
fi
# 3. a senha e pedida uma vez, aqui. -t e o prazo da chave no agente.
if [ "$tem_cliente" = 1 ] && [ -f "$CHAVE" ]; then
if ssh-add -t "$DURACAO" "$CHAVE"; then
echo "chave carregada por ${DURACAO}s"
else
echo "a chave nao entrou: senha errada ou agente sem terminal para perguntar"
fi
echo "== ssh-add -l =="
ssh-add -l
fi
# 4. o que o cliente vai dizer para o outro lado
echo "== ssh -G $DESTINO =="
if [ "$tem_cliente" = 1 ]; then
ssh -G "$DESTINO" 2>/dev/null | grep -iE '^(identityagent|forwardagent|addkeystoagent|identityfile) ' \
|| echo "nenhuma linha de identidade: o cliente vai tentar a senha"
else
echo "sem cliente ssh: esta conferencia fica para rodar na sua maquina"
fi
# 5. o bloco de configuracao que faz o agente ser encontrado em todo terminal
echo "== cole em ~/.ssh/config =="
cat <<CFG
Host *
IdentityAgent $SOCK
# forwarding so onde a outra ponta precisa da sua chave.
# com yes no Host * voce entrega o agente a todo host que abre.
Host github.com
ForwardAgent yes
CFG
# 6. como sair
echo "== para sair =="
echo " ssh-add -d $CHAVE tira so esta chave do agente"
echo " ssh-agent -k mata o agente inteiro"
Como rodar, com a chave nao padrao e prazo de uma hora:
CHAVE=~/.ssh/id_ed25519_producao DURACAO=3600 bash ssh-agente.sh github.com
O que aconteceu na prova, na ordem: Lifetime set to 120 seconds e uma identidade em ssh-add -l (256 SHA256:hUVf... prova-agente (ED25519)), depois o acesso entrando sem senha. O servidor registrou 3 autenticacoes por chave bem-sucedidas na prova inteira, todas com a mesma chave. Trocar o prazo depois e uma linha:
ssh-add -t 300 ~/.ssh/id_ed25519 # renova o prazo desta chave
Como verificar
O comando e a saida esperada, com prazo de 120 segundos:
CHAVE=/caminho/chave DURACAO=120 bash ssh-agente.sh github.com
ssh-add -l
Identity added: /caminho/chave (prova-agente)
Lifetime set to 120 seconds
256 SHA256:hUVfzTcYsuKhYcXyhw+PEHp6exXQy8OztVCk+2bl+HA prova-agente (ED25519)
A segunda linha e a que importa: e ela que diz por quanto tempo a chave esta carregada. Se ssh-add -l responder The agent has no identities, o agente subiu mas a chave nao entrou.
Uma checagem mais dura, que nao depende de senha digitada:
ssh -o BatchMode=yes github.com 'echo entrou'
Se imprimir entrou, o agente esta resolvendo. Se reclamar de autenticacao, a chave nao chegou.
Se der errado
Could not open a connection to your authentication agent. O SSH_AUTH_SOCK aponta para um socket que nao existe, muitas vezes de uma sessao antiga que morreu. Rode SSH_AGENT_DIR=/tmp/ag bash ssh-agente.sh para subir o agente em um caminho limpo, ou confira echo $SSH_AUTH_SOCK.
A senha e pedida mesmo com o agente no lugar. O agente guarda a chave depois que ela entra; ele nao tem como adivinhar a senha de uma chave que ainda nao foi carregada. Rode ssh-add /caminho/chave uma vez, antes.
Funciona num terminal e nao em outro. Cada terminal novo precisa da variavel SSH_AUTH_SOCK. E por isso que o script imprime o bloco IdentityAgent para colar em ~/.ssh/config: ali vale para todo terminal, em vez de depender do shell.
Encaminhamento de agente: onde usar e onde nao
ForwardAgent entrega a um servidor remoto o poder de pedir assinatura para as suas chaves. O cliente ssh avisa na documentacao que quem consegue contornar as permissoes do socket no lado remoto usa o agente encaminhado como se fosse seu.
O risco nao e o servidor roubar a chave, e ele conseguir assinar com ela. Por isso o bloco acima liga o forwarding so no host que precisa, e nao em Host *. Uma saida mais segura que eu prefiro hoje e um host intermediario, com o parametro ProxyJump, que nao precisa de agente nenhum:
ssh -J usuario@host-intermediario usuario@servidor-final
Comparacao das tres formas
| forma | o que resolve | o que fica aberto | custo |
|---|---|---|---|
| chave sem senha | nada a digitar | chave em disco, decifrada | um ssh-keygen a menos |
| ssh-agent com prazo | senha uma vez por prazo | chave decifrada em memoria | processo a Terminar |
| ssh-agent sem prazo | senha uma vez ate sair | chave fica no agente para sempre | o agente vaza sozinho |
| forwarding | a outra ponta assina com sua chave | poder de assinatura entregue ao remoto | so host especifico |
FAQ
O agente guarda a senha ou a chave? A chave, decifrada, na memoria do processo. A senha nao fica guardada em lugar nenhum depois do ssh-add. E por isso que o prazo importa: enquanto a chave esta no agente, nao ha nada para digitar.
A chave some quando eu fecho o terminal? O agente e um processo separado do terminal. Se ele foi criado pelo seu shell e o shell morre, o agente normalmente continua, e o prazo do -t e que decide ate quando. Por isso o script imprime como derrubar tudo: ssh-agent -k.
Posso usar a mesma chave em dois lugares ao mesmo tempo? Pode. Cada agente e independente, e cada processo ssh fala com o agente que a variavel SSH_AUTH_SOCK aponta. O que nao pode e o mesmo agente apontando para dois lugares diferentes.
ssh-add -l mostra a chave, mas o ssh ainda pede senha. Isso acontece quando o SSH_AUTH_SOCK do terminal atual aponta para outro agente, ou quando a chave carregada nao e a que o servidor aceita. Confira com ssh -v e veja qual identity file ele tenta.
Fontes
- ssh-agent(1), pagina de manual do OpenBSD, conferida em 14 de outubro de 2026. As opcoes
-a,-te-k. - ssh-add(1), pagina de manual do OpenBSD, conferida em 14 de outubro de 2026. O
-t(prazo por chave) e o-d(remover uma chave). - ssh(1), pagina de manual do OpenBSD, conferida em 14 de outubro de 2026. A secao sobre
-Ae o aviso sobre encaminhar agente.
Quem ainda nao tirou a senha do servidor trocou pela chave leia primeiro trocar a senha do servidor por chave SSH. E quem usa senha curta em outros lugares deve ver o custo de um hash fraco.