特定のユーザー(つまり私)からのすべてのログインが同じssh-agentを使用することを保証する便利な方法はありますか?ほとんどの場合、これを機能させるためにスクリプトをハッキングしましたが、私が見逃していた方法がいくつかあるのではないかとずっと思っていました。さらに、その時以来、例えばこのウェブサイトのように、コンピューティング技術の驚くべき進歩がありました。
ここでの目標は
ssh-agent
が実行されていない場合は、1つが開始され、環境変数がエクスポートされ、ssh-add
が呼び出されます。この機能は、問題のボックスが3番目のボックスにssh
ingするときにリレーポイントとして使用される場合に特に役立ちます。この場合、sshを実行するたびに秘密鍵のパスフレーズを入力する必要がなく、たとえばgit Push
などを実行する必要がなくなります。
以下のスクリプトはこれをほぼ確実に実行しますが、最近Xがクラッシュし、別のグラフィカルセッションを開始したときに失敗しました。その場合、他の厄介なことが起こった可能性があります。
これが私の悪いスクリプトです。私はこれを.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;
これを行うより良い方法があると教えてください。また、不整合や誤りをつまずかないでください(たとえば、var
のものをetc
に入れます)。私はこれを少し前に書いて、それ以来多くのことを学びました。
私は自分のバリエーションをミックスに投入することもできます:
function sshagent_findsockets {
find /tmp -uid $(id -u) -type s -name agent.\* 2>/dev/null
}
function sshagent_testsocket {
if [ ! -x "$(which ssh-add)" ] ; then
echo "ssh-add is not available; agent testing aborted"
return 1
fi
if [ X"$1" != X ] ; then
export SSH_AUTH_SOCK=$1
fi
if [ X"$SSH_AUTH_SOCK" = X ] ; then
return 2
fi
if [ -S $SSH_AUTH_SOCK ] ; then
ssh-add -l > /dev/null
if [ $? = 2 ] ; then
echo "Socket $SSH_AUTH_SOCK is dead! Deleting!"
rm -f $SSH_AUTH_SOCK
return 4
else
echo "Found ssh-agent $SSH_AUTH_SOCK"
return 0
fi
else
echo "$SSH_AUTH_SOCK is not a socket!"
return 3
fi
}
function sshagent_init {
# ssh agent sockets can be attached to a ssh daemon process or an
# ssh-agent process.
AGENTFOUND=0
# Attempt to find and use the ssh-agent in the current environment
if sshagent_testsocket ; then AGENTFOUND=1 ; fi
# If there is no agent in the environment, search /tmp for
# possible agents to reuse before starting a fresh ssh-agent
# process.
if [ $AGENTFOUND = 0 ] ; then
for agentsocket in $(sshagent_findsockets) ; do
if [ $AGENTFOUND != 0 ] ; then break ; fi
if sshagent_testsocket $agentsocket ; then AGENTFOUND=1 ; fi
done
fi
# If at this point we still haven't located an agent, it's time to
# start a new one
if [ $AGENTFOUND = 0 ] ; then
eval `ssh-agent`
fi
# Clean up
unset AGENTFOUND
unset agentsocket
# Finally, show what keys are currently in the agent
ssh-add -l
}
alias sagent="sshagent_init"
そして、ログインするたびに、wantエージェントが接続されている場合(常にではない)、sagent
と入力します。
ssh -A [user@]remotehost
これはあなたが探しているものかもしれません。 sshを実行するときに-Aスイッチを使用して、ssh-agentを転送します。ここにユースケースがあります:
私は、githubを指しているリモートでいくつかのgitリポジトリを持つリモートサーバーを持っています。スクリーンセッションでssh-agentを実行していない場合、「git pull Origin master」を実行するには、キーのパスフレーズを入力する必要があります。ブー!さらに、リモートサーバーにprivateキーをインストールする必要があります-さらにBoooo!
代わりに、単にssh -A [user@]remotehost
ローカルで実行しているssh-agentを渡します。これで、リモートホスト上に存在するための秘密鍵は不要になりました。 ssh-agentでスクリプトを実行する必要はまったくないと思います。
Cygwinでも機能するかなり素晴らしいものを次に示します。
SSH_ENV=$HOME/.ssh/environment
function start_agent {
echo "Initialising new SSH agent..."
/usr/bin/ssh-agent | sed 's/^echo/#echo/' > ${SSH_ENV}
echo succeeded
chmod 600 ${SSH_ENV}
. ${SSH_ENV} > /dev/null
/usr/bin/ssh-add;
}
# Source SSH settings, if applicable
if [ -f "${SSH_ENV}" ]; then
. ${SSH_ENV} > /dev/null
#ps ${SSH_AGENT_PID} doesn't work under cywgin
ps -efp ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
start_agent;
}
else
start_agent;
fi
.bash_profileまたは.bashrcに追加します
そのために作られたキーチェーンを使ってみてください。 http://www.gentoo.org/doc/en/keychain-guide.xml
私は最近使い始めました:
https://github.com/ccontavalli/ssh-ident
私がしなければならないすべては追加です:
alias ssh=/path/to/ssh-ident
私の.bashrcファイル。スクリプトは次の処理を行います。
私は物事をできるだけシンプルに保つことを好みます:(~/.profile
)からのスニペット
check-ssh-agent() {
[ -S "$SSH_AUTH_SOCK" ] && { ssh-add -l >& /dev/null || [ $? -ne 2 ]; }
}
# attempt to connect to a running agent
check-ssh-agent || export SSH_AUTH_SOCK="$(< ~/.tmp/ssh-agent.env)"
# if agent.env data is invalid, start a new one
check-ssh-agent || {
eval "$(ssh-agent -s)" > /dev/null
echo "$SSH_AUTH_SOCK" > ~/.tmp/ssh-agent.env
}
以前は-a
の使用を考えていませんでしたが、もっと簡単かもしれません:
check-ssh-agent || export SSH_AUTH_SOCK=~/.tmp/ssh-agent.sock
check-ssh-agent || eval "$(ssh-agent -s -a ~/.tmp/ssh-agent.sock)" > /dev/null
私の場合、PowerShellで posh-git を設定しており、cygwinで同じssh-agentを使用する必要がありました。異なるtmpフォルダーを使用しているため、パスを操作する必要があり、作成された.envファイルはBOMとCR\LFを使用したUTF16でした。 cygwinが使用する.bashrcに以下を追加すると機能するはずです。
# Connect to ssh-agent started by posh-git
SSH_AGENT_ENV=$(cygpath "$LOCALAPPDATA\Temp")
if [ -z $SSH_AUTH_SOCK ] && [ -z $SSH_TTY ]; then # if no agent & not in ssh
if [ -f "$SSH_AGENT_ENV/.ssh/SSH_AUTH_SOCK.env" ]; then
AUTH_SOCK=$(iconv -c -f UTF-16LE -t US-ASCII "$SSH_AGENT_ENV/.ssh/SSH_AUTH_SOCK.env" | tr -d '\r\n')
export SSH_AUTH_SOCK="${AUTH_SOCK/\/tmp/$SSH_AGENT_ENV}"
ssh-add -l > /dev/null
if [ $? = 2 ] ; then
echo "Failed to setup posh-git ssh-agent using $AUTH_SOCK"
unset SSH_AUTH_SOCK
else
echo "Found posh-git ssh-agent $AUTH_SOCK"
fi
else #Start new agent if you want (not shared by posh-git)
echo "failed to setup posh-git ssh-agent"
#eval `ssh-agent -s` > /dev/null
fi
fi
これは私が追加したもので、私にとってはうまくいきます。まず、エージェントが実行されているかどうかを確認し、実行されている場合は適切な環境を設定し、そうでない場合は作成します。また、追加のエージェントの作成を排除します。
ちょうどあなたの.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
もう一度、すぐに.bash_profileに入れ、ログオン時にデフォルトのキーを追加するように求める例。私の場合、転送はオプションではありませんでした。
do-ssh-agent() {
# function to start the ssh-agent and store the agent details for later logon
ssh-agent -s > ~/.ssh-agent.conf 2> /dev/null
. ~/.ssh-agent.conf > /dev/null
}
# set time a key should be kept in seconds
keyage=3600
if [ -f ~/.ssh-agent.conf ] ; then
. ~/.ssh-agent.conf > /dev/null
ssh-add -l > /dev/null 2>&1
# $?=0 means the socket is there and it has a key
# $?=1 means the socket is there but contains no key
# $?=2 means the socket is not there or broken
stat=$?
if [ $stat -eq 1 ] ; then
ssh-add -t $keyage > /dev/null 2>&1
Elif [ $stat -eq 2 ] ; then
rm -f $SSH_AUTH_SOCK
do-ssh-agent
ssh-add -t $keyage > /dev/null 2>&1
fi
else
do-ssh-agent
ssh-add -t $keyage > /dev/null 2>&1
fi
〜/ ssh-agent.shファイルを作成します。
agent_out_file="$HOME/ssh-agent.out"
function initialize {
pgrep ssh-agent && kill $(pgrep ssh-agent)
ssh-agent -s > $agent_out_file
. $agent_out_file
}
pgrep ssh-agent
if [ $? -eq 0 ]; then # ssh agent running
ssh-add -l > /dev/null 2>&1
status=$?
if [ $status -eq 0 ]; then # can connect to ssh agent and keys available
echo nothing to do
Elif [ $status -eq 1 ]; then # can connect to ssh agent and no keys available
echo nothing to do
Elif [ $status -eq 2 ]; then # cannot connect to ssh agent
. $agent_out_file
fi
else # ssh agent not running
initialize
fi
.bashrcにファイルを含める
. ~/ssh-agent.sh
これは https://superuser.com/a/141233/5255 (このスレッド内)から変更された私のソリューションです:
# attempt to connect to a running agent - cache SSH_AUTH_SOCK in ~/.ssh/
sagent()
{
[ -S "$SSH_AUTH_SOCK" ] || export SSH_AUTH_SOCK="$(< ~/.ssh/ssh-agent.env)"
# if cached agent socket is invalid, start a new one
[ -S "$SSH_AUTH_SOCK" ] || {
eval "$(ssh-agent)"
ssh-add -t 25920000 -K ~/.ssh/id_rsa
echo "$SSH_AUTH_SOCK" > ~/.ssh/ssh-agent.env
}
}
以下は、常に同じssh-agentを再利用する、または実行されていない場合はssh-agentを起動する単純なスクリプトです。重要なのは、-a
同じソケット名を使用するオプション。それ以外の場合、デフォルトでは毎回ランダムなソケット名が選択されます。これらの3行を1行のエイリアスに簡単に結合することもできます。
# 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 '以下 script 私の 。bash_profile から:
MYAGENTS=(`pgrep -U $USER -f ^ssh-agent$|sort -n`)
echo "Found ${#MYAGENTS[@]} ssh-agents."
# Let's try to take over the agents, like we do everynight Pinky!
if [[ "${MYAGENTS[@]}" ]];then
KEEPER=${MYAGENTS[0]}
echo KEEPER: $KEEPER
OUTCAST=${MYAGENTS[@]:1}
[[ "$OUTCAST" ]] && { echo "Goodbye agent $OUTCAST"; kill $OUTCAST; }
SSH_AUTH_SOCK=`awk '/tmp\/ssh/ {print $NF}' /proc/$KEEPER/net/unix`
export SSH_AUTH_SOCK;
SSH_AGENT_PID=$KEEPER; export SSH_AGENT_PID;
else
NEWAGENT="`ssh-agent`"
echo $NEWAGENT;
eval $NEWAGENT
fi
ssh-add -l | grep "The agent has no identities" && ssh-add
多くの回答はほとんど有効ですが、私は私の短くて簡単な方法を共有します。それをあなたの〜/ .bashrc od〜/ .zshrcに追加してください。これはいくつかの上位の応答に似ています。
# export socket variable
export SSH_AUTH_SOCK=~/.tmp/ssh-agent.sock
[ ! -d ~/.tmp ] && mkdir ~/.tmp # create dir if not exist ~/.tmp
# check is ssh-agent running and socket is valid
check-ssh-agent() {
[ -S "$SSH_AUTH_SOCK" ] && { ssh-add -l >& /dev/null || [ $? -ne 2 ]; }
}
# if socket or agent is not valid/running create ssh-agent with socket from env variable
check-ssh-agent || eval "$(ssh-agent -s -a ${SSH_AUTH_SOCK})"
次の行で〜/ .ssh/configからすべてのキーを追加できます。
cat ~/.ssh/config | grep IdentityFile | awk '{print $NF}' | sort | uniq | xargs ssh-add
〜/ .bashrcまたは〜/ .zshrcのssh-agentコードの後に、またはエイリアスとして追加できます。
alias ssh-add-keys="cat ~/.ssh/config | grep IdentityFile | awk '{print $NF}' | sort | uniq | xargs ssh-add"
私も.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
このソリューションは、SSHエージェント情報のコピーをホームディレクトリに保存します。複数のホスト間で共有される可能性のあるNFS自動マウントホームディレクトリがある場合、ホスト名はファイル名の一部として使用され、それらを区別するため、あるマシンからログインしても、別のマシンで使用中のエージェントファイルが破壊されることはありません。
動作:
1)初めてのユーザーセッションでは、キーパスフレーズの入力を求められます。
2)2番目、3番目、4番目(et cetera)のセッションは、最初に追加されたSSHエージェントとキーを継承します。
3)エージェントが強制終了またはクラッシュした場合、後続の最初のセッションで新しいエージェントが作成され、エージェントファイルが新しいエージェントファイルで上書きされ、キーパスフレーズの入力を再度求められます。その後作成されたセッションは、新しいSSHエージェントが実行されている限り、シナリオ2)のように動作します。
(これは2より高い投稿を指し、コメントを追加できませんでした)
@raghavan:あなたの例は有用ですが、次の2行を変更することをお勧めします
pgrep ssh-agent
に
pgrep -u $ USER ssh-agent>/dev/null
現在のユーザーの下で実行されているエージェントのみが見つかり、pidが画面に表示されないようにします(よりクリーン)。
$ HOME/ssh-agent.outを$ HOME/.ssh-agent.outに変更することもできます
よろしく
複数の_ssh-agent
_プロセスが実行されていることが多く、ソケットファイル名内のPIDが実行中の_ssh-agent
_のPIDと実際には一致しないことがわかったため、これらの条件から回復するために何かをハッキングしました。上記の多数の例に基づいています。
これは単一の関数であり、ユーザーIDがある場合はZsh変数を使用し、find(1)
をもう少し制限することで、巨大な_/tmp
_ディレクトリの解析に費やす時間を短縮しようとします。
おそらくまだエラーが発生しやすく、複雑ですが、大まかなテストでは、ほとんどの場合私のユースケースで機能することが示されています。
attach_ssh_agent(){ if [-n "$ SSH_AGENT_PID"];次に ssh-add -l>/dev/null ret = $? if [$ ret -ge 2]; then echo "エージェントpid $ SSH_AGENT_PIDは有用ではありません(ret = $ ret)-killing ..." kill $ SSH_AGENT_PID unset $ SSH_AGENT_PID Elif [$ ret = 1]; then echo "エージェントpid $ SSH_AGENT_PIDは有用ではありません(ret = $ ret)-シードされます..." else echo "エージェントpid $ SSH_AGENT_PID" return fi fi if [-S "$ SSH_AUTH_SOCK"]; then ssh-add -l> /dev/null ret = $? if [$ ret = 2];次に、 echo "ソケット$ SSH_AUTH_SOCKが停止しています-削除しています..." rm -f $ SSH_AUTH_SOCK unset SSH_AUTH_SOCK Elif [$ ret = 1]; then echo "ソケット$ SSH_AUTH_SOCKはキーのないエージェントを指しています..." ssh-add else echo "ssh-agent $ SSH_AUTH_SOCKが見つかりました( ret = $ ret) " return fi fi $(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) #他のプロセスフォークと競合し、argh 試行= 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"];次に、 echo "ソケット$ SSH_AUTH_SOCKには実行中のエージェントへのリンクが含まれていません-削除しています..." 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); } } ' ;次に ssh-add -l> /dev/null ret = $? if [$ ret -ge 2];次に、 echo "ソケット$ SSH_AUTH_SOCKに、$ SSH_AGENT_PIDにある有用なエージェントへのリンクが含まれていません-削除しています..." rm -f $ SSH_AUTH_SOCK kill $ SSH_AGENT_PID unset SSH_AGENT_PID continue 2 Elif [$ ret = 1];次に、 echo "ソケット$ SSH_AUTH_SOCKには、$ SSH_AGENT_PIDの有用性の低いエージェントへのリンク-シード中..." ssh-add if! ssh-add -l>/dev/null;次に、 echo "ソケット$ SSH_AUTH_SOCKには、$ SSH_AGENT_PIDにある有用性の低いエージェントへのリンクが引き続き含まれています-中止します。" return else break fi else break fi else #echo "ソケット$ SSH_AUTH_SOCKをエージェントPID $ SSH_AGENT_PIDに一致できません-スキップしています... " 続行 fi 完了 if [$ try -gt 0];次に 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"];次に、 echo "何度も試行しましたが、$ SSH_AUTH_SOCKを実行中のエージェントのいずれにも一致させることができませんでした" echo "$ ssh_agent_running" echo "これらの残り物を残して、新しいエージェントを開始しています... " fi eval $(ssh-agent -t 28800) ssh-add }
私はあなたの元の解決策といくつかの提案された解決策を読みましたが、私自身の使用のためにプロセスを簡略化することにしました。これは私が自分の.bashrcに追加したものです:
# get active ssh-agent, or launch new
SSH_AGENT_PID=$(ps -fC ssh-agent | grep "ssh-agent -a ${HOME}/.ssh/ssh-agent-socket" | awk '{print $2}')
if [ -z "${SSH_AGENT_PID}" ]; then
# If there is no ssh-agent running, we'll make sure one hasn't left a socket file dangling
rm ${HOME}/.ssh/ssh-agent-socket &> /dev/null
# And of course start one
eval $(ssh-agent -a ${HOME}/.ssh/ssh-agent-socket)
else
# We found a process matching our requirements, so sticking with that
export SSH_AGENT_PID
export SSH_AUTH_SOCK="${HOME}/.ssh/ssh-agent-socket"
fi
ここでは、いくつかの仮定を行いました。
全体として、私はそれが単純な解決策のように感じていると思います。