81 votes

Partager le même `ssh-agent` entre plusieurs sessions de connexion

Existe-t-il un moyen pratique de s'assurer que toutes les connexions d'un utilisateur donné (c'est-à-dire moi) utilisent le même agent ssh ? J'ai bricolé un script pour que cela fonctionne la plupart du temps, mais je soupçonnais depuis le début qu'il y avait un moyen de le faire que j'avais juste manqué. De plus, depuis cette époque, il y a eu des avancées étonnantes dans la technologie informatique, comme par exemple ce site web.

Donc le but ici est que

  • à chaque fois que je me connecte à la boîte, que ce soit via SSH, ou dans une session graphique lancée depuis gdm/kdm/etc, ou sur une console :
    • si mon nom d'utilisateur n'a pas actuellement un ssh-agent en cours d'exécution, l'un d'entre eux est démarré, les variables d'environnement sont exportées, et ssh-add appelé.
    • sinon, les coordonnées de l'agent existant sont exportées dans les variables d'environnement de la session de connexion.

Cette facilité est particulièrement précieuse lorsque la boîte en question est utilisée comme point de relais lorsque ssh dans une troisième boîte. Dans ce cas, cela évite d'avoir à taper la phrase de passe de la clé privée à chaque fois que vous vous connectez par ssh et que vous voulez, par exemple, faire git push ou quelque chose comme ça.

Le script donné ci-dessous fait cela de manière plutôt fiable, bien qu'il ait récemment bâclé lorsque X a planté et que j'ai ensuite lancé une autre session graphique. Il se peut qu'il y ait eu d'autres problèmes dans ce cas.

Voici mon script mauvais est bon. Je le tire de mon .bashrc .

# ssh-agent-procure.bash
# v0.6.4
# ensures that all shells sourcing this file in profile/rc scripts use the same ssh-agent.
# copyright me, now; licensed under the DWTFYWT license.

mkdir -p "$HOME/etc/ssh";

function ssh-procure-launch-agent {
    eval `ssh-agent -s -a ~/etc/ssh/ssh-agent-socket`;
    ssh-add;
}

if [ ! $SSH_AGENT_PID ]; then
  if [ -e ~/etc/ssh/ssh-agent-socket ] ; then
    SSH_AGENT_PID=`ps -fC ssh-agent |grep 'etc/ssh/ssh-agent-socket' |sed -r 's/^\S+\s+(\S+).*$/\1/'`; 
    if [[ $SSH_AGENT_PID =~ [0-9]+ ]]; then
      # in this case the agent has already been launched and we are just attaching to it. 
      ##++  It should check that this pid is actually active & belongs to an ssh instance
      export SSH_AGENT_PID;
      SSH_AUTH_SOCK=~/etc/ssh/ssh-agent-socket; export SSH_AUTH_SOCK;
    else
      # in this case there is no agent running, so the socket file is left over from a graceless agent termination.
      rm ~/etc/ssh/ssh-agent-socket;
      ssh-procure-launch-agent;
    fi;
  else
    ssh-procure-launch-agent;
  fi;
fi;

S'il vous plaît, dites-moi qu'il y a un meilleur moyen de faire ça. Aussi, s'il vous plaît, ne pinailler pas sur les incohérences/manques (par exemple, mettre le nom de l'auteur dans le texte). var des choses dans etc ) ; j'ai écrit ceci il y a un certain temps et j'ai depuis appris beaucoup de choses.

1voto

Allov Points 674

C'est quelque chose que j'ai ajouté et qui fonctionne pour moi. Il vérifie d'abord si vous avez un agent en cours d'exécution, si oui il va définir les environnements appropriés pour lui, sinon il va le créer. Cela évite également de créer des agents supplémentaires :

Mettez-le dans votre .bashrc

function start_agent() {
    killall ssh-agent  2> /dev/null
    ssh-agent | sed 's/ Agent pid//' > $SSH_ENV
    . $SSH_ENV > $SSH_PID_FILE
    ssh-add ~/.ssh/bb_readonly_rsa 2> /dev/null
}

mkdir -p "$HOME/.ssh/agent"
SSH_ENV="$HOME/.ssh/agent/env"
SSH_PID_FILE="$HOME/.ssh/agent/pid"

