Reputation: 4097
I have a sample sh
script on my Linux environment, which basically run's the ssh-agent
for the current shell, adds a key to it and runs two git commands:
#!/bin/bash
eval "$(ssh-agent -s)"
ssh-add /home/duvdevan/.ssh/id_rsa
git -C /var/www/duvdevan/ reset --hard origin/master
git -C /var/www/duvdevan/ pull origin master
Script actually works fine, but every time I run it I get a new process so I think it might become a performance issue and I might end up having useless processes out there.
An example of the output:
Agent pid 12109
Identity added: /home/duvdevan/.ssh/custom_rsa (rsa w/o comment)
Also, along with all this, is it possible to find an existing ssh-agent
process and add my keys into it?
Upvotes: 98
Views: 169283
Reputation: 956
Regarding finding running ssh-agents, previous answers either don't work or rely on a magic file like $HOME/.ssh_agent
. These approaches require us to believe that user never run agents without saving their output to this file.
My approach instead relies on a rarely changed default UNIX domain socket template to find an accessible ssh-agent
among available possibilities.
# (Paste the below code to your ~/.bash_profile and ~/.bashrc files)
C=$SSH_AUTH_SOCK
R=n/a
unset SSH_AUTH_SOCK
for s in $(find $C /tmp/ssh-*/agent.* -user "${USER}" 2>/dev/null | sort -u) ; do
if SSH_AUTH_SOCK=$s ssh-add -l 2>/dev/null >/dev/null ; then R=$? ; else R=$? ; fi
case "$R" in
0|1) export SSH_AUTH_SOCK=$s ; break ;;
esac
done
if ! test -S "$SSH_AUTH_SOCK" ; then
eval $(ssh-agent -s)
unset SSH_AGENT_PID
R=1
fi
echo "Using $SSH_AUTH_SOCK"
if test "$R" = "1" ; then
ssh-add
fi
In this approach, SSH_AGENT_PID
remains unknown, since it is hard to deduce it for non-roots. I assume it is actually not required for users since they don't normally want to stop agents. On my system, setting SSH_AUTH_SOCK
is enough to communicate with agent for e.g. passwordless authentication.
The code should work with any shell-compatible shell.
Upvotes: 3
Reputation: 5228
To check if ssh-agent
is already running in bash?
Here's what works for me:
if ps -p $SSH_AGENT_PID > /dev/null
then
echo "ssh-agent is already running"
# Do something knowing the pid exists, i.e. the process with $PID is running
else
eval `ssh-agent -s`
fi
Upvotes: 80
Reputation: 11710
On Mac, I had the same issue as the OP, and I had multiple identities set up and when I was running git push
(even with no local changes) I saw an error message:
$ git push
ERROR: Write access to repository not granted. fatal: Could not read from remote repository.
Turns out, the issues that I had were twofold:
ssh-add -l
, I could see there was an extraneous identity - i.e. one which didn't exist anymore. That is, I thought I deleted it earlier, but it was still registered on ssh-agent
.ssh-agent
processes (normally there should only be 1-2 running) when I ran pgrep ssh-agent
.The fix it, the solution was rather simple. First, it is helpful to authorize the SSH key on GitHub.
If using Enterprise Cloud, you might need to authorize the SSH key for use with SAML.
Under Settings > SSH and GPG keys on your target GitHub account, find your SSH key and ensure SSO is enabled.
Choose Configure SSO
and Authorize
- see image below.
Next, to be safe I closed most if not all open terminal windows.
Then to kill all those running ssh-agent
processes, I ran:
kill $(pgrep ssh-agent)
Then, I started a new window and when it said:
$ ssh-add -l
The agent has no identities
If SSH_AUTH_SOCK
is unset, you might need to first start up ssh-agent
. Note tthat I didn't need to run this command myself.
test -z "$SSH_AUTH_SOCK" && eval "$(ssh-agent -s)"
I just add them back with ssh-add
:
ssh-add ~/.ssh/id_ed25519_<user>
I can confirm that ssh-add -l
now lists all identities after restarting a new terminal window.
If anyone still runs into issues, there could be a problem with the clone or push URL for a project. For example, using HTTPS instead of SSH.
Note that insteadOf
in git config does not chain. This post (along with its answer) might be helpful.
Upvotes: 1
Reputation: 4097
The answer from AndrewD was the most helpful for me in most cases, but I found out that when $SSH_AGENT_PID
is not set or present, the ps
command will respond with the error:
error: list of process IDs must follow -p
To fix this, we need to check the existence of the $SSH_AGENT_PID
variable so that the condition case will now be:
if [ -n "$SSH_AGENT_PID" ] && ps -p "$SSH_AGENT_PID" > /dev/null
The entire modified snippet:
if [ -n "$SSH_AGENT_PID" ] && ps -p "$SSH_AGENT_PID" > /dev/null
then
echo "ssh-agent is already running"
# Do something knowing the pid exists, i.e. the process with $PID is running
else
eval `ssh-agent -s`
fi
Shorter and revised version:
if ! [ -n "$SSH_AGENT_PID" ] || ! ps -p "$SSH_AGENT_PID" > /dev/null
then
eval "$(ssh-agent -s)"
fi
ssh-add ~/.ssh/github_ed25519
Upvotes: 0
Reputation: 207
Very simple command to check how many processes are running for ssh-agent (or any other program): pidof ssh-agent
or:
pgrep ssh-agent
And very simple command to kill all processes of ssh-agent (or any program):
kill $(pidof ssh-agent)
Upvotes: 2
Reputation: 4757
I've noticed that having a running agent is not enough because sometimes, the SSH_AUTH_SOCK
variable is set or pointing to a socket file that does not exist anymore.
Therefore, to connect to an already running ssh-agent
on your machine, you can do this :
$ pgrep -u $USER -n ssh-agent -a
1906647 ssh-agent -s
$ ssh-add -l
Could not open a connection to your authentication agent.
$ test -z "$SSH_AGENT_PID" && export SSH_AGENT_PID=$(pgrep -u $USER -n ssh-agent)
$ test -z "$SSH_AUTH_SOCK" && export SSH_AUTH_SOCK=$(ls /tmp/ssh-*/agent.$(($SSH_AGENT_PID-1)))
$ ssh-add -l
The agent has no identities.
Upvotes: 1
Reputation: 1541
If you want it to be killed right after the script exits, you can just add this after the eval line:
trap "kill $SSH_AGENT_PID" exit
Or:
trap "ssh-agent -k" exit
$SSH_AGENT_PID
gets set in the eval of ssh-agent -s
.
You should be able to find running ssh-agent
s by scanning through /tmp/ssh-*
and reconstruct the SSH_AGENT
variables from it (SSH_AUTH_SOCK
and SSH_AGENT_PID
).
Upvotes: 10
Reputation: 11966
Also, along with all this, is it possible to find an existing ssh-agent process and add my keys into it?
Yes. We can store the connection info in a file:
# Ensure agent is running
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
# Could not open a connection to your authentication agent.
# Load stored agent connection info.
test -r ~/.ssh-agent && \
eval "$(<~/.ssh-agent)" >/dev/null
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
# Start agent and store agent connection info.
(umask 066; ssh-agent > ~/.ssh-agent)
eval "$(<~/.ssh-agent)" >/dev/null
fi
fi
# Load identities
ssh-add -l &>/dev/null
if [ "$?" == 1 ]; then
# The agent has no identities.
# Time to add one.
ssh-add -t 4h
fi
This code is from pitfalls of ssh agents which describes both the pitfalls of what you're currently doing, of this approach, and how you should use ssh-ident to do this for you.
If you only want to run ssh-agent if it's not running and do nothing otherwise:
if [ $(ps ax | grep [s]sh-agent | wc -l) -gt 0 ] ; then
echo "ssh-agent is already running"
else
eval $(ssh-agent -s)
if [ "$(ssh-add -l)" == "The agent has no identities." ] ; then
ssh-add ~/.ssh/id_rsa
fi
# Don't leave extra agents around: kill it on exit. You may not want this part.
trap "ssh-agent -k" exit
fi
However, this doesn't ensure ssh-agent
will be accessible (just because it's running doesn't mean we have $SSH_AGENT_PID
for ssh-add
to connect to).
Upvotes: 70
Reputation: 338
cat /usr/local/bin/ssh-agent-pro << 'EOF'
#!/usr/bin/env bash
SSH_AUTH_CONST_SOCK="/var/run/ssh-agent.sock"
if [[ x$(wc -w <<< $(pidof ssh-agent)) != x1 ]] || [[ ! -e ${SSH_AUTH_CONST_SOCK} ]]; then
kill -9 $(pidof ssh-agent) 2>/dev/null
rm -rf ${SSH_AUTH_CONST_SOCK}
ssh-agent -s -a ${SSH_AUTH_CONST_SOCK} 1>/dev/null
fi
echo "export SSH_AUTH_SOCK=${SSH_AUTH_CONST_SOCK}"
echo "export SSH_AGENT_PID=$(pidof ssh-agent)"
EOF
echo "eval \$(/usr/local/bin/ssh-agent-pro)" >> /etc/profile
. /etc/profile
then you can ssh-add xxxx
once, you can use ssh-agent everytime when you login.
Upvotes: 1
Reputation: 1
I made this bash function to count and return the number of running ssh-agent processes... it searches ssh-agent process using procfs instead of using $ ps -p $SSH_AGENT_PID
:cmd or $SSH_AUTH_SOCK
:var ... (these ENV-var. can still be set with old values while ssh-agent's process is already killed: if $ ssh-agent -k
or $ $(ssh-agent -k)
instead of $ eval $(ssh-agent -k)
)
function count_agent_procfs(){
declare -a agent_list=( )
for folders in $(ls -d /proc/*[[:digit:]] | grep -v /proc/1$);do
fichier="${folders}/stat"
pid=${folders/\/proc\//}
[[ -f ${fichier} ]] && [[ $(cat ${fichier} | cut -d " " -f2) == "(ssh-agent)" ]] && agent_list+=(${pid})
done
return ${#agent_list[@]}
}
..and then if there is a lot of ssh-agent process running you get their PID with this list..."${agent_list[@]}"
Upvotes: 0
Reputation: 10711
Using $SSH_AGENT_PID
can only test the ssh-agent
but miss identities when it is not yet added
$ eval `ssh-agent`
Agent pid 9906
$ echo $SSH_AGENT_PID
9906
$ ssh-add -l
The agent has no identities.
So it would be save to check it with ssh-add -l
with an expect script like example below:
$ eval `ssh-agent -k`
Agent pid 9906 killed
$ ssh-add -l
Could not open a connection to your authentication agent.
$ ssh-add -l &>/dev/null
$ [[ "$?" == 2 ]] && eval `ssh-agent`
Agent pid 9547
$ ssh-add -l &>/dev/null
$ [[ "$?" == 1 ]] && expect $HOME/.ssh/agent
spawn ssh-add /home/user/.ssh/id_rsa
Enter passphrase for /home/user/.ssh/id_rsa:
Identity added: /home/user/.ssh/id_rsa (/home/user/.ssh/id_rsa)
$ ssh-add -l
4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /home/user/.ssh/id_rsa (RSA)
So when both ssh-agent
and ssh-add -l
are put to run on a bash script:
#!/bin/bash
ssh-add -l &>/dev/null
[[ "$?" == 2 ]] && eval `ssh-agent`
ssh-add -l &>/dev/null
[[ "$?" == 1 ]] && expect $HOME/.ssh/agent
then it would always check and assuring that the connection is running:
$ ssh-add -l
4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /home/user/.ssh/id_rsa (RSA)
You can also emulate the repeating of commands on above script with do while
Upvotes: 8
Reputation: 21
Thanks to all the answers here. I've used this thread a few times over the years to tweak my approach. Wanted to share my current ssh-agent.sh
checker/launcher script that works for me on Linux and OSX.
The following block is my $HOME/.bash.d/ssh-agent.sh
function check_ssh_agent() {
if [ -f $HOME/.ssh-agent ]; then
source $HOME/.ssh-agent > /dev/null
else
# no agent file
return 1
fi
if [[ ${OSTYPE//[0-9.]/} == 'darwin' ]]; then
ps -p $SSH_AGENT_PID > /dev/null
# gotcha: does not verify the PID is actually an ssh-agent
# just that the PID is running
return $?
fi
if [ -d /proc/$SSH_AGENT_PID/ ]; then
# verify PID dir is actually an agent
grep ssh-agent /proc/$SSH_AGENT_PID/cmdline > /dev/null 2> /dev/null;
if [ $? -eq 0 ]; then
# yep - that is an agent
return 0
else
# nope - that is something else reusing the PID
return 1
fi
else
# agent PID dir does not exist - dead agent
return 1
fi
}
function launch_ssh_agent() {
ssh-agent > $HOME/.ssh-agent
source $HOME/.ssh-agent
# load up all the pub keys
for I in $HOME/.ssh/*.pub ; do
echo adding ${I/.pub/}
ssh-add ${I/.pub/}
done
}
check_ssh_agent
if [ $? -eq 1 ];then
launch_ssh_agent
fi
I launch the above from my .bashrc
using:
if [ -d $HOME/.bash.d ]; then
for I in $HOME/.bash.d/*.sh; do
source $I
done
fi
Hope this helps others get up and going quickly.
Created a public gist if you want to hack/improve this with me: https://gist.github.com/dayne/a97a258b487ed4d5e9777b61917f0a72
Upvotes: 2
Reputation: 55
The accepted answer did not work for me under Ubuntu 14.04.
The test to check if the ssh-agent is running I have to use is:
[[ ! -z ${SSH_AGENT_PID+x} ]]
And I am starting the ssh-agent with:
exec ssh-agent bash
Otherwise the SSH_AGENT_PID
is not set.
The following seems to work under both Ubuntu 14.04 and 18.04.
#!/bin/bash
sshkey=id_rsa
# Check ssh-agent
if [[ ! -z ${SSH_AGENT_PID+x} ]]
then
echo "[OK] ssh-agent is already running with pid: "${SSH_AGENT_PID}
else
echo "Starting new ssh-agent..."
`exec ssh-agent bash`
echo "Started agent with pid: "${SSH_AGENT_PID}
fi
# Check ssh-key
if [[ $(ssh-add -L | grep ${sshkey} | wc -l) -gt 0 ]]
then
echo "[OK] SSH key already added to ssh-agent"
else
echo "Need to add SSH key to ssh-agent..."
# This should prompt for your passphrase
ssh-add ~/.ssh/${sshkey}
fi
Upvotes: 2
Reputation: 301
ps -p $SSH_AGENT_PID > /dev/null || eval "$(ssh-agent -s)"
Single line command. Run for the first time will start ssh-agent. Run for the second time will not start the ssh-agent. Simple and Elegant Mate !!!
Upvotes: 12
Reputation: 510
You can modify line #1 to:
PID_SSH_AGENT=`eval ssh-agent -s | grep -Po "(?<=pid\ ).*(?=\;)"`
And then at the end of the script you can do:
kill -9 $PID_SSH_AGENT
Upvotes: -1