SSH Config File
The user defined SSH config file (~/.ssh/config) can save a lot of typing. Any options to ssh are first gotten from the command line, then from config files. Only the first value found is used. An example file follows:
Host newton HostName newton.zgib.net # so if you do `ssh newton`, it really turns it into `ssh newton.zgib.net` # makes it easier to type, and you can tab complete it. User rkdarst HostKeyAlias newton # you probably won't need this. ForwardX11 yes #Port 2222 # to change the port # defaults last Host * ForwardX11 no
Now, instead of having to login with ssh firstname.lastname@example.org, all you would have to type is ssh newton. This can be especially nice when it comes to doing lots of scps, rsyncs, or anything else over ssh. The same file and aliases work with anything that uses ssh (rsync, unison, etc.).
The ForwardX11 yes option should be obvious as to what it does. (Richard thinks this should never be done for *, since it is a security risk. I demonstrated that by simply sshing to a computer you don't own, root can a) grab ALL keystrokes b) take screen shots c) send commands to windows, but I haven't done (c) yet. So, I recommend turning it off for *, and turning it on when you need it. The config file makes this easy. If anyone can demonstrate how times have changed, let me know.) This does not affect you if you are running a server, only if you are the one doing the sshing to someone else. You can't hurt the server, the server can hurt you. Note that even the ssh_config manual page warns you of this.
In order to enable X forwarding, the server also needs to be set up in /etc/ssh/sshd_config:
There is no reason to not do this.
I have heard of public/private key authentication that will let you restrict what commands can be run, but I haven't found much documentation for it. This article (http://www.jdmz.net/ssh/) mentions it (look near footnote 4 in the text.) It says to do:
from="10.1.1.1",command="/home/remoteuser/cron/validate-rsync" ssh-dss AAAAB3Nza...
There is more information on this in the sshd manual page, which is online at http://www.openbsd.org/cgi-bin/man.cgi?query=sshd.
command="unison -server",from="160.39.55.*" ssh-...
First off, we need to make our passwordless, limited ssh keys. We want to be very clear in our filenames here, since otherwise we might get the keys confused! That would be... bad. For the filenames and comments, ramanujan and lefschetz are the names of the machines that this key will be able to ssh from and to. We also want the -C to specify a comment for what this key does (this will appear in the authorized_keys on the other computer - good for auditing later!). Remember, do not enter a password for making this key.
1 ssh-keygen -C "ramanujan->lefschetz limited-access key for rsync" -f .ssh/rsync-auto-ramanujan-lefschetz.key
Then, copy the .ssh/rsync-auto-ramanujan-lefschetz.key to .ssh/authorized_keys on the remote machine. Next, we need to limit this key, so that it can _only_ run rsync. To do this, we want to use a special syntax in .authorized_keys. We add command=XXX,no-port-forwarding,no-X11-forwarding to the front of the line with the key file.
command="python .ssh/rsync-limited.py",no-port-forwarding,no-X11-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuyTCqO.....
This will always execute the command python .ssh/rsync-limited.py when you log in with this key. The trick is making a correct .ssh/rsync-limited.py file.
Here is my example:
- This script could use more eyes, to ensure that there are no vulnerabilities with it. Note, it restricts paths you can access, but not rsync options, which could be problematic in some cases.
1 #!/usr/bin/env python 2 import os, string, sys 3 #print >> sys.stderr, os.environ['SSH_ORIGINAL_COMMAND'] 4 5 PATHS = ('/srv/wiki-data/richard-data/', ) 6 RSYNC='rsync' 7 8 command = os.environ['SSH_ORIGINAL_COMMAND'] 9 10 # Send-only: 11 assert " --sender " in command 12 # Recieve only 13 #assert "--sender" not in command 14 15 cmd = command.split(' ') 16 newcmd = [ ] 17 18 assert cmd == RSYNC 19 newcmd.append(cmd.pop(0)) 20 21 assert cmd == "--server" 22 newcmd.append(cmd.pop(0)) 23 24 if cmd == "--sender": 25 newcmd.append(cmd.pop(0)) 26 27 assert cmd == '-' 28 for char in cmd[1:]: 29 assert char in string.ascii_letters + string.digits + "." 30 newcmd.append(cmd.pop(0)) 31 32 assert cmd == '.' # This period is always here, not sure why 33 newcmd.append(cmd.pop(0)) 34 35 assert cmd in PATHS 36 newcmd.append(cmd.pop(0)) 37 38 assert not cmd # We completed parsing, nothing left in cmd 39 40 os.execvp(RSYNC, newcmd)
Let's test it. This tries to run the command date on the server, but should fail since it isn't a valid rsync command.
ssh -o IdentitiesOnly=yes -i ~/.ssh/rsync-auto-ramanujan-lefschetz.key lefschetz date
- Aside: if you have ssh multiplexing enabled (see below), you want to disable that with these ssh options:
-o ControlPath=/nothere -o ControlMaster=no
Now, how to use rsync? Like this:
rsync --rsh="ssh -o IdentitiesOnly=yes -i ~/.ssh/rsync-auto-ramanujan-lefschetz.key" OPTIONS SOURCE DESTINATION
You might not want to use a --delete option, since that means if the other end gets destroyed, then your copy will get destroyed on the next backup
For a more advanced system, see this: http://wiki.hands.com//howto/passphraseless-ssh/ , including a nice two-way ssh method.
If you put this in your config file, you can multiplex ssh connections. The first connection does all normal authentication, and the future ones piggyback off of it. It can save startup time but cause subtle problems if the first connection closes or tries to close. Furthermore, if you have start a second ssh process, it can't forward any additional ports (or X11).
Host * ControlMaster auto ControlPath /tmp/.ssh-richard-mux-ssh-%r@%h:%p
You may have to remove the /tmp/ file if the connection dies unexpectedly and leaves the file there.
To selectively disable ssh muxing, I have this script named ssh-nomux:
exec ssh -o ControlMaster=no -o ControlPath=/nothere "$@"
And bash completion for it:
complete -F _ssh ssh-nomux