|
What appears below are my personal notes I wish were part of my long-term memory but don't always seem to fit. I strive for accuracy and clarity and appreciate feedback. If applying any of this information anywhere, confirm for youself the correctness of your work as what you see below might very well be, albeit unintentionally, incorrect or misleading. These notes are here as an easy reference for myself.
Information worthy of a more formal presentation will appear elsewhere than this "Scratch" area. - ksb
Table of Contents | References |
ssh uses public-key cryptography to encrypt and authenticate communication. Public-key means that there are pair of keys (big numbers) each of which can be used to decrypt what the other encrypts. The idea is that only that pair work this way together so one is published (the public key) and the other kept secret (the private key) and used to identify the person who generated them both.
To use ssh to connect to another machine without being prompted for your password you need to set up that remote account to trust the local account. This is done by using your private/public key-pair by placing the public key on the remote machine in such a way that when logging into the remote machine, you on the local machine (and only you) can authenticate yourself using your private key.
The first step is to generate a pair of keys for yourself. This is done with the ssh-keygen command:
$ ssh-keygen -t rsa -b 2048 Generating public/private rsa key pair. Enter file in which to save the key (/home/ksb/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/ksb/.ssh/id_rsa. Your public key has been saved in /home/ksb/.ssh/id_rsa.pub. The key fingerprint is: 64:d1:b3:55:eb:32:c9:d8:34:73:ad:15:a9:1f:13:38 ksb@local
This generates an RSA 2048-bit pair of keys, into two separate files. It is important to use a strong passphrase to encrypt the private key. Otherwise anyone who gets a copy of that id_rsa file can masquerade as you. The whole idea of this is limiting who you need to trust - if you don't encrypt your private key then you are trusting whoever has root on that machine.
To set up the remote machine to trust you with this new key-pair you need to place the public key into the ~/.ssh/authorized_keys file on the remote machine. That file is a text file with one line per authorized key so it will look something like this:
$ cat ~/.ssh/authorized_keys ssh-rsa AAAA<very long key that goes on and on...>9XDQ== ksb@remote.example.com ssh-dsa AAAA<another long key>FR50+1x= ksb@another.example.com ...
Just add the public key generated above (id_rsa.pub) onto the end of that file or copy it there and name it authorized_keys. It is important that that file is not writable to anyone. This means that it must have at least 644 (rw-r--r--) permissions. That also means that it's parent directory and all parent directories do not have group write permissions. Also note that the part after the last '=' in each key is a comment and can be anything you like, which is useful for identifying who owns that key.
If you now try to ssh into the remote machine you will be prompted for the passphrase of your private key. This is because ssh is trying to authenticate you to the remote machine by decrypting a challenge which was encrypted with your public key (which is in the authorized_keys file on the remote server). Type in your passphrase and (barring other problems) you will be authenticated and logged in. If you fail to correctly type in your passphrase 3 times, then ssh will give up trying to authenticate you using your key and will prompt you for your unix password. But we're trying to use public keys here, so that won't do.
The ssh-agent program is used to store your private key in memory and be accessed by ssh programs (like ssh, scp, etc.) for authentication. This means you only need type in your passphrase once, when loading it into the agent. There are several ways to set this up, but what needs to happen is for the ssh program to be able to access the agent via the $SSH_AUTH_SOCK environment variable. One way to do this is to run the command:
$ eval `ssh-agent | tee ~/.agent` Agent pid 2560This will start an ssh-agent and both evaluate it's stdout and write it to the file ~/.agent. Looking at ~/.agent we can see that it simply sets a few environment vars:
$ cat ~/.agent SSH_AUTH_SOCK=/tmp/ssh-uwgqfN3868/agent.3869; export SSH_AUTH_SOCK; SSH_AGENT_PID=2560; export SSH_AGENT_PID; echo Agent pid 2560;The file identified by $SSH_AUTH_SOCK is a Unix domain socket which the agent is listening on. This is own and read/write only by you. This is how the ssh programs connect to the agent.
Another (preferred way when running X) is for ssh-agent to be the parent process of your window manager. This way the agent can pass the $SSH_AUTH_SOCK var down to all child processes you will run in that window session. This can be done by starting the window manager as follows in your ~/.xinitrc:
$ ssh-agent /usr/X11R6/bin/gnome-session
ssh-agent will start, fork your window manager (or whatever other program you pass to it) and continue until the window manager exists, at which time it will exit.
In the past I suggested here that if you are logging into a remote machine and want to start an agent there, to do:
$ exec ssh-agent bash
which replaces your current shell with the ssh-agent program which in turn forks bash as your shell. I'm now in favor of either using the above eval command (as it is easier to connect to the same agent if you open another shell on that machine by simply sourcing ~/.agent) or using agent forwarding.
If you now, after starting an agent, try to log into the remote machine, you will still be prompted for your passphrase. This is because the agent doesn't know about any private keys yet. To load your private key into your ssh-agent process, use the ssh-add program. Here's a simple example:
$ ssh-add Enter passphrase for /home/ksb/.ssh/id_rsa: Identity added: /home/ksb/.ssh/id_rsa (/home/ksb/.ssh/id_rsa)
Note that it prints the private key file you are adding into the agent. This will only need to be once per agent, as all programs which know how to access the agent will benefit from it. You can specify the key to load, and load multiple keys into a single agent.
To list what is currently added into the agent use the -l flag:
$ ssh-add -l 2048 64:d1:b3:55:eb:32:c9:d8:34:73:ad:15:a9:1f:13:38 /home/ksb/.ssh/id_rsa (RSA) 2048 d8:34:73:ad:15:a9:1f:13:38:f3:32:3d:e9:a1:b9:03 /home/ksb/.ssh/id_dsa (RSA)
This is also a good way to see if you have an agent running, accessible to the current shell and what keys it has loaded.
The ssh-askpass program can be helpful in adding ssh private keys into your agent when running X. (There are actually several such programs, I use gnome-ssh-askpass2.) Here's how I use it in my ~/.xinitrc:
$ cat ~/.xinitrc SSH_ASKPASS=/usr/X11R6/bin/gnome-ssh-askpass2 export SSH_ASKPASS ssh-agent /usr/X11R6/bin/gnome-session
All this does is set the SSH_ASKPASS var to the gnome-ssh-askpass2 binary for my window session. Then I add
/usr/bin/ssh-add /home/ksb/.ssh/id_rsa /home/ksb/.ssh/id_dsaAs a Gnome startup program (Applications->Desktop Preferences->Advanced->Sessions->Startup Programs, make it order 200 so it is last). This will pop up a login-like panel which will prompt you for the passphrase of your private keys and load them into your agent.
The phrase "port forwarding" is somewhat descriptive of what an SSH tunnel does but I think the phrase "connection forwarding" is better. An SSH tunnel forwards connections to a port on your local machine to be connections made from a remote machine to another remote machine.
As an example, say you are at home and can ssh into your office workstation which is behind a firewall, but can't directly reach the office intranet which is also behind the firewall. You want to be able to browse through the office intranet from your home machine, so you set up a tunnel between your home machine and your office workstation (which can reach the intranet). Assuming you've got your keys in place such that your office workstation mydesk.work.com trusts connections from your home machine, run this command on your home machine:
$ ssh -NL 8080:intranet:80 mydesk.work.com & [1] 25737This will forward connections to localhost:8080 (on your home machine) via this tunnel to be connections to intranet:80 from your office workstation mydesk.work.com. So the URL http://localhost:8080/ be as if you had hit the URL http://intranet from your workstation. Note: if the remote web site has link to a hostname, or expects a hostname (for virtual servers or URL rewriting) then you should direct your web browser to use localhost:8080 as a proxy. This isn't a real proxy but should work as long as you stay browsing on that machine.
The -N says to not run a command on the remote machine, which is useful for when all you want is port (er, connection) forwarding like this.
These tunnels can be used for forwarding connections to any port, even the ssh port. Say you wanted to ssh to the intranet machine which is only reachable from behind the firewall. You could use two ssh commands and/or agent forwarding, but using tunnels you would:
$ ssh -NL 2222:intranet:22 mydesk.work.com & [1] 25738 $ ssh -p 2222 -o HostKeyAlias=intranet localhostThe first command sets up the tunnel, and the second command ssh's to intranet through mydesk.work.com. From the perspective of the machine intranet, you've logged in from mydesk.work.com not your home machine. The -o HostKeyAlias=intranet instructs ssh to expect the hostkey of intranet for host authentication rather than localhost.
You can customize and enhance ssh behavior by writing a ~/.ssh/config file. For example:
Put example hereI'll finish this later after getting something to eat...