<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/xhtml.xsl"?>
<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Using ssh-agent with ssh</title>
<meta name="title" content="Using ssh-agent with ssh" />
<meta name="author" content="mah@everybody.org" />
<style type="text/css">
@import "/mah.css";
</style>
<meta name="Description" content="
How to use ssh-agent to get secure, encrypted passwordless logins.
" />
</head>
<body>
<div id="header">
<p><a href="/">top</a>::<a href="/docs/">docs</a>
</p>
<h1>Using ssh-agent with ssh</h1>
by <a href="http://mah.everybody.org/">Mark A. Hershberger</a> (<a href="http://mah.everybody.org/weblog/">weblog</a>)
</div>
<div id="main">
<div id="googlead">
<script type="text/javascript"><!--
google_ad_client = "pub-3932658445533817";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "E0FFE3";
google_color_bg = "E0FFE3";
google_color_link = "0000CC";
google_color_url = "008000";
google_color_text = "000000";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

  <p>
    I went searching for a good, general page that would explain how to do
    <a
      href="http://www.google.com/search?q=passwordless+logins+ssh-agent">passwordless
      logins using ssh-agent</a> and didn't find much at the time
    (now there is much more out there).  So I wrote this
    page.</p>

  <h2>Goals</h2>
  <p>
    Get a secure, encrypted connection to a remote machine without typing
    in a password.
  </p>

  <h2>Executive Summary</h2>
  <ol>
    <li><a href="#gen-keys">Create a key pair on the local machine.</a></li>
    <li><a href="#upload-public-key">Put the public key on any remote machines.</a></li>
    <li><a href="#run-ssh-agent">Run <tt>ssh-agent</tt> to cache login credentials for the
    session.</a>  <tt>ssh-agent</tt> requires the user to "unlock" the
    private key first.</li>
  </ol>

  <h2>Related Pages</h2>
  <ol>
    <li><a href="ssh-agent-startup">Alternate agent startup scripts</a> --
    Working with KDE, Cygwin, or csh-derived shell?  Some scripts to help</li>
    <li><a href="ssh-troubleshooting">Troubleshooting</a> -- Can't
    connect?  Here's some ideas to help you troubleshoot the problem.</li>
    <li><a href="ssh-automatic">Automatic ssh</a> -- Daemons, long-lived
      processes and ssh.</li>
  </ol>

  <h2>Methods</h2>
  <p>
    Use <a href="http://www.openssh.com">OpenSSH</a> to handle the
    authentication.
  </p>

  <p>For Windows users, the methods I describe here will work
      with the OpenSSH that is part of the 
      <a href="http://www.cygwin.org/">CygWin</a> toolset.</p>

  <p>Anyway, here is how to set up a pair of keys for passwordless
    authentication via ssh-agent.</p>

  <ol>
    <li><a name="gen-keys" />Generate the keys.  Do this on the host that you want to connect
      from.
      
      <p>
      <i><b>Note:</b> Older versions of OpenSSH (1.2.xx) and,
	perhaps, commercial SSH may require that you have to use
	RSA keys.  In this case substitute "RSA" for "DSA" after
	"-t" and "identity" for "id_dsa".  Continue to substitute
	"RSA" where you see "DSA" throughout.  Everything else should
	be the same.</i></p>

      <p><i><b>Also Note:</b> On Windows machines, the command
      prompt doesn't understand the ~ which on Unix machines
      means "the home directory".  Instead use <tt>%HOME%</tt>
      wherever you see the tilde.</i></p>

      <blockquote><pre>
      $ ssh-keygen -t dsa -f ~/.ssh/id_dsa -C "you@example.com"
      Generating DSA keys:  Key generation complete.
      Enter passphrase (empty for no passphrase): USE-A-PASSPHRASE
      Enter same passphrase again: USE-A-PASSPHRASE
      Your identification has been saved in ~/.ssh/id_dsa
      Your public key is:
      1024 35 <i>[really long string]</i> you@example.com
      Your public key has been saved in ~/.ssh/id_dsa.pub
      $
    </pre></blockquote>
    </li>

    <li>To use the key on other hosts you will be connecting
      <i>from</i>, copy the <tt>~/.ssh/id_dsa</tt> key to the other
      hosts:<blockquote>
	<pre>
	  $ scp ~/.ssh/id_dsa you@another-box:.ssh/
	</pre>
      </blockquote>
      However, it is probably better just to generate new keys for
      those hosts.
      </li>

    <li><a name="upload-public-key" />Make sure the public key is in the <tt>~/.ssh/authorized_keys</tt>
      file on the hosts you wish to connect to.  You can use a
      password authenticated connection to do this:
      <blockquote><pre>
	  $ cat ~/.ssh/id_dsa.pub | ssh you@other-host 'cat - &gt;&gt; ~/.ssh/authorized_keys'
	  you@other-host's password: 
	  $
	</pre></blockquote>

      <p><b>Note:</b> If an older version of ssh is running on
	  the remote host, you may have to use the
	  <tt>~/.ssh/authorized_keys2</tt> file.</p>
      <p>
	<b>Note</b>: If your local machine is Windows, try</p>
      <blockquote>
	<pre>
	  C:\&gt; type %HOME%/.ssh/id_dsa.pub | ssh you@other-host "cat - &gt;&gt; ~/.ssh/authorized_keys"
	  you@other-host's password: 
	  C:\&gt;
	</pre>
      </blockquote>
      <p><b>Also note</b>: If the remote server is Windows, you
      will probably want to use <tt>type</tt> instead of
      <tt>cat</tt> for the second half of your command.</p>
    </li>
    <li>Verify that DSA authentication works:

      <blockquote><pre>
      $ ssh you@example.com
      Enter passphrase for DSA key 'you@example.com': ^D
      $
      </pre></blockquote>
      
      If you don't get the prompt for your DSA key, then
      something has gone wrong.  (One thing to check: verify that
      <tt>sshd_config</tt> on the server has been configured to
      do DSA authentication.  Look for <tt>DSAAuthentication
      yes</tt> or get your system administrator to add it if
      necessary.)
    </li></ol>

  <p><a name="run-ssh-agent"/>Now that that works, you will want the passwordless part, right?</p>

  <ol><li>Start up ssh-agent.  You can have it create a
      subprocess which inherits the <tt>SSH_AUTH_SOCK</tt>
      environment variable, or you can run it as a daemon.

      <p>Since I run gdm on Debian, ssh-agent is started
	automatically when I log in.  If you don't have this
	benefit, you can get it by putting the following line at
	the end of your <tt>.xsession</tt> file (You can
	substitute your window manager for <tt>gnome-session</tt>
	if that is what you use):
      </p>

      <blockquote><pre>
      ssh-agent gnome-session
      </pre></blockquote>
      
      <p>Which basically means that ssh-agent starts up, creates a socket,
	sets up a couple of environment variables and then starts up
	gnome-session.  That way all of the programs run in Gnome have
	access to the agent.
      </p>

      <p>The above solution is the best one if you are logging in via
      GDM or another graphical login manager under *nix.  However, if
      you login at the console, or want to use ssh-agent under Cygwin,
      you'll have to use one of the following solutions.</p>

      <p>If you want to, say, put it in your <tt>.profile</tt>,
	then you might try the following setup.  In my
	<tt>.bash_profile</tt>, I have
      </p>

      <blockquote>
	<pre>
	  SSHAGENT=/usr/bin/ssh-agent
	  SSHAGENTARGS="-s"
	  if [ -z "$SSH_AUTH_SOCK" -a -x "$SSHAGENT" ]; then
            eval `$SSHAGENT $SSHAGENTARGS`
	    trap "kill $SSH_AGENT_PID" 0
	  fi
	</pre>
      </blockquote>

      <p>(If you use csh or tcsh, see <a href="#csh_login">this
      note</a> for the equivilent piece of code for your .login
      shell.)</p>

      <p>This brings <tt>SSH_AUTH_SOCK</tt> and
	<tt>SSH_AGENT_PID</tt> as environment variables into the
	current shell.
      </p>

      <p>The <tt>trap</tt> should kill off any remaining
	ssh-agent process.  If it doesn't, you won't want the
	ssh-agent daemons sitting around, so you might want the
	following in your <tt>.logout</tt>:
      </p>

      <blockquote>
	<pre>
	  kill $SSH_AGENT_PID
	</pre>
      </blockquote>

      <p>An alternative, provided by John Buttery, is</p>
      <blockquote>
	<pre>
        if [ ${SSH_AGENT_PID+1} == 1 ]; then
          ssh-add -D
          ssh-agent -k > /dev/null 2>&amp;1
          unset SSH_AGENT_PID
	  unset SSH_AUTH_SOCK
	fi
	</pre>
      </blockquote>

      <p>Finally, this solution from <a
      href="http://www.cygwin.com/ml/cygwin/2001-06/msg00537.html">Joseph
      M. Reagle</a> by way of Daniel Starin:</p>
      <blockquote>
	<pre>
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 -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
         start_agent;
     }