if [[ -e $SSH_PID_FILE ]]; then
    SSH_PID=$(< $SSH_PID_FILE) 
    PROCESS=$(ps -p $SSH_PID -o comm=)

    if [[ $PROCESS == 'ssh-agent' ]]; then
        . $SSH_ENV > $SSH_PID_FILE
    else 
        start_agent
    fi  
else
    start_agent
fi

1voto

wisbucky Points 2298

Voici un simple script qui réutilisera toujours le même ssh-agent, ou démarrera ssh-agent s'il n'est pas en cours d'exécution. La clé est d'utiliser le -a pour utiliser le même nom de socket. Sinon, par défaut, il choisira un nom de socket aléatoire à chaque fois. Vous pouvez facilement combiner ces 3 lignes en un alias d'une ligne également.

# set SSH_AUTH_SOCK env var to a fixed value
export SSH_AUTH_SOCK=~/.ssh/ssh-agent.sock

# test whether $SSH_AUTH_SOCK is valid
ssh-add -l 2>/dev/null >/dev/null

# if not valid, then start ssh-agent using $SSH_AUTH_SOCK
[ $? -ge 2 ] && ssh-agent -a "$SSH_AUTH_SOCK" >/dev/null

source

0voto

Oliver Jones Points 101

J'ai aussi une variante de ce problème, tirée directement de mon .bashrc :

# File for storing SSH agent information
OSH=".agent.${HOSTNAME}"

# Test if an agent file exists
if [ -f ${OSH} ];

    # We have one, so let's use it
    then eval `cat ${OSH}` >/dev/null

else

    # No file exists, so we must spawn a new agent
    eval `ssh-agent | tee ${OSH}` >/dev/null

fi

# Try to list agent keys
ssh-add -l &>/dev/null

# Determine the agent status
case $? in

    # Current and SSH keys installed, nothing to do here
    0) ;;

    # Current but no SSH keys installed, so we must add them
    1) ssh-add ;;

    # Stale, so we must redo from scratch with a new agent, then add keys
    *) eval `ssh-agent | tee ${OSH}` >/dev/null && ssh-add ;;

esac

Cette solution stocke une copie des informations de l'agent SSH dans votre répertoire personnel. Si vous avez un répertoire personnel monté sur NFS qui peut être partagé entre plusieurs hôtes, le nom d'hôte est utilisé comme partie du nom de fichier pour les différencier, de sorte que la connexion à partir d'une machine n'altère pas le fichier agent utilisé sur une autre.

Comportement :

1) Les utilisateurs qui se présentent pour la première fois sont invités à saisir une phrase de passe pour la clé.

2) Les deuxième, troisième et quatrième sessions (et cetera) héritent de l'agent SSH et des clés ajoutées lors de la première.

3) Si l'agent est tué ou tombe en panne, la première session suivante créera un nouvel agent, écrasera le fichier de l'agent avec le nouveau et demandera à nouveau une phrase de passe pour la clé. Les sessions créées par la suite se comporteront comme dans le scénario 2), tant que le nouvel agent SSH reste actif.

0voto

ganqqwerty Points 542

J'ai découvert que j'avais souvent plusieurs ssh-agent en cours d'exécution, et que le PID contenu dans le nom de fichier de la socket ne correspondait jamais au PID d'un processus en cours d'exécution. ssh-agent J'ai donc bricolé quelque chose pour essayer de récupérer dans ces conditions, en me basant sur les nombreux exemples ci-dessus.

Il s'agit d'une seule fonction, qui utilise une variable Zsh pour l'ID de l'utilisateur si elle existe, et qui essaie de passer moins de temps à analyser des données éventuellement énormes. /tmp en restreignant find(1) un peu plus.

Elle est probablement encore sujette à des erreurs, et alambiquée, mais quelques tests superficiels indiquent qu'elle fonctionne pour mes cas d'utilisation, alors voilà :

