24

I'm trying to create a shell script that, among other things, starts up ssh-agent and adds a private key to the agent. Example:

#!/bin/bash
# ...
ssh-agent $SHELL
ssh-add /path/to/key
# ...

The problem with this is ssh-agent apparently kicks off another instance of $SHELL (in my case, bash) and from the script's perspective it's executed everything and ssh-add and anything below it is never run.

How can I run ssh-agent from my shell script and keep it moving on down the list of commands?

Dan
  • 647
  • 2
  • 8
  • 12

9 Answers9

21

Put the following at the top of your script:

eval `ssh-agent`

Your script should look like this:

#!/bin/bash
eval `ssh-agent`
ssh-add /path/to/key
...
...

Explanation

The backticks around ssh-agent collect its output. eval collects that output, concatenates it into a single command, and then executes the command. Then you can use ssh-add to provide your key credentials.

scottysseus
  • 417
  • 1
  • 5
  • 10
  • 12
    This is exactly what I needed, thanks, although worth pointing out that backticks are on the way out. In the new bash form, it should be `eval $(ssh-agent)` – sibaz Jan 04 '16 at 13:01
  • 2
    This solution didn't work for me until I put `bash -i` at the end of the script. – Adolfo Correa Sep 09 '18 at 23:52
13

ssh-agent is supposed to start a session and when it finishes the user session is over. So any command after ssh-agent would perhaps be executed after logoff.

What you want is a session-script that contains your sessions commands like this:

#!/bin/bash
ssh-add /path/to/key
bash -i # or other session starter

Then start ssh-agent session-script.

6

I tend to do something like this in scripts that require an agent.

#!/bin/bash

# if we can't find an agent, start one, and restart the script.
if [ -z "$SSH_AUTH_SOCK" ] ; then
  exec ssh-agent bash -c "ssh-add ; $0"
  exit
fi

... and so on.

Basically the first thing the script does it check to see if an agent is running. If it isn't exec is used to start a new process in place of the script. The agent is started, keys are added, and finally, the script is called again (see the $0).

Zoredache
  • 128,755
  • 40
  • 271
  • 413
  • But that will not preserve any script parameters. And if any of the parameters has whitespace, it won't be easy to pass them along. – Denilson Sá Maia Aug 07 '14 at 14:24
  • 3
    You could use `.. "ssh-add ; $0 $*"`, or `.. "ssh-add ; $0 $@"` instead, which may work. Which wouldn't be perfect, but would certainly work in many cases. The best solution is almost always to have your agent running before anything else anyway, this is just something that might be useful in obscure cases. – Zoredache Aug 07 '14 at 16:40
6

I found this works for me.

eval `ssh-agent` # create the process
ssh-add ~/.ssh/priv_key # add the key
git -C $repo_dir pull # this line is the reason for the ssh-agent
eval `ssh-agent -k` # kill the process

I create the ssh-agent process, add the key, do what I need to do, then kill it. No need to check if it's running later.

steampowered
  • 593
  • 2
  • 10
  • 24
5

It is better to use keychain in this case

Debian/Ubuntu:

apt-get install keychain

RHEL/Fedora/CentOS

yum install keychain

Add in your .bashrc the following:

eval `keychain --eval id_rsa`
  • 1
    Better? Why is it better? – JFlo Oct 03 '17 at 18:24
  • 1
    @JFlo "Better" in that, it will save the env variables to $HOME/.keychain/. Running that command again will pickup an existing ssh-agent if it is still running. It can then be reused between shells/scripts. In some scenarios that isn't super safe, so you have to make that call. For me, it is an improvement over some scripts I'd written to accomplish the same task – Scott Carlson Aug 06 '18 at 13:06
  • This solution works perfectly, and I consider it very secure. You could run the eval command from a script, you can add 'zsh -i' after. That way you enable the keyring, and you can disable it typing 'exit'. Example: https://pastebin.com/6bdsLKZR – Adrian Lopez Oct 31 '21 at 22:51
3

I found with Zoredache's solution, the key would be available to any shell that happens to share the same ssh-agent as the shell that called the script. I wanted to avoid this in a script that required root access to a remote machine, for obvious security reasons.

