NOTE: This section was originally written by VincentDanen as a piece for the
One of the problems with
Of course, using
One of the best features of
For instance, assume that you are the administrator of a particular server. You regularly SSH into the server to perform maintenance. This server is also a mail server from which you retrieve your mail. While you are astute enough to use SSH to protect the information you send in-transit (passwords, commands used for your administration, etc.), you use a regular POP3 client to retrieve your POP3 mail. Most people know this is not a good idea as POP3 traffic is completely in the clear; the POP3 password will be sent with no encryption and no security whatsoever. For the sake of argument, let's assume that you mean to setup a POP3S server (POP3 over SSL) in the future, but haven't had the opportunity yet. Any malicious individual sniffing network traffic could obtain your POP3 password. Since you don't use any virtual mail-hosting software, and the POP3 account is linked to your shell account, you are basically sending your login information across the network for all to see. The attacker could take your login name and password and use it to obtain shell access to the system; they would most likely use your secure alternative to telnet to do so.
This scenario is a bad one; that goes without saying. There are a few simple ways to mitigate this problem: The first is to use a virtual mail hosting system that separates mail users from system users, ensuring that mail users do not have a valid shell account. The second is to use encryption for POP3 traffic by utilizing POP3 over SSL. The final method is to use SSH keys.
To extend the above scenario, assume the administrator has configured the
The advantages of SSH keys should be obvious. The first step
in heading towards a password-less SSH experience is to generate a
keypair that has both a public and private key. SSH uses three types
of keys: RSA1, RSA2, and DSA. It is recommended to completely
disregard RSA1 entirely (both asenabled protocol in
To generate a DSA keypair, execute (as the user to whom the keys should belong):
$ ssh-keygen -t dsa
This will, by default, create a 1024 bit DSA key with the private key being stored in ~/.ssh/id_dsa and the public key being stored in ~/.ssh/id_dsa.pub. If you wish to use an RSA2 key, use " -t rsa
" instead on the command line and if you wish to generate an RSA1 key, use " -t rsa1
".
You will be asked for a passphrase to secure the private key. This passphrase should be between 10 and 30 characters and difficult to guess. It should also be a good mix of numbers and letters, punctuation and whitespaces. It is deliberately called a passphrase, not a password. This private key must be protected at all costs, so the passphrase is important. The private key file should also be readable only by the user and no one else.
If you wish to change your passphrase, you can do so using this command:
$ ssh-keygen -p -f ~/.ssh/id_dsa
This tells ssh-keygen
to change the passphrase on the private key stored in the file ~/.ssh/id_dsa
(a DSA private key). You will be asked for the old passphrase and the
new passphrase. If you ever forget the passphrase for a key, there is
no way to retrieve it. You will have to generate a new key, delete the
old key, and distribute the new public key to the servers you wish to
use it with.
Now that the first step is completed, you must copy your public key onto whichever remote server you wish to access. If password authentication is enabled on the remote server, you can copy the file to your home directory there yourself; if password authentication is not enabled, you will need to send the public key to the administrator of the system for them to place for you.
Public keys belong in the ~/.ssh/authorized_keys file on the remote server. For instance,
The caveat is that if you use a protocol 2 key, the server
must support protocol 2. This should be a non-issue because protocol 2
is much more secure than protocol 1, and should be used over protocol
1. Some sites have taken to disabling protocol 1 altogether, while by
default in
Now, when you wish to copy a file with scp
or login via ssh
,
you will be asked for your passphrase locally. The passphrase will
unlock the private key, allowing you to log into the remote server
without any passwords being exchanged over the network.
One final note. Unless you copy your public key to the remote server yourself, verifying the host is who it is supposed to be and using a secure means of transport (ie. SSH itself), you should not trust the public key. For instance, if Joe sends his public key to Bob (who is the administrator of said remote system), asking Bob to apply his public key to his account's authorized_keys file, Bob should not trust the key itself, unless Joe provides him the key physically (ie. on a disk, in person). If Joe emails the key to Bob, Bob must assume that the key may not be legitimate as email is an insecure means of transport. To get around this, Joe can email the key to Bob and then give him a phone call and let him know what the key's fingerprint is. Again, depending on Bob's level of paranoia, this may or may not be an acceptable means of verifying the key. This dilemma is similar to signing keys in GnuPG, and applies with any public key tool when an insecure transport method is utilized. For the sake of argument, Bob knows who Joe is, they've met, and he can verify that Joe is who he claims to be on the phone. The fingerprint that Joe would give to Bob can be obtained by executing:
$ ssh-add -l id_dsa.pub 1024 61:ed:d2:82:35:b4:54:3d:92:26:f8:48:69:21:de:c3 /home/joe/.ssh/id_dsa (DSA)
This shows the fingerprint for Joe's public DSA key. Bob can likewise used the same command on the key Joe claimed to have sent him, and if the two fingerprints match, he can assume the key is legitimate.
This more or less covers the use of public/private keys in
While using keys is more beneficial than using passwords, there is a
particular drawback. Because a passphrase should be long and difficult
to guess, re-typing it each time can be cumbersome and just plain
annoying. To get around this,
$ ssh-agent $ ssh-add
This will not work if you execute it in an xterm; if you do, ssh-add
will generate an error that it cannot connect to the agent. This is because the output of ssh-agent
needs to be sourced as environment variables; it provides the PID
(process ID) of the agent and the path to the socket file the agent
uses. Without this information, ssh-add
doesn't know which agent to connect to, nor does it know how to connect to it. ssh-agent
is meant to be run during a login shell or when starting X; and some
operating systems, such asMandrake Linux, do this automatically for you
when you start a new X session. In Mandrake Linux, if you start a new
X session, then open a terminal and simply type "ssh-add", your keys
will be added to the appropriate agent, provided you give the correct
passphrase.
If you wish to delete an identity from the agent, you can do so with the -d
parameter. For instance, if you have both an RSA and DSA key, and wish to remove the RSA key from the agent, you would use:
$ ssh-add -d ~/.ssh/id_rsa
If you wish to know what identities are loaded, you can do so with the -l
option. Using -D
will delete all identities from the agent.
There is a very handy utility called Keychain which you can use to load your identities into an agent that can be used for the duration of the machine's uptime. Currently, if you log out of X, your agent is removed, and when you log in again later, you will have to re-enter your passphrase. With Keychain, you enter your passphrase once and it can be used across multiple X sessions and even a console login without re-entering your passphrase. If the system reboots, you will have to re-enter your passphrase again, but it will persist until the agent is killed or the system is rebooted again.
Keychain is extremely simple to install. It is a single bash script that you install into /usr/bin. Download the Keychain tarball, untar it, and install it into /usr/bin as root. Then, for each user that wishes to use Keychain, the ~/.bashrc file must be edited to look like this:
# .bashrc # User specific aliases and functions # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi /usr/bin/keychain -q ~/.ssh/id_dsa . $HOME/.keychain/${HOSTNAME}-sh
The last two lines are of interest. This tells Keychain to load the ~/.ssh/id_dsa key and to be quiet when doing so (usually Keychain is verbose and tells you if it started a new agent, connected to a new one, and whether or not it added a key). If you wish to have more than one key, simply add the keys to the command line. For instance, an individual using an RSA1, DSA, and RSA keys might use:
/usr/bin/keychain -q ~/.ssh/identity ~/.ssh/id_dsa ~/.ssh/id_rsa
Now, the next time you log in to the console or open an xterm, Keychain will run and load all of the specified keys into your agent.
One final note on using agents: They are not very secure. While standard UNIX permissions will protect the IPC channel used to communicate with the agent, if a system is compromised, these permissions can be circumvented. To this end, agents should only be used on trusted machines because they load your private key into the cache, unencrypted. If an attacker were to compromise a system and obtain access to the agent, they could make their own requests of the agent until the agent was killed or the private keys removed from the cache.
If you are using the agent in a workplace or other untrusted
or semi-trusted environment, you will want to remove your private keys
from the agent if you will be away from your system for a significant
period of time (such as overnight or if you leave the premises for
lunch). Using the -D
option with ssh-add
will clear out all keys. By using Keychain, you are not opening
yourself to any further holes; Keychain simply uses available programs
to do it's job. If the identities are not in the agent, Keychain will
call ssh-add
, which will in turn ask for your passphrase.
The obvious drawback here is that a user can try to guess your
passphrase, thus obtaining access to your private key. Of course,
common sense prevails here as well. Clearing out the agent is a very
appropriate step, but locking your console or terminal, or logging out
completely while you are away, is an even better means of protecting
your private keys.
Probably one of the more widely used features in SSH is it's ability to create secure tunnels for insecure transports. For example, we all know that POP3 is an insecure protocol. If you have shell access to the POP3 server you retrieve mail from, you can use an SSH tunnel to pass your POP3 data via SSH from the remote to the local machine. The same goes for X applications; you can ssh into a remote machine, execute a GUI application on the remote system and have the application "open" on your local display. This feature of SSH is extremely powerful as it allows you to use insecure protocols in a secure manner, without opening additional ports on your firewall or relaxing access permissions or utilizing unencrypted traffic in order to make the connection or execute the application.
Let's assume for a moment that you want to wrap connections to your POP3 server with SSH. This can be done if you have SSH access to your POP3 server. The first step is to select a local port between 1024 and 65535; these are port numbers that unprivileged users are allowed to bind to. For example, choose port number 10110. Create the SSH tunnel like this:
$ ssh -L10110:localhost:110 remotesystem
This creates a tunnel that links port 10110 on the localhost to port
110 on the remote system, "remotesystem". It will also open a normal
SSH connection to the remote host. By using the netstat
tool, we can see that the port is in fact open and listening for connections:
[user@localhost user]$ netstat -l --tcp -p|grep ssh (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp 0 0 *:ssh *:* LISTEN - tcp 0 0 localhost.localdo:10110 *:* LISTEN 31295/ssh [user@localhost user]$
When you exit the SSH shell, the forwarding connection will close as
well. Before you exit the shell, however, you can have your email
client retrieve POP3 mail; not by connecting to remotesystem:110, but
by connecting to localhost:10110. Having an open terminal, however,
may not be always what you want. For instance, if you wanted to use
cron to retrieve your emails via fetchmail
or a similar program, you don't want a shell to be opened to the remote
host. To accomplish this, you must give the SSH command something to
do on the remote server. There are two avenues you can take here;
persistent forwarding or temporary forwarding. With temporary
forwarding, you are opening the tunnel for a short period of time; just
enough to allow your email client or retrieval program to connect to
the remote host via the tunnel. For instance:
$ ssh -f -L10110:localhost:110 remotesystem sleep 10
This tells SSH to go into the background ( -f
), open our tunnel, and execute the command " sleep 10
". Normally, once this command is complete, SSH will terminate the session. However, if fetchmail
utilizes the tunnel within that 10 second window, SSH will wait for the
connection to terminate before exiting. This allows you to make use of
the tunnel for the duration of your fetchmail
run, but
doesn't leave it open for a prolonged period of time. On the other
hand, if you check your mail every few minutes, it may be more
convenient to keep a persistent connection open. You can do this by
giving the sleep
command a longer amount of time, such as
a value of 100000 or so. You could even get creative and execute a
small script on the remote system that does nothing but continuously
call the sleep
command with extremely large values. This prevents you from opening and closing connections on a continual basis.
Forwarding X11 data works on the same principle. In the client configuration file (/etc/ssh/ssh_config or /etc/ssh_config on some systems), if
When you ssh into a remote host, you can execute X11 programs on the command line, just as you would if you were using an xterm on the local system. On the local system, the DISPLAY variable is used to tell X11 programs where to run; on the local system the DISPLAY variable might be set to ":0". On a remote system, when connecting via SSH, the value of DISPLAY will be something like "localhost:11.0". Again, this is forwarding magic that is virtually transparent to the programs you run, and to yourself. As with all things *nix, there are a few ways you can run remote X11 programs. The first, and probably most widely used, is to actually SSH into the remote system and execute the command, like this:
[user@localhost user]$ ssh user@remotesystem [user@remotesystem user]$ gkrellm &
This illustrates connecting to the remote box "remotesystem" as the user "user" and executing gkrellm
, a graphical monitoring tool. Note the "&" character at the end of the commandline to indicate that gkrellm
should launch into the background, keeping the terminal free for you to
use. You could omit the "&" character and simply keep gkrellm
attached to the terminal, minimizing the terminal on your desktop and ignoring it. A more efficient means of launching gkrellm
remotely is by executing:
[user@localhost user]$ ssh -f user@remotesystem gkrellm
Doing this, you can close the xterm you used to execute ssh
, leaving the gkrellm
monitor on your desktop, unattached to any session, because ssh
is backgrounded. If you want to close the connection, kill the program
you called. When you close the program, the instance of ssh
is likewise terminated.
There are times when you will want to use SSH and you won't be around to enter in a passphrase. Backups from remote systems over SSH are a good example, or launching commands on remote systems via cron on the local system. In these cases, you may want to create a special account to do the maintenance; an account that cannot be accessed on the local system.
For instance, assume you wanted to run a backup every night using rsync over ssh. You would create a user with the name "backup" or "mirror" or something similar. Create a new SSH keypair for this user with an empty passphrase. Copy this user's key to the remote server. Depending on what you want to backup, you may have to add this user's key to the root account's ~/.ssh/authorized_keys file. Be warned that this gives the user immediate and password-less access to the root account on the remote system! This can be a very serious security hole if you do not configure things properly.
Now that the user has access to the root account, you can write your shell script and associated crontab entry to run the backup. For instance, you may run the following script daily on your system, as the backup user:
#!/bin/sh RSYNC="/usr/bin/rsync -aP --quiet --delete -l -t -e ssh" cd /data/backup/host $RSYNC root@host:/etc . $RSYNC root@host:/home . ...
Now this script can be executed every night by the backup user. It will run successfully because there is no passphrase defined for the user's private key, and the public key is in the remote root user's authorized_keys file. Now you have to secure the backup user's account. The first step is to modify the sshd_config file and add to it:
DenyUsers backup
This will disallow anyone from attempting to login to this account via SSH. Next, edit the /etc/passwd file. Here we will remove the ability for the backup account to login to the system via the console. To do this, execute the vipw
program as root. Assuming your backup user's name is "backup", you will want to find the line that looks like this:
backup:x:512:512:Backup User:/home/backup:/bin/bash
The second field, "x", represents a shadow password. However, we can change the "x" to a "*" which tells login to disallow logins for this account. So this line would look like this when you have finished editing it:
backup:*:512:512:Backup User:/home/backup:/bin/bash
By default, vipw
uses the vi
text editor. If you are unfamiliar with vi
,
press the "i" character to get into INSERT mode; this will allow you to
change the password field. When you have changed it press ESC to get
back into command mode, then type ":wq" to exit and save your changes.
When you are done, vipw
will ask you if you want to edit the /etc/shadow
file as well. Press "n"; we still want this account to have a real password.
What we have now accomplished is this: User "backup" cannot
login via SSH, nor can "backup" login at the command line. You can
still use su
to change to the user, which is why we want to keep the shadow password;
non-root users will still have to supply a password to change to
"backup". Make it as cryptic as possible; if you have root privilege
on the system, you don't have to even worry about remembering the
password as you can su
to "backup", as root, without
knowing the user's password. This will protect the "backup" user from
access via SSH, taking care of remote logins, from local access by
disallowing login for this user, and from existing users by retaining a
password.
Finally, another option is to use Keychain, as noted previously. With Keychain installed, you can do your backups as a regular user, with a passphrase-protected keypair, without causing problems for the cron-scheduled job provided that you supply the passphrase at least once before your cron jobs run.
Configuring the client consists of three files: /etc/ssh/ssh_config (or /etc/ssh_config), which is the system-wide configuration file, ~/.ssh/config which is the user's personal SSH configuration, and ~/.ssh/authorized_keys which can configure incoming connections for this client.
A nice default client-side configuration that allows users to use X11 forwarding would look something like this:
Host * ForwardX11 yes Protocol 2,1 StrictHostKeyChecking ask
The ssh_config(5)
manpage covers each option in detail.
Here we are essentially telling SSH to enable X11 forwarding, use
protocol 2 then fallback to protocol 1 if protocol 2 is not supported,
and enable strict hostkey checking (but ask us what we want to do about
it), on every remote connection. This is fairly liberal, but still
relatively secure.
This configuration also does not allow you to forward the
connection to your authentication agent to the remote system. The
benefit here is if you are bouncing between multiple machines, you can
use the same key on your originating system on all systems that have
that public key available. For instance, if you are on compA and
connect to compB (which has a copy of your public key), you will not
need to specify your password on compB. If you then decide to ssh into
compC (from compB), you will have to enter your password on compC if
Leaving the ssh_config file as-is is probably a good idea. Anything special that you wish to configure can be done in the user's own configuration file, ~/.ssh/config. There are a lot of time-saving things you can do with your personal configuration. The basic format of the file is:
Host [host] options ... Host [host2] options ...
The file is read top-down in a "first match wins" order. When creating your configuration file, make sure that the more specific entries are listed first, with wildcard or global Host entries define last. Likewise, there is a distinct order of preference with options specified by SSH because you can specify options on the commandline, in the user's configuration file, and in the system configuration file. The highest precedence of a given command is given to the commandline, then the user's local configuration file, then the system configuration file.
The following is an example ~/.ssh/config file:
Host devel HostName myserver.mydomain.com User special Host otherserver.mydomain.com User admin ForwardAgent no Port 220 ForwardX11 no Host *.mydomain.com ForwardAgent yes Compression yes
This configuration file illustrates a few things. The first entry defines the Host "devel", which has a real
The second entry defines the Host otherserver.mydomain.com. This entry uses the FQDN for the host and not an alias. It also specifies the default user to connect to as being "admin", that agent forwarding is to be disabled, that connections are to be made to port 220 by default, and that X11 forwarding is likewise disabled.
The next entry defines the wildcard *.mydomain.com. This defines that agent forwarding is allowed, and also that we enable compression by default. Now, with these three rules, we can determine what features will be enabled by each host. Remember, we're using a default ssh_config file, so we also have options defined there that work on all hosts. The following table shows what options will be enabled when connecting to myserver.mydomain.com, otherserver.mydomain.com, myhost.mydomain.com, and otherhost.otherdomain.com:
HostName | User | ForwardAgent | ForwardX11 | Port | Compression | Protocol | StrictHostKeyChecking |
myserver.mydomain.com | special | yes | yes | 22 | yes | 2,1 | no |
otherserver.mydomain.com | admin | no | no | 220 | yes | 2,1 | no |
myhost.mydomain.com | user | yes | yes | 22 | yes | 2,1 | no |
otherhost.otherdomain.com | user | no | yes | 22 | no | 2,1 | no |
Looking at the table, you may not see what you would expect. Why does myserver.mydomain.com have
The otherserver.mydomain.com entry, on the other hand, negates the
Finally, when connecting to otherhost.otherdomain.com, only
As you can see, client-side configuration can be quite flexible, and doing so can be a time-saver. If you routinely ssh into a system with a username other than that on your local box (ie. userX on the remote system, userY on the local), you can define a Host entry to match the remote system and use the User keyword to specify userX. This way, you only have to type "ssh remotehost" instead of "ssh userX@remotehost". By default, if you only specify a hostname on the commandline (ie. "ssh remotehost"), ssh will try to log in with the same username invoking ssh (ie. userY invokes "ssh remotehost" so ssh will try to login as "userY@remotehost" which may not always be accurate).
So far, this has dealt with outgoing ssh connections. How about incoming? You can configure how SSH will handle connections to your account as well. There are a few limitations to configuring things this way. Firstly, configuration directives will never override server-wide configuration, unless permitted (for example, you can increase the server's idle timeout, but cannot enable password authentication if it is disabled site-wide). It is also highly recommended that you use public key authentication as it is the most flexible. With password authentication, many of these features will be unavailable to you.
Server-side client configuration is accomplished by modifying public key authorization files, typically ~/.ssh/authorized_keys (for both Protocol 1 and Protocol 2). An authorized_keys file will look something like this:
ssh-dss AAAAB3NxaC1kc3M...mc= user@somehost.com
The actual key has been abbreviated, but you can see that each line
in the file begins with the string "ssh-dss", the DSA or RSA public
key, and then the owner's address; usually the username and hostname of
the originating machine. Using this file, we can add some extra
commands to do particular things. For example, let's go back to our
backup user scenario from the previous section. In that case, the user
was able to use rsync
to do the backup. This is done by executing the rsync command on the
server. We can restrict what the backup user can do, as root, on the
remote system quite easily by adding the following before the backup
user's public key in root's authorized_keys file:
command="/usr/bin/rsync" ...key...
Now, if the backup user attempts to connect to the system and execute a login shell or any other program, they will execute the /usr/bin/rsync program every time. However, keep in mind that you can only assign one forced command per key, so if you wanted the backup user to be able to do something else, you would have to either use multiple keys or write a frontend shell script that would be the forced command.
In the case of using rsync over ssh, this obviously will not work because only the command in it's entirety is permitted. Using "/usr/bin/rsync --help" will not be allowed because it is not part of the command; the command is the entire command. So in our case, we would write a wrapper script. This is a very quick example and could probably be improved upon, but it illustrates what is required. Create the script /root/remote-rsync and use in the authorized_keys file:
command="/root/remote-rsync" ...key...
The contents of /root/remote-rsync would be something similar to this:
#!/bin/sh log="/root/rsync.log" command="$SSH_ORIGINAL_COMMAND" denystring="No access. Sorry." send="0" server="0" deny="0" date=`date +"%F %H:%M:%S"` echo "$date Connection from $SSH_CLIENT; command: $command" >>$log if echo $command|grep -e "^rsync " >/dev/null 2>&1; then for arg in $command; do if [ "$arg" == "--sender" ]; then send="1" fi if [ "$arg" == "--server" ]; then server="1" fi done else deny="1" fi if [ "$send" != "1" ]; then deny="1" fi if [ "$server" != "1" ]; then deny="1" fi if [ "$deny" == "0" ]; then $command fi
What this does is test to make sure that the command being issued by the remote client begins with "rsync " and contain the strings "---server" and "--sender". All of this must be checked to ensure that the connection is a one-way "download" connection. We do not want the connection able to upload files to the system as it would allow the connection to overwrite or place any file anywhere on the system. If it does not, the script simply does nothing. You can have it echo something like "No access" if you like, but then you would have to make some changes to the above script (for some reason, if I try to echo something rsync thinks I've got a dirty shell and since the script works fine other than that, I elected just to not provide any information at all).
Because rsync over ssh passes commands like this:
rsync --server --sender -vlogDtpr --delete --partial . /etc
You can't possibly trap every call to rsync
. However,
you can make sure that "rsync[space]" is the first thing on the command
line; this will reject "/usr/bin/rsync", and other variants. As long
as the remote system is clean and there is no trojaned rsync in the
path, you should be ok. In the case of rsync, make sure you pipe the
output of grep
to /dev/null otherwise the calling rsync
will think there is a problem and not do the actual transfer. The main
thing is to make sure that "--sender" and "--server" are checked for to
ensure nothing is being written on the system. You could likewise take
the script further to ensure that only certain paths are being copied
and reject paths that don't match.
Finally, the script logs every command to /root/rsync.log with the command requested and the client's IP address so you can keep an eye on what that key is doing. It would be a good idea to perhaps use a unique script for every key that you give access to (although for a root account one would hope that you use as few as possible), this way you can track the commands issued from each particular key; this may help track down compromised systems if you do notice anything funny.
This also illustrates the environment variable, $SSH_ORIGINAL_COMMAND
.
This environment variable contains the command line that the client is
requesting the server execute as the user connected. You can use this
to create a log of all activity on a specific key by echoing the
contents of the variable to a log file, then calling the variable
directly, as illustrated in our remote-rsync script.
This is a very good way of permitting restricted access to an account and, in the case of our backup example, should be utilized as it will minimize the impact in case the backup account is compromised. While being able to use rsync will allow an attacker to gain copies of sensitive files, they won't actually be able to do anything as the root user, by way of the compromised backup account. However, keep in mind that many programs allow escaping to a shell and these programs should be avoided. For instance, most text editors and commandline mail clients, among many others, allow a user to escape to the shell. If you use one of these commands or programs as the forced command, the end user can easily "break out" of the forced command.
Another command you can use is the "from" command, which allows you to be even more cautious with authentication. In this case, you can specify the key that is able to access an account, but you can also specify the originating host. This means that the connection would have to be established from a particular host, regardless of the key. If the key matches, but the originating host does not, the connection is refused. To use this, place in your authorized_keys file:
from="client.mydomain.com" ...key...
You can use the FQDN, IP address, and wildcards. So instead of limiting it to one host, you could limit it to one domain by using "*.mydomain.com" instead. Also, you can specify multiple hostnames, IPs, and expressions by separating them with commas; you can also use the "!" character to negate an expression. For example:
from="*.mydomain.com,!xclient.mydomain.com" ...key...
Will allow access to this account using the specified key by any machine in the mydomain.com domain except for the machine xclient.mydomain.com. Also keep in mind that server-wide configuration settings override these; if the system is configured to keep all mydomain.com systems from connecting, then even using the above command will not let them in.
You can also set environment variables in the same way by using:
environment="EDITOR=joe" ...key...
In the above example, anyone connecting to the account with the specified key will have their $EDITOR environment variable set to "joe". You can set any environment variable you like this way, or even multiple environment variables by using:
environment="EDITOR=joe",environment="MYVAR=somevalue" ...key...
Another option is to set the idle timeout per key, like this:
idle-timeout=60s ...key...
In this case, the idle timeout is set to 60s for all connections to this account using the specified key.
Finally, you can also disable port forwarding, agent forwarding, and tty allocation on a key-by-key basis. The keywords to use are "no-port-forwarding", "no-agent-forwarding", and "no-pty" respectively.
As a final note, you can "stack" commands also. For instance:
no-agent-forwarding,environment="MYVAR=somevalue",command="/usr/bin/env|/bin/grep MYVAR" ...key...
would result in the following on a connection:
[user@localhost user]$ ssh someuser@somehost /bin/ls MYVAR=somevalue [user@localhost user]$ ssh someuser@somehost MYVAR=somevalue Connection to somehost closed. [user@localhost user]$
As you can see here, the first thing attempted was to gain a listing of someuser's home directory. Instead our grep
command's output was displayed. Likewise, on the second attempt, which was to gain shell access, the grep
command's output was displayed and the connection was closed. This
simply illustrates that command "stacking" is in effect: the
environment variable $MYVAR
was created initially and our call to the env
program displayed it, while grep
singled it out from the rest.
It should be quite obvious now that there are many ways that
Finally, configuring the
Port 22 Protocol 2,1 HostKey /etc/ssh/ssh_host_key HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key KeyRegenerationInterval 3600 ServerKeyBits 768 SyslogFacility AUTH LogLevel INFO LoginGraceTime 600 PermitRootLogin no StrictModes yes RSAAuthentication yes PubkeyAuthentication yes RhostsAuthentication no IgnoreRhosts yes RhostsRSAAuthentication no HostbasedAuthentication no PasswordAuthentication yes PermitEmptyPasswords no ChallengeResponseAuthentication no PAMAuthenticationViaKbdInt no X11Forwarding yes X11DisplayOffset 10 PrintMotd yes KeepAlive yes UsePrivilegeSeparation yes Compression yes Subsystem sftp /usr/lib/ssh/sftp-server
This basically tells the SSH server to listen on port 22 and use Protocol 2 and then fallback to Protocol 1 if the client doesn't support Protocol 2. For a higher level of security, this could be modified to be just "Protocol 2" and eliminate Protocol 1 altogether.
Next it defines three host keys: The first is the SSH1 (RSA)
host key, following are the SSH2 (RSA) and SSH2 (DSA) host keys. A
number of other options are specified here that are at their defaults;
the sshd_config(5)
manpage covers each of these options in depth. We will take a look at a
few specific keywords here that may be of use if you are interested in
tightening up your SSH security.
The sudo
or su
to
change to root from an unprivileged user. However, due to the way SSH
is designed, allowing root to login via SSH isn't that much of a
security threat, provided you use a strong password or disable password
authentication. If you do not wish to disable password authentication
site-wide, you can use:
PermitRootLogin without-password
This will refuse all attempts for password authentication on the root account, which is much more secure than allowing password authentication. If you must have password authentication enabled, you should protect root's account in this manner. Likewise, you could also use "forced-commands-only" which would only allow access to the root account by an authorized public key, but only if the command option is specified for the key. In this manner, password authentication is likewise disabled; either way, one needs their public key in root's authorized_keys file.
The
The
The
There are some other good keywords worth mentioning that aren't
in the default Mandrake Linux configuration. The first of these is the
AllowUsers joe AllowUsers jim@remotehost.com
This will allow the local users joe and jim to log in, but access to jim is only granted to those connecting from the host "remotehost.com". In other words, if a user is trying to log in as jim, but is connecting from otherdomain.com, they will not be permitted to log in. You can also use wildcards here to specify a domain, such as "jim@*.remotehost.com". The wildcards that can be used are "?" which matches any single character except the "@" character, and "*" which matches any sequence of characters, also except for "@".
Likewise, you can use the
You can also allow access based on groups with the
AllowGroups sshusers DenyGroups users
In this example, users belonging to the group "sshusers" are able to login on the system, but users belonging to the group "users" are not. On many Linux distributions, it is standard for each user to belong to their own group as a primary group (ie. user joe will belong to group joe). You can add users to supplementary groups, such as users or, in this case, sshusers. Remember restrictions; they are the same here as they are for the user-based keywords. Here, if a user belongs to both the users group and the sshusers group, they will not have access to login.
Finally, if you want to use host-based access control, you can do so using the
It should be painfully obvious that
One final note: Any time you make changes to your sshd_config
file, make you sure you restart sshd with a "service sshd restart" as
root (for initscript controlling Linux distributions). For other
platforms, restart sshd
accordingly or send a HUP signal to the daemon. Changes to user configuration files, such as ~/.ssh/authorized_keys and ~/.ssh/config require no restart of the sshd
daemon.
-- VincentDanen - 07 Jul 2003
Topic OpenSSH . { Edit | Attach | Ref-By | Printable | Diffs | r1.5 | > | r1.4 | > | r1.3 | More } |
Revision r1.5 - 07 Jul 2003 - 01:41 GMT - VincentDanen Parents: WebHome > SystemHardening |
Copyright © 2003 by the contributing authors.
All material on this collaboration platform is the property of the contributing authors. Ideas, requests, problems regarding linsec TWiki? Send feedback. |