Secure OpenSSH Config Reference





Home


OpenSSH is a set of utilities to allow you to connect to a remote machine through an encrypted tunnel. You can use it as a terminal connection or to tunnel any data through a VPN interface.

OpenSSH is a FREE version of the SSH suite of network connectivity tools that increasing numbers of people on the Internet are coming to rely on. Many users of telnet, rlogin, ftp, and other such programs might not realize that their password is transmitted across the Internet unencrypted, but it is. OpenSSH encrypts all traffic (including passwords) to effectively eliminate eavesdropping, connection hijacking, and other network-level attacks.OpenSSH FAQ

Most operating systems come with one version or another of OpenSSH. You may want to make sure you have the latest version on your machine. Check the OpenSSH site for the latest source code. You can also look to the package maintainers of your OS revision to see if they make a premade package for you to install.

NOTE: The directives and options listing in the following config files apply to the latest official OpenSSH release from OpenSSH.org .



Client side ssh config options (/etc/ssh/ssh_config)

This config is for the client side options. You can specify directives here and the client will negotiate them with the server. Only if the server allows them will they will take effect.

#######################################################
###  Calomel.org  CLIENT  /etc/ssh/ssh_config
#######################################################
Host *
 AddressFamily inet
 CheckHostIP yes
 Ciphers aes128-ctr,aes256-ctr,arcfour256,arcfour,aes128-cbc,aes256-cbc
 Compression no
 ConnectionAttempts 1
 ConnectTimeout 10
 ControlMaster auto
 ControlPath ~/.ssh/master-%r@%h:%p
 EscapeChar ~
 ForwardAgent no
 ForwardX11 no
 ForwardX11Trusted no
 HashKnownHosts yes
 IdentityFile ~/.ssh/identity
 IdentityFile ~/.ssh/id_rsa
 IdentityFile ~/.ssh/id_dsa
 IdentitiesOnly yes
 MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
 PermitLocalCommand no
 Port 22
 Protocol 2
 RekeyLimit 1G
 ServerAliveInterval 15
 ServerAliveCountMax 3
 StrictHostKeyChecking ask
 TCPKeepAlive no
 Tunnel no
 TunnelDevice any:any
 VisualHostKey no
#######################################################
###  Calomel.org  CLIENT  /etc/ssh/ssh_config
#######################################################





Need help setting up a chrooted sftp server? Check out our Chroot'd SFTP server "how to".





Server side sshd config options (/etc/ssh/sshd_config)

These directives are for sshd. Permissions should be "chmod 755". We want to restrict access with the following options to better protect the server.

#######################################################
###  Calomel.org  SERVER  /etc/ssh/sshd_config
#######################################################
#
Port 22
Protocol 2
AddressFamily inet
#ListenAddress 127.0.0.1

#See the questions section for setting up the gatekeeper
#ForceCommand /tools/ssh_gatekeeper.sh 

AllowUsers calomel@10.10.10.3 calomel@192.168.*
AllowGroups calomel

AllowTcpForwarding yes
AuthorizedKeysFile .ssh/authorized_keys
Banner /etc/banner
ChallengeResponseAuthentication no
Ciphers aes128-ctr,aes256-ctr,arcfour256,arcfour,aes128-cbc,aes256-cbc
ClientAliveInterval 15
ClientAliveCountMax 3
Compression no
GatewayPorts no
LogLevel VERBOSE
LoginGraceTime 50s
MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
MaxAuthTries 6
MaxStartups 10
PasswordAuthentication yes
PermitEmptyPasswords no
#PermitOpen localhost:80
PermitRootLogin no
PermitUserEnvironment no
PidFile /var/run/sshd.pid
PrintLastLog yes
PrintMotd no
PubkeyAuthentication yes
StrictModes yes
Subsystem sftp /usr/libexec/sftp-server
SyslogFacility AUTH
TCPKeepAlive no
UseDNS no
UseLogin no
UsePrivilegeSeparation yes
X11DisplayOffset 10
X11Forwarding no
X11UseLocalhost yes

#Match User anoncvs
#       X11Forwarding no
#       AllowTcpForwarding no
#       ForceCommand cvs server
#
#######################################################
###  Calomel.org  SERVER  /etc/ssh/sshd_config
#######################################################



For more information about OpenBSD's Pf firewall and HFSC quality of service options check out our PF Config (pf.conf) and PF quality of service HFSC "how to's".





Questions? Need a script?



How can we setup OpenSSH to do multi-factor authentication using the Ssh_Gatekeeper script?

In many high security (top secret) or ultra paranoid environments multi factor authentication is required. In order to log into a machine you need to provide many proofs of your identity. An authentication factor is a piece of information and process used to authenticate or verify the identity of a person requesting access under security constraints. For example, two-factor authentication (TFA) is a system wherein two different factors are used in conjunction to authenticate. Using more than one factor (single factor or SFA) is sometimes called strong authentication. However, strength is always bound to secrecy under which the factors are kept and protected against any third party challenge. In order to increase security one can increase the amount of independent authentication methods used.

