ssh-agent in bash script causes many dead processes

Viewed 223

I use a bash script (deploy.sh) to deploy my application to a shared host. As part of the deployment process, I clone the latest code from bitbucket using the script below:

eval `ssh-agent -s`
ssh-add ~/.ssh/SHA256-XXX.priv
git clone git@bitbucket.org:username/gng2.git --branch $branchname --single-branch

It seems that this script causes a lot of "dead" processes on the shared host, and when I reach a limit, my app does not work any more as there is no more free process. Please see some examples of dead processes below:

699      65313  0.0  0.0   7112  1752 ?        Ss   Jan04   0:00 ssh-agent -s
699      67925  0.0  0.0   7112  1744 ?        Ss   Feb07   0:00 ssh-agent -s
699      70469  0.0  0.0   7112  1612 ?        Ss   Jan04   0:00 ssh-agent -s
699      71078  0.0  0.0   7112  2352 ?        Ss   Feb10   0:00 ssh-agent -s 

The support team at the hosting company helped to track down that the dead processes are started by my deploy script:

u201-gsoxvughqohx@gfra1.hosting.eu:~$ grep -ril "ssh-agent" .
./www/example.com/gng2-core/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php
./www/example.com/gng2-core/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php
./www/example.com/gng2-core/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php
./www/example.com/repos/gng2/deploy/scripts/deploy.sh
./www/example.com/repos/deploy.sh

This article suggests that my script may "spawns a distinct ssh-agent instance which remains running with the added keys in memory even after logout, unless explicitly killed"

How do I need to change my script so that it does not create so many (dead) processes? Can I simply add the following to the end of my script to solve this problem?

eval `ssh-agent -k`

Or is there a better solution to this problem?

2 Answers

Your script probably shouldn't start ssh-agent; it should make use of an ssh-agent that's already running. That way, the user is responsible for starting a single agent that can be used by multiple invocations of the script.

The simplest thing you can do, though, is simply add either

kill $SSH_AGENT_PID

or

ssh-agent -k

to the end of your script to kill the agent that was just started. One of the things the eval command does is sets the value of SSH_AGENT_PID to the process ID of the just-started agent.

(The former is useful if you have, for whatever reason, multiple concurrent agents, so that you kill the correct agent.)

This on multiple folds has to be dealt with carefully:

First check an ssh-agent is not already available

#!/usr/bin/env bash

# Limit risk of leaving script with an ssh key unlocked
# Keep in mind that SIGKILL cannot be trapped, so it is not 100% abuse-proof
# So remove all pending authorizations
trap 'ssh-add -D 2>/dev/null"' EXIT INT

# Spawn an ssh agent for a limited time only if none already available
if [ -z "$SSH_AUTH_SOCK" ] && [ -z "$SSH_AGENT_PID" ] ! ; then
  # Runs the agent only for the next 5 minutes
  eval "$(ssh-agent -t 600)"
fi

# Now that we know an ssh-agent is available
# we can register our ssh key with an expiration timeout
# so the authentication does not remain exposed for too long
ssh-add -t 600 # expire in 5 minutes

About security precautions when using an ssh-agent:

https://goteleport.com/blog/how-to-use-ssh-agent-safely/

Related