Defindit Docs and Howto Home
This page last modified: May 12 2008
title:SSH public key authentication including scp, sftp, sshfs.
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 and scp notes as well as SELinux context problem diagnosis and fixes; also sshfs and fuse.
Table of contents
-----------------
Notes
Using the -l limit option with scp
How to determine which SSH version you have
SSH public key setup and configuration
Detailed explanations
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
Notes
-----
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.
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 mst3k@example.com:
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.
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
# 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 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, mst3k@host1.example.com, 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 ----
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 remote@example.com:public_html/readme_files/ ./readme_files
mst3k@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
sshfs#guest@guest.login.com: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 mst3k@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 mst3k@example.com:/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.