Multi factor authentication (MFA) is comprised of three(3) or more of the following:

OpenSSH can help you better secure remote access by adding another authentication layer to the system by using the ForceCommand directive and the ssh_gatekeeper script. By definition true multi-factor authentication requires the use of solutions from two or more of the three categories of factors. Using multiple solutions from the same category would not constitute multi-factor authentication

To practice good security using multi-factor (very strong) authentication through OpenSSH you should at least:

How does the ssh_gatekeeper script work? How does it help me?

The Gatekeeper script will require the user to enter the correct answer before being allowed a shell and access to the system. This adds another layer of authentication as the string can be constantly changing. If someone steals your ssh key, especially if it is pass phrase-less, or gets a hold of your password they will still need to deduce what the gatekeeper expects as an answer. Lets take a look.

The script will have the client input a string once they have been authenticated through ssh and are just about to be awarded a shell. The user can run any shell they want to including bash, sh, ksh, csh or tcsh. Before the gatekeeper can run the user must provide a valid password for a valid user or connect using a pre-authorized ssh key having supplied a valid or empty pass-phrase. The sshd daemon will run the ssh_gatekeeper.sh script using ForceCommand. The user will not be able to break out of the script and must provide the correct answer to receive shell access according to the $QUERY question. If the script receives anything other than the correct response the connection is closed.

The default question ($QUERY variable) we have setup is a string asking the current minute, day of the month and hour (24-hour format). If the date is "Mon Jan 10 13:25:00 EST 2020" then the answer is "251013". As you can see the answer is only good for 60 seconds per month and only for that exact minute. This is just an example and you can make up any question you want.

You can put anything into the $QUERY variable like a string, an equation or put a logic if-then tree in to make it even more difficult to know. We highly suggest using some logic that changes periodically, but the client can remotely deduce.

How do I setup the "ssh_gatekeeper.sh" script?

First, edit your /etc/ssh/sshd_config and add the following line. The ForceCommand directive will make sshd execute this script when any client tries to log into the machine. The rest is the path and name of the script. Make sure you restart the sshd server so the changes take effect.

ForceCommand /tools/ssh_gatekeeper.sh

Second, copy the following script to a location where all users will be able to execute it. When the ForceCommand directive runs the script it will be run as the user attempting log in. For our example we will place it in /tools/ssh_gatekeeper.sh and set the permissions to "chmod 755" with the owner as root (chown root).

#
## Calomel.org  ssh_gatekeeper.sh
#
## This script is run by the ForceCommand directive in the sshd_config. It expects
## the user SSH'ing to the box to answer the $QUERY question before being allowed
## a shell. Permissions of this script should be owned by root and executable by
## all other users (chmod 755)". Rsync is allowed through, but scp and sftp are
## denied.
#

## Disconnect clients who try to quit the script (Ctrl-c)
trap jail INT
jail()
 {
   kill -9 $PPID
   exit 0
 }

## Allow SSH. Clients can ssh to the box and then answer the $QUERY question.
if [ -z "$SSH_ORIGINAL_COMMAND" ];
  then
    ## This is the question the client needs to know the answer to.
    ## Here we are asking for the current minute, day of the month
    ## and hour (24-hour time). If the date is "Mon Jan 10 13:25:00 EST 2020"
    ## then the answer is "251013"
    QUERY=`date +%M%d%H`

    ### The welcome message. This can be helpful or completely arbitrary
    ### depending on your user. Here we use a random quote as we are
    ### expecting the user to already know the question.
    echo "" 
    echo "    All truths are easy to understand once they are"
    echo "    discovered; the point is to discover them."
    echo "                                   -Galileo Galilei"
    echo ""

    ### The Decision
    ### If the answer is correct give the user their shell.
    ### If the answer is wrong, log the attempt and kill the connection.
    while read -s inputline
      do
       answer="$inputline"
         if [ $QUERY = "${answer}" ];
           then
             $SHELL -l
             exit 0
           else
             logger "ssh_gatekeeper $USER login failed from $SSH_CLIENT"
             kill -9 $PPID
             exit 0
         fi
      done
fi

## Allow RSYNC. Rsync can not be used with the question above.
## We need to let the command though so our shell environment is clean. 
if [ `echo $SSH_ORIGINAL_COMMAND | awk '{print $1}'` = rsync ];
  then
    $SHELL -c "$SSH_ORIGINAL_COMMAND"
    exit 0
fi

## Default deny. This is the last command to catch all other command
## input. If the client tries to use anything other than ssh or rsync
## the connection is dropped. SCP and SFTP are not allowed on our server
## so they are denied as well.
kill -9 $PPID
exit 0




Testing the ssh_gatekeeper.sh script