attach\_ssh\_agent () {
  if \[ -n "$SSH\_AGENT\_PID" \]; then
    ssh-add -l >/dev/null
    ret=$?
    if \[ $ret -ge 2 \]; then
      echo "Agent pid $SSH\_AGENT\_PID is less than useful (ret=$ret) - killing..."
      kill $SSH\_AGENT\_PID
      unset $SSH\_AGENT\_PID
    elif \[ $ret = 1 \]; then
      echo "Agent pid $SSH\_AGENT\_PID is less than useful (ret=$ret) - will be seeding it..."
    else
      echo "Agent pid $SSH\_AGENT\_PID"
      return
    fi
  fi
  if \[ -S "$SSH\_AUTH\_SOCK" \]; then
    ssh-add -l > /dev/null
    ret=$?
    if \[ $ret = 2 \]; then
      echo "Socket $SSH\_AUTH\_SOCK is dead - deleting..."
      rm -f $SSH\_AUTH\_SOCK
      unset SSH\_AUTH\_SOCK
    elif \[ $ret = 1 \]; then
      echo "Socket $SSH\_AUTH\_SOCK points to an agent with no keys..."
      ssh-add
    else
      echo "Found ssh-agent $SSH\_AUTH\_SOCK (ret=$ret)"
      return
    fi
  fi
  for sf in $(find /tmp/ -mindepth 2 -maxdepth 2 -uid ${UID:-$(id -u)} -path '/tmp/ssh-\*/agent.\*' -type s); do
    test -r $sf || continue
    export SSH\_AUTH\_SOCK=$sf
    SSH\_AGENT\_PID=$(basename $SSH\_AUTH\_SOCK | cut -d. -f2)
    # races with other process forks, argh
    try=50
    while \[ $try -gt 0 \]; do
      try=$(($try-1))
      export SSH\_AGENT\_PID=$(($SSH\_AGENT\_PID+1))
      echo "Testing $SSH\_AUTH\_SOCK -> $SSH\_AGENT\_PID"
      ssh\_agent\_running=$(ps -u $USER | grep ssh-agent)
      if \[ -z "$ssh\_agent\_running" \]; then
        echo "Socket $SSH\_AUTH\_SOCK does not contain a link to any running agent - deleting..."
        rm -f $SSH\_AUTH\_SOCK
        continue
      fi
      if echo "$ssh\_agent\_running" | \\
           awk '$1 == '$SSH\_AGENT\_PID' {
                  found=1;
                  exit(0);
              }
              END {
                  if (!found) {
                      print "did not find running PID '$SSH\_AGENT\_PID'";
                      exit(1);
                  }
              }'; then
        ssh-add -l > /dev/null
        ret=$?
        if \[ $ret -ge 2 \]; then
          echo "Socket $SSH\_AUTH\_SOCK does not contain a link to a useful agent at $SSH\_AGENT\_PID - deleting..."
          rm -f $SSH\_AUTH\_SOCK
          kill $SSH\_AGENT\_PID
          unset SSH\_AGENT\_PID
          continue 2
        elif \[ $ret = 1 \]; then
          echo "Socket $SSH\_AUTH\_SOCK contains a link to a less than useful agent at $SSH\_AGENT\_PID - seeding..."
          ssh-add
          if ! ssh-add -l > /dev/null; then
            echo "Socket $SSH\_AUTH\_SOCK still contains a link to a less than useful agent at $SSH\_AGENT\_PID - aborting."
            return
          else
            break
          fi
        else
          break
        fi
      else
#        echo "Could not match socket $SSH\_AUTH\_SOCK to agent PID $SSH\_AGENT\_PID - skipping..."
        continue
      fi
    done
    if \[ $try -gt 0 \]; then
      echo "Found ssh-agent $SSH\_AUTH\_SOCK"
      echo "Agent pid $SSH\_AGENT\_PID"
      return
    fi
  done
  if \[ -n "$try" -a -n "$SSH\_AUTH\_SOCK" -a -n "$ssh\_agent\_running" \]; then
    echo "We tried many times, but could not match $SSH\_AUTH\_SOCK to any of the running agents, sigh"
    echo "$ssh\_agent\_running"
    echo "Leaving these leftovers behind and starting a new agent..."
  fi
  eval $(ssh-agent -t 28800)
  ssh-add
}

0voto

boran Points 31

(ceci concerne le poste 2 plus haut, je n'ai pas pu ajouter de commentaire)

@raghavan : Votre exemple est utile, mais je suggérerais de modifier les deux lignes qui ont

pgrep ssh-agent

à

pgrep -u $USER ssh-agent >/dev/null

afin que seuls les agents fonctionnant sous l'utilisateur actuel soient trouvés, et que le pid ne soit pas renvoyé à l'écran (plus propre).

Il serait également souhaitable de changer $HOME/ssh-agent.out en $HOME/.ssh-agent.out

Salutations

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X