Skip to content

Instantly share code, notes, and snippets.

@dayne
Last active July 4, 2023 11:09
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dayne/a97a258b487ed4d5e9777b61917f0a72 to your computer and use it in GitHub Desktop.
Save dayne/a97a258b487ed4d5e9777b61917f0a72 to your computer and use it in GitHub Desktop.
ssh-agent checker/launcher

ssh-agent checker/launcher

about

A bash script for managing ssh-agent that I use for Ubuntu and OSX.

Started as a variation from this classic on Stack Overflow How to check if ssh-agent is already running and then adapted it to align with behaivor I want.

This version does the following:

  • checks for ssh agent forward (remote login) and if so does not setup ssh-agent or any keys
  • checks if there is an existing agent running and if so uses it
  • otherwise launches a new agent
  • then, if it is an interactive shell, loads keys:
    • priority is to load only $HOME/.ssh/id_rsa-${HOSTNAME} key
    • if that isn't found it loads all public keys: .ssh/*.pub

setup

I put the script into ~/.bash.d/ssh-agent.sh and launch the script from my .bashrc using:

if [ -d $HOME/.bash.d ]; then
  for I in $HOME/.bash.d/*.sh; do
    source $I  
  done
fi

or you can put script as $HOME/.ssh-agent.sh do the one liner in .bashrc

curl -o ssh-agent.sh https://gist.githubusercontent.com/dayne/a97a258b487ed4d5e9777b61917f0a72/raw/ssh-agent.sh
test -f $HOME/.ssh-agent.sh && source ${_}

example setup for a new user

mkdir .bash.d
cd .bash.d
curl -o  ssh-agent.sh https://gist.githubusercontent.com/dayne/a97a258b487ed4d5e9777b61917f0a72/raw/ssh-agent.sh
cd ..
nano .bashrc 

Scroll to bottom of .bashrc (mouse down) and insert (paste) the above example.

# https://gist.github.com/dayne/a97a258b487ed4d5e9777b61917f0a72
# toggle between true and false when debugging this
# debugging between linux flavors, mac, and other systems can be fun
ssh_agent_debug=false
function chat() {
if [ "${ssh_agent_debug}" = true ]; then
echo "info: ${1}"
fi
}
function check_forward_ssh_agent() {
chat "check_forward_ssh_agent()"
if [[ ! -S ${SSH_AUTH_SOCK} ]]; then
chat "no: agent forward detected"
return 1
else
chat "detected agent forward"
ssh-add -L > /dev/null 2>&1
if [ $? -eq 0 ]; then
chat "verified agent auth sock is valid"
return 0
else
chat "ssh auth sock invalid"
return 1
fi
fi
}
function check_ssh_agent() {
chat "check_ssh_agent()"
if [ -f $HOME/.ssh-agent ]; then
source $HOME/.ssh-agent > /dev/null
else
# no agent file
return 1
fi
# thanks to @craighurley for this improvement that works on OSX & Ubuntu fine
lsof -p $SSH_AGENT_PID | grep -q ssh-agent
return $?
}
function launch_ssh_agent() {
chat "launch_ssh_agent()"
ssh-agent > $HOME/.ssh-agent
source $HOME/.ssh-agent
}
function add_keys_to_agent() {
chat "add_keys_to_agent()"
ssh-add -l > /dev/null
if [ $? -eq 0 ]; then
# ssh-agent already has keys loaded - skipping scan & load logic
return 0
fi
# add ~/.ssh/id_rsa-${HOSTNAME} otherwise add all keys in .ssh
echo "adding ssh keys"
test -f $HOME/.ssh/id_rsa-${HOSTNAME}.pub && ssh-add ${_/.pub}
if [ $? -ne 0 ]; then
for I in $HOME/.ssh/*.pub ; do
echo "adding ${I/.pub/}"
ssh-add ${I/.pub/}
done
fi
}
function find_existing_or_launch_new_agent() {
chat "finding existing or launching new ssh agent"
check_forward_ssh_agent
if [ $? -ne 0 ]; then
chat "no forwarded agent found - look locally"
check_ssh_agent
if [ $? -ne 0 ];then
chat "no local or forward agent found"
chat "killing existing agents"
killall ssh-agent # verify there aren't any error state/lost agents running
launch_ssh_agent
fi
# add keys (only if interactive terminal)
if [[ $- = *i* ]];then
# interactive terminal .. but make sure it isn't tmux first
if [ "$TERM" = "screen" ] && [ -n "$TMUX" ]; then
# tmux session - lets avoid key adding magic here
return 0
else
chat "adding keys to agent"
add_keys_to_agent
fi
else
# non-interactive
return 0
fi
fi
}
find_existing_or_launch_new_agent
@craighurley
Copy link

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 $?

could be re-written as the following to actually check that the process is indeed ssh-agent:

lsof -p $SSH_AGENT_PID | grep -q ssh-agent
return $?

@craighurley
Copy link

craighurley commented Dec 31, 2018

check_ssh_agent
if [ $? -eq 1 ];then
  launch_ssh_agent
fi

could be re-written as:

check_ssh_agent
if [ $? -ne 0 ];then
  killall ssh-agent
  launch_ssh_agent
fi

This will catch any error code. Also, if the PID check in my previous comment fails and there is an existing ssh-agent running on a different PID, it will kill that existing ssh-agent, start a new ssh-agent and write the correct ssh-agent details (including PID) to $HOME/.ssh-agent.

@dayne
Copy link
Author

dayne commented Jan 15, 2019

@craighurley thanks. Incorporated those changes.

The lsof -p works on both Ubuntu and Mac OSX and allowed consistent/simpler logic. Awesome.

Also updated this to handle non-interactive shells (including tmux related shells) better that it had been.

@dayne
Copy link
Author

dayne commented Jan 17, 2020

Jan 17th, 2020

Updated to include debug messages to help debugging weird situations. Turns out you can get a SSH_AUTH_SOCK that isn't connected to a valid ssh-agent. Added a test for that scenario along with ability to toggle on debug messages to help debug why a new valid agent isn't being kicked off.

@gauravcanon
Copy link

Is there any way to pass SSH key password in the script ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment