This page last modified: Aug 05 2011
title:SSH public key authentication including scp, sftp, sshfs and X11 forwarding keywords:ssh,scp,public,key,authentication,authorization,key,pair,dsa,rsa,login,password,log,in,se,selinux,audit,auditd,fuse description:Configuring ssh to use your public key, scp notes as well as SELinux context problem diagnosis and fixes, sshfs and fuse, and how to configure X11 forwarding in order to run Firefox and Emacs in graphical mode. Table of contents ----------------- Shortcuts and .ssh/config X11 graphical appications Introduction to ssh keys How to determine which SSH version you have SSH public key setup and configuration Detailed ssh key explanations Using the -l limit option with scp How to sshfs, using ssh to mount a remote file system aka fuse How to create shortcuts in .ssh/config Host identification warning Public key not accepted due to SELinux context Permission denied (publickey,keyboard-interactive) due to config Shortcuts and .ssh/config ------------------------- If you have a file named "config" in the .ssh directory in your home directory, then that file will be used for aliases and other ssh options. I like have short name for each server (host) that I routinely login to. It is also useful to include a username if the destination user name is different. You'll also want to use a key pair (see below) so you don't have to type your password every time. From what I can tell, the information for each host begins with a "Host" line. I separate stanzas with at least one blank line. Lines beginning with # are comments. See notes below about the X11 configurations settings. I set EscapeChar to none because I am prone to use all my escape characters for something, and I don't want any conflicts. I have never used the escape anyway. If a session hangs, I kill it and start another. These options apply to OpenSSH. The commercial version may differ. With the config file in place, and your public key properly installed on the destination server (zeus.example.com), then you can login simply with: ssh zeus No password will be required. The config file: # see man ssh_config Host zeus HostName zeus.example.com User mst3k EscapeChar none ForwardX11 yes ForwardX11Trusted yes X11 graphical appications ------------------------- If you are running X-windows then you can run graphical applications just like they were on your desktop. Aside from minor style differences, the applications look and act like they are running on your computer, however, they are running on the server. This does require a fairly fast network connection. Use the ForwardX11 config as below. Linux-to-Linux normally does not need the ForwardX11Trusted. However, I have found that Mac-to-Linux requires it. (Probably because the Mac is configured not to trust other X11 servers.) If you run an X11 graphical application on the server, the window will appear on your X11 desktop, although the application is running on the server. Use "&" at the end of the command to run the application in the background, allowing you to continue to use your terminal. I typically run several terminal sessions, but I try to keep all my background X11 applications in one of the terminals. If you try to close a sessions with background jobs, you may get a warning. To view any background tasks, use the shell's "jobs" command. Here is a sample of what I see when I enter the command "jobs" with two background jobs: > jobs - Running emacs & + Running firefox & Here are three example commands that will run graphical applications (assuming that these applications are installed on your server): firefox & emacs & google-chrome & It is also possible to start the entire desktop, either KDE or Gnome. startkde & gnome-session & My initial trials with this were not good. I was running IceWM locally on a Macintosh and when Gnome started, the keyboard started sending the wrong characters. I'll try again without a local desktop, just plain XQuartz. Introduction to ssh keys ------------------------ Ssh keys are generally used to login securely with the need to enter a password. The "key pair" consists of a private key and a public key. The public key is installed on other computers. You keep the private key local on your computer, and you must make sure that your private key cannot be read by anyone else, including other users on your computer. Login via public key is more secure than a password because no one can look over your shoulder and see you type your password, and if your computer is infected with a trojan malware keyboard password sniffers, there's nothing to sniff. Ssh establishes an encrypted session before exchanging keys or passwords, so network packet sniffing will not reveal passwords or keys. I'm pretty sure that anything that seems to require copying private keys is wrong. I have never needed to copy a private key. Instead of copying a private key, generate a new key pair with the other user or other machine. The private key allows access from anyone, which is why private keys must also always be readable only by their creator. (users read only). Use this method to have a secure login without using a password. The machines are host1 and host2. Use this method to login to host2 without using a password. Assume you have accounts on both machines, and you able to ssh login to either machine using a password. Assume you are already logged in to host1. Assume your userid is mst3k. In order to avoid confusion, rename the public key that is copied to host2. Confusion would arise in the situation where multiple accounts and/or multiple users were logging in to host2. How to determine which SSH version you have ------------------------------------------- Use the command: ssh -V The two types of output are shown below. Commercial version from SSH Communications Security Corp. In this case "non-commercial" most likely means commercial software on a non-commercial licence to the university. [mst3k@hostx mst3k]$ ssh -V ssh: SSH Secure Shell 3.1.0 (non-commercial version) on i686-pc-linux-gnu [mst3k@hostx mst3k]$ OpenSSH, Open source version: [mst3k@host1 ~]$ ssh -V OpenSSH_4.2p1, OpenSSL 0.9.7f 22 Mar 2005 [mst3k@host1 ~]$ SSH public key setup and configuration -------------------------------------- # All steps when going from an OpenSSH machine to an OpenSSH machine # This has been tested. When running ssh-keygen you will be prompted # for a file name and a passphrase. Simply hit the return key to accept the # default file name, and enter no passphrase. cd .ssh ssh-keygen -t dsa scp id_dsa.pub host2:/home/mst3k/.ssh/host1_mst3k_id_dsa.pub ssh host2: cd .ssh cat host1_mst3k_id_dsa.pub >> authorized_keys # The last three steps above can be replaced by one command: ssh host2 'cd .ssh; cat host1_mst3k_id_dsa.pub >> authorized_keys' # Those tick marks around the command are single quotes, and that quoted # command is sent to host2 to be run as a shell command on host2. I # don't know if double quotes "" will work. Do not use backticks `` # which will not work because backticks evaluate the enclosed text in # the current shell. # All steps when going from an OpenSSH machine to a commercial SSH # machine. scp may require a -1 switch to force scp1 compatibility # mode. Note! The commercial SSH directory is .ssh2 (with a 2). # These steps have been tested when host1 was Fedora Core 4, and host2 # was SunOS 5.8. cd .ssh ssh-keygen -t dsa ssh-keygen -e -f id_dsa.pub > host1_mst3k_commercial.pub scp host1_mst3k_commercial.pub host2:/home/mst3k/.ssh2/host1_mst3k_commercial.pub ssh host2: cd .ssh2 echo "key host1_mst3k_commercial.pub" >> authorization # All steps when going from an commercial SSH machine to a OpenSSH machine. # This has not been tested. cd .ssh2 ssh-keygen -t dsa scp id_dsa_1024_a.pub host2:/home/mst3k/.ssh/host1_mst3k_commercial.pub # The following line may be necessary on host1 (the commercial SSH host) echo "IdKey id_dsa_1024_a" >> identification ssh host2: cd .ssh ssh-keygen -i -f host1_mst3k_commercial.pub > host1_mst3k_openssh.pub cat host1_mst3k_openssh.pub >> authorized_keys # All steps when going from an commercial SSH to a commercial SSH machine. # This has worked, but was not tested thoroughly. cd .ssh2 ssh-keygen -t dsa scp id_dsa_1024_a.pub host2:/home/mst3k/.ssh2/host1_mst3k.pub # The following line may be necessary on host1 (the commercial SSH host) echo "IdKey id_dsa_1024_a" >> identification ssh host2: cd .ssh2 echo "key host1_mst3k.pub" >> authorization Detailed ssh key explanations ----------------------------- #Create a OpenSSH DSA key pair. This might be the same for commercial SSH. # man ssh-keygen should answer questions. ssh-keygen -t dsa #Copy the DSA public key from host1 to host2 scp id_dsa.pub host2:/home/mst3k/.ssh/host1_id_dsa.pub # A variant of scp where your userid on host2 is explicit. scp id_dsa.pub mst3k@host2:/home/mst3k/.ssh/host1_id_dsa.pub # login, and cd to the ssh directory ssh host2 cd .ssh # DSA keys seem to want to be in authorized_keys, not authorized_keys2 (see RSA below) cat host1_id_dsa.pub >> authorized_keys #Create an OpenSSH RSA key pair: ssh-keygen -t rsa #Copy the public key from host1 to another host2 scp id_rsa.pub host2:/home/mst3k/.ssh/host1_id_rsa.pub # login and cd to the ssh directory ssh host2: cd .ssh # Note: it appears that RSA keys go into authorized_keys2 cat host1_id_rsa.pub >> authorized_keys2 # Debuging. To get access to verbose information, use ssh -vvv. # If you get the message: # userauth_pubkey_agent: no more key # This may mean that $HOME or $HOME/.ssh is group/other writable. # The following chmod fixed this problem: cd ~/ chmod go-rw . chmod go+x . # On an OpenSSH host, convert an OpenSSH key to the SECSH format. # Use this when you need to move an OpenSSH key to a commercial SSH machine. # In the following example, we assume that host1 is OpenSSH, # and host2 is commercial SSH. ssh-keygen -e -f id_dsa.pub > host1_mst3k_commercial.pub # On an OpenSSH host, convert a public key from a commercial SSH client. # Use this when you have a public key generates on a commercial SSH machine. # In this case, we assume that host1 was commercial SSH, and we are # logged in to host2. cd ~/.ssh ssh-keygen -i -f id_dsa_1024_a.pub > host1_mst3k_openssh.pub # Concatenate the key to the end of the authorized_keys file. cat host1_mst3k_openssh.pub >> authorized_keys # Logged in to commercial SSH machine host2 where host1_mst3k_commercial.pub is # an SECSH formatted public key. # Add a single line to the "authorization" file using the echo command. # Apparently, commercial SSH uses the key file name, in the authorization file # instead of the whole key. cd ~/.ssh2 echo "key host1_mst3k_commercial.pub" >> authorization #SSH Corp, non-OpenSSH # Contents of the file ./ssh2/authorization key=desktop_id_dsa_1024_a.pub # Contents of the file ./ssh2/desktop_id_dsa_1024_a.pub ---- BEGIN SSH2 PUBLIC KEY ---- Subject: mst3k Comment: "1024-bit dsa, firstname.lastname@example.org, Thu Aug 22 \ 2002 11:12:23 -0400" AAAAB3NzaC1kc3MAAbCBAMkSh4R0zsK/OSuXRwZaSM5vYu5UjTdGgEfFbLPEwvbI0KY2D0 yjOzRwm00qCq2KM5mRTNX+Q6OVkF+zU23hfcikXLen6aXIYhEMTuLZ2O/28WzqJfDY1XVB pJkKfnl0MLGKGJ1LTqH3D+XZdWi6zk7XmsXZ16rYOMXrEenMOfbxAAAAFQDr7U5JThqw9G 9aFFZXlnrsKeIxJwAAAIEAkzQPn/qG/J3gTRHIYxf0smmhFZ/sDzhwTOlmyMSpDHvqShYG SJVV8KmfNrnwIjcb4xbYSPg0OYjeOpWw5FzG3Pzjxm9dAa/sesMDDM/bgrpjG/m9GXvGei 7ZNllnsa4b9ny3rtu0to7TX3uFeNze6S5zcbNEpiaN74qDDQ1X97EAAACAE9rZJ7hbmiZG QR2t9y0jnM08JVfUPy78lYQl7HsZ/DmBdCOQ/Mc4segQOHERoxd7HBuktU0mJ0FtPy+vhH 2nOGdpkfZN/4UF7MOVB7APkFAKLMXCFFod8c6iiiP21hH/LlsqvS3fiwOfrSmb3ScOlHxG ccL8L585Xpwarijt+ks= ---- END SSH2 PUBLIC KEY ---- Using the -l limit option with scp ---------------------------------- The scp -l limit option uses Kbit/s which is kilobits per second (8 bits per byte). To convert to KB per second use Google calculator. Enter a query like the following into google.com 20 KBps in kbps For example, you have a 70 kilobyte per second DSL, and you want to move a large file, but you don't want to overload the DSL. You decide that 20 KB per second is fine. The answer (from Google) is 160 kbps (note lower case kb for kilobit versus uppercase KB for kilobyte). Somewhere I got the idea (seems accurate) that to convert kbps to actualy KB per second one multiplies by 0.088 760 kbps * 0.088 = 67 KB/s This must be actual throughput number since 760 kbps is actually 95 KBps (according to Google; I haven't done the conversion myself since I'm lazy). My DSL provider says I have a 760 kbps line, but max throughput is right about 67 KB/s. In any case, -l 160 with scp settles down (after 15 seconds or so) to 20 KB/s. scp -l 160 big.tar email@example.com: How to sshfs, using ssh to mount a remote file system aka fuse -------------------------------------------------------------- Many thanks to Ryan for telling me about this nifty way to connect to remote machines via ssh. I've tried this mounting a server that is on a DSL line, and then editing files with emacs. Works great. There were minimal (1 second or less) delays when saving files. - You will have to install the fuse-sshfs.i386 package (Fedora) if it doesn't already exist on your sytem. - Add yourself to the fuse group. Logout and login again or su -l to a new shell so that the shell has your new group membership. - Create an empty directory to use as a mount point. (As far as I know you can use any directory as a mount point, but it seems odd to mount a file system to a directory that has files in it. If you try to use sshfs on a non-empty directory, you'll get a message like this: fuse: mountpoint is not empty fuse: if you are sure this is safe, use the 'nonempty' mount option I suggest that you use an empty directory as the mount point, however, I've had no problems when mounting to a directory with files. This error: fuse: failed to open /dev/fuse: Permission denied means that either you aren't in group fuse, or your shell doesn't know it yet. See output from the groups command below. You may have to logout/exit your X session in order to get the shell to refresh your new group memberships. In the example below I'm "mst3k" on host "zeus". In my home directory I make a new directory "readme_files". I'm mounting "/home/remote/public_html/readme_files" on "./readme_files". (The full path of ./readme_files is /home/mst3k/readme_files.) Example session transcript: [zeus ~]$ groups mst3k fuse [zeus ~]$ pwd /home/mst3k [zeus ~]$ mkdir readme_files [zeus ~]$ sshfs firstname.lastname@example.org:public_html/readme_files/ ./readme_files email@example.com's password: [zeus ~]$ ls readme_files/ 3c905.html find_tricks.html perl_setuidperl.html 3c905.txt find_tricks.txt perl_setuidperl.txt actiontec_ethernet_modem.html firefox.html perl_sql_example.html actiontec_ethernet_modem.txt firefox.txt perl_sql_example.tar adduser.html fsck_check_logical_volumes.html perl_sql_example.txt adduser.txt fsck_check_logical_volumes.txt perl_syntax_errors.html analog_web_logs.html gconfd_firefox_evolution.html perl_syntax_errors.txt analog_web_logs.txt gconfd_firefox_evolution.txt pg_dump.html apache_13_error.html gconfd_http_launch_howto.html pg_dump.txt ... To unmount a fuse filesystem: fusermount -u mountpoint Using the example above: fusermount -u readme_files The filesystem will be unmounted even if there are files open in emacs because emacs (apparently) doesn't keep an i/o stream open to the file. In my (brief) test, when "less" was reading a file from the mounted filesystem, fusermount -u gave the expected message: umount: /home/mst3k/readme_files: device is busy umount: /home/mst3k/readme_files: device is busy As with sshfs, you must be in group "fuse" to run fusermount. The fuse home page is: http://fuse.sourceforge.net/sshfs.html The basic syntax is: $ sshfs [user@]host:[/path/to/folder] /local/mountpoint [-o mount_options,SSHOPT=value,...] If you leave out the username, it uses the default, just like ssh. If you leave out the directory, it defaults to your home directory (or more specifically, whichever directory you would start out in if you ssh'ed to that server). You can include ssh options in the mount options, and these will be passed to the underlying ssh process. Someone recommends "BatchMode=yes" but I have no idea why. An alternate way to show the same command format for etc/fstab is: sshfs#USERNAME@REMOTE_HOST:REMOTE_PATH MOUNT_POINT fuse SSHFS_OPTIONS 0 0 firstname.lastname@example.org:data /mnt/guest fuse uid=1003,gid=100,umask=0,allow_other 0 0 I'm not sure why #guest since I always just use a space after the ssh command. It is possible to set these up from fstab to mount at boot time (or rather, at such time as the network becomes available). Here are some working sshfs commands. Run this as root to mount mst3k from example.com to the current machine. sshfs email@example.com:/home/mst3k /home/mst3k -o nonempty -o follow_symlinks -o allow_other -o default_permissions -o workaround=rename Comments: -o nonempty # allow mounting to nonempty directories as mount pointes -o follow_symlinks # probably not necessary, but I have symlinks so I added this -o allow_other # necessary so that apache can serve web pages -o default_permissions # related to other users reading your files -o workaround=rename # necessary for CVS to work. The -o workaround=rename option fixes this problem: cannot rename file CVS/Entries.Backup to CVS/Entries: Operation not permitted I found a note about the rename problem in a FUSE support page: http://article.gmane.org/gmane.comp.file-systems.fuse.macfuse.devel/24 Run the command below as mst3k to mount home directory from example.com to the local file system: sshfs firstname.lastname@example.org:/home/mst3k /home/mst3k -o nonempty Here is a handy fuse FAQ: http://fuse.sourceforge.net/wiki/index.php/SshfsFaq As of May 2008 using Fedora 8, I have an unresolved error. Creating symlinks give an i/o error, but the symlink is created and works. The resulting symlink cannot be distinguished from a real file. Here is a session transcript: [mst3k@zeus CGKB]$ ls -l ~/public_html/omssaweb/session_lib.pm -rw-r--r-- 1 mst3k users 36592 2008-04-25 16:47 /home/mst3k/public_html/omssaweb/session_lib.pm [mst3k@zeus CGKB]$ ln -s /home/mst3k/public_html/omssaweb/session_lib.pm ./session_lib.pm ln: creating symbolic link `./session_lib.pm': Input/output error [mst3k@zeus CGKB]$ ls -l ./session_lib.pm -rw-r--r-- 1 mst3k users 36592 2008-04-25 16:47 ./session_lib.pm [mst3k@zeus CGKB]$ Also, I don't know if you use ftp often, but there's also curlftpfs, which allows you to mount an ftp server folder as a filesystem in much the same way. Here's the website for curlftpfs: http://curlftpfs.sourceforge.net/ How to create shortcuts in .ssh/config -------------------------------------- I often have to login to machines with long names like sassafras.unix.example.com. If the command is in my bash history I can use control-R to search backwards which is fast, but the ever clever Ryan suggested another, more comprehensive solution. Create a file ~/.ssh/config and add lines Host, HostName, and User. This is also great when you are logging in to a machine where your userid is different. # sassafras unix shortcut Host sas HostName sassafras.unix.example.com User msterry Host identification warning --------------------------- This means you need to delete the entry or entries in you .ssh/known_hosts file for the machine you are connecting too. This occurs after re-installing the operating system. It could also mean that someone is attempting a man-in-the-middle attack on your ssh connection. You can verify host identity by logging in to the remote host via some other method, and getting that host's RSA finger print. From the ssh man page, we learn how to get a hosts RSA fingerprint. The RSA keys are private, and therefore only readable by root. [root@zeus ~]# ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key 2048 e9:14:81:58:0b:b8:91:09:4d:f1:07:a7:1f:eb:ac:25 /etc/ssh/ssh_host_rsa_key.pub [root@zeus ~]# This might also be useful: ssh-keygen -R ip-address Here is a typical warning: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that the RSA host key has just been changed. The fingerprint for the RSA key sent by the remote host is 43:21:ca:82:d5:01:fa:b2:f4:a1:5b:56:98:09:bc:ba. Please contact your system administrator. Add correct host key in /home/mst3k/.ssh/known_hosts to get rid of this message. Offending key in /home/mst3k/.ssh/known_hosts:1 RSA host key for zeus.example.com has changed and you have requested strict checking. Host key verification failed. Public key not accepted due to SELinux context ---------------------------------------------- In May of 2008 with Fedora 8 I found that SELinux file contexts will prevent the use of public key authentication until the context is restored. For this example we have two machines "zeus" and "hera". Machine (server) hera is running SELinux, but is otherwise essentially identical to zeus. (Both zeus and hera are running up to date Fedora 8.) The public key on zeus has been generated as above, and copied to .ssh/authorized_keys on hera as usual (I used scp and authenticated with my password). File and directory permissions were all correct (700 for .ssh, 600 for all the files). This is the output from hera when the public key is not accepted: [zeus .ssh]$ ssh -v hera ... debug1: Next authentication method: publickey debug1: Trying private key: /home/mst3k/.ssh/identity debug1: Trying private key: /home/mst3k/.ssh/id_rsa debug1: Offering public key: /home/mst3k/.ssh/id_dsa debug1: Authentications that can continue: publickey,gssapi-with-mic,password debug1: Next authentication method: password ... Note that after the public key was offered, the server did not accept the key. When the public key authentication works properly you'll see these lines: debug1: Server accepts key: pkalg ssh-dss blen 434 debug1: read PEM private key done: type DSA debug1: Authentication succeeded (publickey). The problem is on hera. To diagnose the problem you must login to hera as a normal user (since we have root ssh logins disabled for security reasons), and then "su -l root". You must be running both setroubleshootd and auditd. If you are running setroubleshootd and not running auditd, then you'll find lines like this in your /var/log/setroubleshoot/setroubleshootd.log 2008-05-06 13:09:29,057 [avc.WARNING] could not open any audit sockets (/var/run/audispd_events, /var/run/audit_events), retry in 60 seconds Those "could not open any audit sockets" messages means that auditd is not running. Confirm by running "/etc/init.d/auditd status". Start auditd by running "/etc/init.d/auditd start" and remember to enable it at boot with "chkconfig auditd on". When both setroubleshootd and auditd are running, again attempt to ssh from zeus to hera and /var/log/messages says: May 6 13:11:47 zeus setroubleshoot: SELinux is preventing sshd (sshd_t) "getattr" to /home/mst3k/.ssh/authorized_keys2 (home_root_t). For complete SELinux messages. run sealert -l 85cae04a-0185-4921-8a68-e82dfbe0e955 May 6 13:11:47 zeus setroubleshoot: SELinux is preventing sshd (sshd_t) "getattr" to /home/mst3k/.ssh/authorized_keys (home_root_t). For complete SELinux messages. run sealert -l 3a90536d-63b9-4f2c-94da-513da0d5793f Now we see that there is some problem with /home/mst3k/.ssh/authorized_keys and /home/mst3k/.ssh/authorized_keys2. This would explain why the authentication didn't work. To see a diagnosis of the problem, run the recommended command sealert. You may run this command as root or mst3k (the normal user), however, only root can view /var/log/messages. sealert -l 3a90536d-63b9-4f2c-94da-513da0d5793f The output is long, but this is the important part: ... Sometimes labeling problems can cause SELinux denials. You could try to restore the default system file context for /home/mst3k/.ssh/authorized_keys, restorecon -v '/home/mst3k/.ssh/authorized_keys' ... To solve my problem, I ran /sbin/restorecon as mst3k, *not* as root. Note that /sbin is not in the default path for non-root users, thus you must type the entire path. [mst3k@hera .ssh]$ /sbin/restorecon -v '/home/mst3k/.ssh/authorized_keys' /sbin/restorecon reset /home/mst3k/.ssh/authorized_keys context system_u:object_r:home_root_t:s0->system_u:object_r:user_home_ssh_t:s0 [mst3k@hera .ssh]$ Problem solved. Login via ssh was successful using public key authentication. From this I conclude that users must be somehow aware of SELinux context (whatever "context" means) when creating files that will be used by the system and/or system daemons such as sshd. I su'd to root in order to read /var/log/messages and solve the problem. However, you may be able to sealert -l * in order to read alerts as a non-root user. Permission denied (publickey,keyboard-interactive) due to config ---------------------------------------------------------------- If you have a .ssh/config file on the originating computer and use a setting to force the use of publickey, but don't have a public key, login will fail. You don't be prompted for a password. You will get this message: Permission denied (publickey,keyboard-interactive) The key diagnostic is that login will fail from one computer, but not from another. This line is the feature in the config that causes this interesting situation: PreferredAuthentications password,publickey This can happen when you have a config file working on one computer, and copy the config file to a second computer, but forget to set up public keys. Being prompted for a password could be "password" or could be "keyboard-interactive". Using just one or the other could cause the failure, and you won't be prompted for a password.