Now, ssh to the machine as a valid user. You should first have to enter your password or use your ssh key. Then the "welcome message" will print out from the script. If you kept the same $QUERY from the example you will need to enter in the current minute, day of the month and hour (24-hour format). Make sure the time on all of your machines is in sync otherwise you will never figure out the answer. Your input will _not_ be echoed. If the entry is correct you will be given a shell. If the input is wrong the connection will be closed and the attempt will be logged.



How about a Distributed SSH shell script ?

If you have many machines to take care of you can setup ssh keys on each of them from a central ssh key server. This way you can ssh to the key server and then ssh to any other machine with the key without a password. Working with one machine at a time is fine, but what if you need to work on many machines doing the same task over and over again?

This is a simple shell script you can use to connect to many machines and execute the same commands on all of them from your centralized key server.

#!/usr/local/bin/bash
#
## Calomel.org Distributed SSH 
##   sh batch_ssh.sh "machine1 machine2" 'uptime'
##   sh batch_ssh.sh "`cat servers.txt`" 'uptime'
#

## global options
TIMEOUT=3
OUTLOG=/tmp/remote-out-$$.log

## command line options
MACHINES=$1;shift
COMMAND=$1;shift

## distribute commands to machines
for machine in $MACHINES
 do
    echo $machine >>$OUTLOG.$machine
    ssh -q -oStrictHostKeyChecking=no -oBatchMode=yes -oCompression=yes \
      -oConnectTimeout=$TIMEOUT -l root $machine $COMMAND >>$OUTLOG.$machine \
      2>>$OUTLOG.$machine &
 done

# wait for all processes to finish
wait

## print logs and delete tmp files
cat $OUTLOG.*
rm -f $OUTLOG.*



How about a Distributed SCP shell script ?

This is a companion script to the distributed SSH script above. The is for scp'ing a local file on your key server to a list of servers. Just provide three arguments in the form of the list of machines, the name of the local file to distribute and the location on the remote server you want the file to be placed.

#!/usr/local/bin/bash
#
## Calomel.org Distributed SCP 
##   sh batch_scp.sh "machine1 machine2" 'local_file' 'remote_directory'
##   sh batch_scp.sh "`cat servers.txt`" 'myfile.txt' '/root/'
#

## global options
TIMEOUT=3
OUTLOG=/tmp/remote-out-$$.log

## command line options
MACHINES=$1;shift
LOCAL=$1;shift
REMOTE=$1;shift

## distribute commands to machines
for machine in $MACHINES
do
    echo $machine >>$OUTLOG.$machine
    scp -q -oStrictHostKeyChecking=no -oBatchMode=yes -oCompression=yes \
      -oConnectTimeout=$TIMEOUT $LOCAL root@$machine:$REMOTE \
       >>$OUTLOG.$machine 2>>$OUTLOG.$machine &
done

# wait for all processes to finish
wait

## print logs and delete tmp files
cat $OUTLOG.*
rm -f $OUTLOG.*



How can I setup a reverse SSH connection?

A reverse ssh connection will allow you to use an existing ssh connection from work, through their restrictive firewall (port 443 is open), to your machine at home. Then you can initiate a reverse ssh connection from your home machine, back through the established ssh tunnel to your work machine. This is what we are tying to accomplish:

Initial Tunnel: 1.1.1.1:443  --> NAT FIREWALL --> 2.2.2.2:443 [localhost:12345]
                 (work)                             (home) 
Reverse SSH:    localhost:22 <--  SSH TUNNEL  <-- localhost:12345         

Lets say work only allows port 80 (http) and port 443 (https) out through the firewall. Since ssh and https are both encrypted no one should notice ssh traffic going out the https port on the firewall.

First, you need to execute the following on your work machine. It will setup a ssh tunnel to your home machine (sshd at home is listening on port 443) going out port 443 (hidden on the https port). On your home machine, port 12345 on localhost will the the end of the tunnel that starts on your machine at work.

calomel@WORK: ssh -R 12345:localhost:22 usernamer@2.2.2.2

Now, on your home machine you can use the ssh tunnel you just setup to ssh back though to the target machine at work.

calomel@HOME: ssh localhost -p 12345

Anyone with access to the home machine can now access the work machine through the tunnel. To keep the tunnel active you can run "top" on the home machine. Just imagine the security implications and how difficult a reverse tunnel would be to stop if you are the admin of the work machine.



Using OpenSSL to encrypt and decrypt files

Instead of using a special program to encrypt and decrypt files, like password or financial data, you can just use OpenSSL. You can pass any file into OpenSSL and using a password as a key you can encrypt it. The best part is that any OS, be it Linux OpenBSD, NetBSD, MacOSX or even windows and use this method as long as OpenSSL is installed. For example, we have some random file called "calomel". Use the following commands to encrypt and then decrypt this file.

to encrypt (-e):
 openssl aes-256-cbc -a -e -salt -in calomel -out calomel.aes

to decrypt (-d):
 openssl aes-256-cbc -a -d -salt -in calomel.aes -out calomel





Questions, comments, or suggestions? Contact Calomel.org