else
     start_agent;
fi 
	</pre>
	<p>This last version is especially nice since it will see if
	you've already started ssh-agent and, if it can't find it,
	will start it up and store the settings so that they'll be
	usable the next time you start up a shell.</p>
        <p>(Update 25 Sep 2007: Adam Piper pointed out that quoting
        anything that uses $HOME is necessary on Cygwin.)</p>
      </blockquote>
    </li>

    <li>Finally, time to type a password.  The last one of this session,
      maybe.
      <blockquote><pre>
      $ ssh-add ~/.ssh/id_dsa
      Need passphrase for /home/mah/.ssh/id_dsa (you@example.com).
      Enter passphrase:
      $
    </pre></blockquote>
    </li>

    <li>Now, you should test it:
      <blockquote><pre>
      $ ssh you@example.com
      Last login: Tue Apr 25 13:40:21 1492 from europe.com
      Sun Microsystems Inc.   SunOS 5.7       Generic October 1998
      No mail.
      [you@example.com]$ 
    </pre></blockquote>
      <p>Jubilation! It worked! Go forth and conquer!  (If it doesn't
      work, try <tt>chmod -R go-rw ~/.ssh</tt> on the server and try again.)</p>
    </li></ol>

  <p>Ok, so, did it work or no? <a href="mailto:mah@everybody.org">Let
      me know.</a></p>

  <p>If you want to use this setup for editing remote files in <a
      href="http://www.gnu.org/software/emacs/">emacs</a> under
      Windows, check out my <a href="tramp-on-nt">Tramp-on-NT</a>
      page.</p>

  <p>If you want to understand a little bit more about how all this
  works,
  read <a
  href="http://www.unixwiz.net/techtips/ssh-agent-forwarding.html"> An
  Illustrated Guide to SSH Agent Forwarding</a>.</p>


  <h2>Acknowlegements</h2>

  <p><b>27 Aug 2002</b>: David Previti offered the working
  Windows-client to Windows-server key copy command as well as
  other Window-isms.</p>

  <p><b>9 Aug 2002</b>: Lloyd Smith suggested verifying that
  <tt>sshd_config</tt> is set up to do DSA authentication if it
  fails initially.</p>

  <p><b>3 Jul 2002</b>: David Newcomb offered the trick of
  putting trap 0 in the login/profile script.</p>

  <p><b>18 May 2002</b>: A more complete logout script
  from John Buttery.  Also added tips on using RSA rather than
  DSA keys.</p>



</div>
<hr />
<div id="footer">
<table width="100%"><tr><td>
<address>
<a href="mailto:mah@everybody.org">mah@everybody.org</a>
</address>
<span class="modified">Last Modified: Tue Sep 25 09:38:05 2005</span>
</td><td align="right">

<a href="http://jigsaw.w3.org/css-validator/check/referer">
<img src="http://jigsaw.w3.org/css-validator/images/vcss.gif"
     alt="Valid CSS!" height="31" width="88" /></a>

<a href="http://validator.w3.org/check/referer">
<img src="http://validator.w3.org/images/vxhtml10"
     alt="Valid XHTML 1.0!" height="31" width="88" /></a>

</td></tr></table>
</div>
</body></html>
