>_ josetilabs.com
← blog

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.

Terminal com tres estados do mesmo acesso SSH: sem agente o login por chave falha com codigo 255, com agente ssh-add -l mostra uma identidade e o login entra sem senha, e depois de ssh-add -d volta a falhar com o agente sem identidades
As tres coletas sao o mesmo acesso com a mesma chave, mudando so o agente.

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.

bash
#!/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:

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

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

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

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

bash
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

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.

Leia também

// Por e-mail

Os textos publicados aqui também vão por e-mail. O envio ainda não começou: quem deixar o endereço agora entra na primeira lista.

Guardo só o seu e-mail, a data e o registro desta autorização. Sem cookies, sem rastreador e nada compartilhado com terceiros. Detalhes na política de privacidade.