I've found putting the following shebang at the top of the script works:

#!/usr/bin/ssh-agent bash

ssh-add /path/to/ssh-key
ssh root@remotehost "remote commands"
Andy Wood
  • 31
  • 4
1

Even better, you might want to share your ssh-agent socket with all processes so that if one process adds some keys, they are accessible to you and all other processes later. This is a bit of a security risk as well, but is a tradeoff between convenience and security and is better than removing your ssh password entirely. In case this is what you want, this works perfectly. It is based on this answer here, but has my modifications.

In your server's ~/.bashrc or ~/.bash_aliases file, add this:

# Auto-start the ssh agent and add necessary keys once per reboot. 
#
# This is recommended to be added to your ~/.bash_aliases (preferred) or ~/.bashrc file on any
# remote ssh server development machine that you generally ssh into, and from which you must ssh
# into other machines or servers, such as to push code to GitHub over ssh. If you only graphically
# log into this machine, however, there is no need to do this, as Ubuntu's Gnome window manager,
# for instance, will automatically start and manage the `ssh-agent` for you instead.
#
# See: 
# https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/tree/master/home/.ssh#auto-starting-the-the-ssh-agent-on-a-remote-ssh-based-development-machine

if [ ! -S ~/.ssh/ssh_auth_sock ]; then
    echo "'ssh-agent' has not been started since the last reboot. Starting 'ssh-agent' now."
    eval "$(ssh-agent -s)"
    ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
# see if any key files are already added to the ssh-agent, and if not, add them
ssh-add -l > /dev/null
if [ "$?" -ne "0" ]; then
    echo "No ssh keys have been added to your 'ssh-agent' since the last reboot. Adding default keys now."
    ssh-add
fi

This will automatically start your ssh-agent and add default keys once per reboot whenever you ssh into your remote server.

Then, to give any other script access to this agent, so that the script can use the keys, for instance, to push or pull to or from a GitHub code repo, add this to your script:

export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock

That simply tells your script to use the already-open ssh socket which you opened when you manually ssh-ed in.

In case the script runs before you ever manually ssh in, though, you can add the entire large code block above to the script instead, so that it will prompt you to start the ssh-agent right there and let you type in your ssh keys right then. In this case, you'd end up with that large code block above both in your ~/.bashrc or ~/.bash_aliases file, and in your script which needs to use the ssh-agent and add more keys to it.

References:

  1. this fantastic answer: https://unix.stackexchange.com/questions/90853/how-can-i-run-ssh-add-automatically-without-a-password-prompt/217223#217223
  2. my own ssh documentation: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/tree/master/home/.ssh
0

You can do all of the following inline:

  • start an agent
  • add the necessary key
  • execute arbitrary code
  • implicitly cleanup session when process exits

start an agent

$ <<eof ssh-agent sh 
echo \$SSH_AGENT_PID
ssh-add /tmp/key
ssh-add -l
echo arbitrary code
eof
98114
Identity added: /tmp/key (control@fubar)
4096 SHA256:MSKhXkIcFHnMIaY7+eOdIH5V23LXt+azcVtu4T01o5M control@fubar (RSA)
arbitrary code

agent go(ne) bye bye

$ ps -p 98114
  PID TTY           TIME CMD

I'll hold my breath while I wait for the gesta.. er, moderators to come edit something

christianlc
  • 121
  • 3
-2

I've tried and lot and the solution that finally worked was replacing my passphrase with an empty string.

ssh-keygen -p
Stephan Weinhold
  • 177
  • 1
  • 1
  • 6
  • 1
    This is a very unsafe practice. Why bother using ssh at all? If you don't protect your private key, you might as well be talking in clear text. – JFlo Aug 07 '18 at 14:47
  • 1
    @JFlo: not if your client system is sufficiently secure, which it might be. Especially if you (can and do) add ACL, SELinux, or similar, which is easy with a static file but less so with ssh-agent's randomized socket. That said I wouldn't usually recommend it as first choice. – dave_thompson_085 Mar 05 '19 at 09:49
  • While that is a very helpful process you provide, I don't think it answers anything about the OP's question. – Alexander Bird Apr 10 '19 at 20:36