SSH - the Secure SHell

mail

SSH keys types

Key type Length [bits] Comment
min. default max.
DSA exactly 1024 Deprecated since OpenSSH 7.0, should not be used anymore (source, details)
ECDSA ssh-keygen -b determines the key length by selecting from one of three elliptic curve sizes: 256, 384 or 521 bits. All other values will fail.
  • Is ECDSA obsolete/deprecated?
  • key strength depends on the actual randomness of the number generator
  • The 521 bits elliptic curve size is not a typo, it's _really_ 521 (not 512 as I thought , details)
Ed25519 keys have a fixed length and ssh-keygen -b flag will be ignored
  • probably the strongest mathematically (and also the fastest), but not yet widely supported
  • stronger encryption (password-protection) of the private key by default than other key types
RSA 1024 2048
  • Generally, 2048 bits is considered sufficient.
  • The best bet if you can't use Ed25519.

  • If you need more security than RSA-2048 offers, the way to go would be to switch to elliptic curve cryptography — not to continue using RSA. (source)
  • If supported, ECDSA should be used instead of RSA.
  • Virtual machines and machines having a short uptime have not enough entropy to benefit from cryptographically-acceptable randomness and generate strong keys.
mail

How can I assign several names / aliases to an SSH host ?

There are situations —like working with Ansible— where naming hosts is paramount so that everything is organized, readable and explicit. This implies the whole team settles on a naming convention.

Alas, for the vision of one man lends not its wings to another man., the team members sometimes can't agree on such a convention, ending with :

However, nobody has to resign to having to use such poor names.

File Single naming convention Multiple naming conventions
Ansible inventory file
Common to all team members, usually shared via Git.
apache	ansible_host=platformA_apache
mysql	ansible_host=platformA_mysql
apache	ansible_host=xyzABC_123-j_054
mysql	ansible_host=xyzABC_123-j_012
~/.ssh/config
Not shared with the team
Host platformA_*
	User kevin
	ProxyCommand ssh bastion -W %h:%p
	IdentityFile ~/.ssh/myPrivateKey
	AddKeysToAgent yes
	StrictHostKeyChecking no

Host platformA_apache
	HostName 192.168.0.45

Host platformA_mysql
	HostName 192.168.0.46
Host platformA_* xyzABC_123-j_*
	User kevin
	ProxyCommand ssh bastion -W %h:%p
	IdentityFile ~/.ssh/myPrivateKey
	AddKeysToAgent yes
	StrictHostKeyChecking no

Host platformA_apache xyzABC_123-j_054
	HostName 192.168.0.45

Host platformA_mysql xyzABC_123-j_012
	HostName 192.168.0.46
mail

known_hosts

The known_hosts file exists in 2 flavors : Both contain public host keys for all known hosts.

known_hosts format (source) :

  • Entries are space-separated.
  • Lines starting with # and empty lines are considered as comments and ignored
Fields :
  1. markers : one of @cert-authority or @revoked
  2. hostnames :
    • comma-separated list of patterns, including wildcards ? or *, negation !, or stuff like : [hostname]:nonStandardPortNumber
    • lines starting with a | : 1 hashed host name only, no wildcards
  3. keyType : taken directly from the host key
  4. base64-encoded key : taken directly from the host key
  5. comment : for humans only, field ignored
mail

How to open an SSH connection through an HTTP Proxy with authentication ?

SSH is not able to use a proxy in order to access external computers.

To do so, you'll need an extra application to tunnel TCP connections through an HTTP Proxy supporting the CONNECT method : here comes corkscrew.

  1. setup :
    apt install corkscrew
  2. configure corkscrew :
    echo 'proxyUser:proxyPassword' > ~/.corkscrew
    Looks like corkscrew prefers when passwords (including special characters) are not urlencoded.
  3. for privacy of your credentials :
    chmod 600 ~/.corkscrew
  4. configure SSH client by adding to ~/.ssh/config :
    Host sshServer
    	HostName 12.34.56.78
    	User stuart
    	IdentityFile ~/.ssh/myPrivateKey
    	ProxyCommand corkscrew proxy.myCompany.tld proxyPort %h %p ~/.corkscrew
  5. connect to sshServer :
    ssh sshServer

Alternate solution :

  • not tested (yet!)
  • works when otherProxy.mycompany.tld asks no authentication
Host sshServer
	HostName 12.34.56.78
	User stuart
	IdentityFile ~/.ssh/myPrivateKey
	ProxyCommand connect-proxy -H http://otherProxy.mycompany.tld:proxyPort %h %p
	ServerAliveInterval 120	
See : source, man page
mail

How to avoid recording the host key into the known hosts list (~/.ssh/known_hosts) ?

Situation :

When connecting to a new host, SSH adds its host key to its local known hosts list : ~/.ssh/known_hosts. The next time a connection is being open towards this host, SSH will compare its known key with the key advertised by the host it's currently connecting to :

Details :

The behavior described above is normal and expected : a host key is not supposed to change.
However, when experimenting with containers or virtual machines, it's pretty usual to build + use + destroy + re-build "hosts", and in such circumstances, SSH will send repeated warnings about hosts that have changed —which we are aware of and is not a security issue in this context.

Solution :

Add this to ~/.ssh/config :
Host 172.17.*
	StrictHostKeyChecking no
	UserKnownHostsFile /dev/null
	LogLevel QUIET
mail

How can an SSH connection succeed / fail intermittently with no error message despite verbose mode ?

Situation :

Details :

Looks like you've done nothing wrong. The problem must be :

Solution :

There are chances you actually shot your own foot with hardened security rules like this .
mail

How to mount / umount a SFTP directory ?

  • SFTP != FTPS
  • SFTP is what you do while using scp (and also WinSCP or FileZilla — in their respective SFTP modes (i.e. SSH-based file transfer), since they support other protocols as well).

For a quick / one-time use, consider using the SFTP client built in many file managers (Caja has one) by opening :
sftp://sshServer/path/to/remote/directory

mount, umount and CLI access :

Setup :

on sshServer :
provided sshd is up and running, there's nothing more to do
on sshClient :
apt install sshfs

mount :

  • As a non-root user
  • Should you need to map UID/GID between sshServer and sshClient, have a look at -o idmap=TYPE
interactively or with SSH keys
sshfs stuart@sshServer:/path/to/remote/directory /mount/point
password-based authentication (this solution is _a little_ dirty )
echo password | sshfs -o password_stdin stuart@sshServer:/path/to/remote/directory /mount/point

umount :

As a non-root user :
fusermount -u /mount/point

Save keystrokes with an extra /etc/fstab entry :

stuart@sshServer:/path/to/remote/directory /mount/point	fuse.sshfs	noauto,user,default_permissions,uid=1000,gid=1000,noatime	0	0
  • You'll be able to mount the remote filesystem as usual :
    mount /mount/point
  • But umount requires sudo privileges :
    umount /mount/point
    umount: /mount/point: Permission denied
    This is because sshfs uses FUSE instead of the regular mount command (+ elevated privileges). As a result, you'll have to use the FUSE "umount command" (source) :
    fusermount -u /mount/point
When experimenting mount options, you may end up receiving errors such as :
read: Connection reset by peer
In such situation, add the debug and sshfs_debug options to increase verbosity (source).

Alternate solution : use this _VERY BASIC_ script :

#!/usr/bin/env bash

sshServer='mySshServer'	# full details in ~/.ssh/config
sshRemoteDir='/path/to/remote/directory'
mountPoint='/mount/point'

case "$1" in
	m)
		mount | grep -q "$mountPoint" && { echo 'Already mounted'; exit 1; } || sshfs -o idmap=user "$sshServer":"$sshRemoteDir" "$mountPoint"
		;;
	u)
		mount | grep -q "$mountPoint" || { echo 'Not mounted'; exit 1; } && fusermount -u "$mountPoint"
		;;
	*)
		echo 'wut?'
		exit 1
		;;
esac

Improve network throughput :

Your may experience poor transfer speed with sshfs, and search engines will surely take you to pages suggesting to use the arcfour cipher type. However, arcfour is now considered unsafe and is disabled by default since OpenSSH 6.7 (2014-10-06) and not supported anymore since OpenSSH 7.6 (2017-10-03).
command-line line 0: Bad SSH2 cipher spec 'arcfour'.
	==> has been disabled by default in recent versions of SSH.
man -P 'less -p encryption' ssh_config
https://wiki.csnu.org/index.php/SSH_ciphers_speed_comparison

man -P 'less -p ciphers' ssh_config
mail

How to automate password-based SSH logins ?

Situation :

Details :

For reasons unrelated to the current article, I also have inter-operability constraints between GNU/Linux and Windows, and when saying KeePass, I mean : which both can handle .kbdx files.

Solution :

The idea is to :

  1. chain SSH logins from a single command-line (source) :
    ssh -At hopLogin@hop ssh -A targetLogin@target
  2. store hosts + credentials in KeePass, avoiding repeating stuff thanks to field references
  3. let KeePass build and auto-type the full SSH connection command, based on a template like :

    ssh -At {REF:U@I:C03D4B434F400B4C843F682A994B0A02}@{REF:A@I:C03D4B434F400B4C843F682A994B0A02}{ENTER}{DELAY 100}{REF:P@I:C03D4B434F400B4C843F682A994B0A02}{ENTER}ssh -At {USERNAME}@{URL}{ENTER}{DELAY 100}{PASSWORD}

    {whatever} placeholders will be replaced by the value of the named variable or key or action :
    • USERNAME : username of the current entry
    • REF:U@I:C03D4B434F400B4C843F682A994B0A02 : reference to the value of another entry (details)
    • ENTER :
    • ...

Let KeePass auto-type the SSH connection command :

  1. open the KeePass vault and select the entry you'd like to auto-type
  2. give the focus to the window that will receive the simulated keystrokes
  3. give the focus back to KeePass and hit Ctrl-v to fire Perform Auto-Type
  4. if this fails complaining The 'xdotool' utility/package is required for auto-type.
  5. see the magic happen
  • During setup / tests, you may send simulated keystrokes to a text editor to see the generated SSH connection command and debug the auto-type template. Keep in mind your passwords will be echo'ed to screen.
  • Don't forget to connect manually to each SSH server (gateways + targets), since you'll be prompted to accept the SSH host keys.
don't mix sshpass and "auto-type" !
You may have landed here after having automated (or tried to) password-based SSH logins with sshpass. Your process may have lines such as :
sshpass -p 'password' ssh kevin@sshServer
If you plan to use any kind of "auto-type" feature, do NOT use it to generate SSH connection commands including sshpass, otherwise you will : Actually, you don't even need sshpass anymore since the "auto-type" feature will "type" the password for you (for interactive logins only, I'm afraid ). As for KeePass, you'll end with auto-type sequences like :
ssh {USERNAME}@{URL}{ENTER}{DELAY 200}{PASSWORD}{ENTER}

The 'xdotool' utility/package is required for auto-type.

apt install xdotool
mail

ssh-agent

Setup :

apt install openssh-client

Starting ssh-agent :

  • Was it automatically started at login :
    ps aux | grep [s]sh-agent
    bob      982  0.0  0.0  11088   328 ?        Ss   Oct08   0:00 /usr/bin/ssh-agent startxfce4
  • env | grep SSH_
    	SSH_AUTH_SOCK=/tmp/ssh-Nmp81HTtfifX/agent.3012
    	SSH_AGENT_PID=3082
    
    check the agent is running :
    	echo $SSH_AUTH_SOCK
    	/!\ not '$SSH_AGENT_SOCK' as said in the doc

Manage private keys :

  • add a private key :
    ssh-add ~/.ssh/myPrivateKey
  • list known keys :
    ssh-add -l
    2048 SHA256:cMdVUp8pTJGbLYS6Ngrl5odnFYGhoBXGY1p8pTJGbLTk+drlkgE /home/kevin/.ssh/myPrivateKey (RSA)
  • delete all keys :
    ssh-add -D
Looks like under some conditions, ssh-agent forgets keys after a reboot (don't know whether this is context-specific or the default behavior. Details). Anyway, to permanently add keys to the agent, no need for
ssh-add myKey
in ~/.bashrc. Instead, use AddKeysToAgent.
run the agent manually (should not be necessary) :
	eval `ssh-agent`

kill the agent :
	ssh-agent -k
mail

How to revoke a host key from SSH's ~/.ssh/known_hosts file ?

ssh-keygen -R 10.201.95.197
# Host 10.201.95.197 found: line 124
/home/kevin/.ssh/known_hosts updated.
Original contents retained as /home/kevin/.ssh/known_hosts.old
mail

How to hide the connection banner ?

Situation :

Displaying a connection banner is fine when manually opening a connection to a server, but it's getting ugly / awkward when :

Solution :

From light to heavy weaponry :
Use SSH client's quiet mode :
ssh -q host command
Decrease verbosity :
ssh -o LogLevel=QUIET host command
Explicitly filter the unwanted banner :
ssh -q host command 2>&1 | sed -r '/banner/d'
This banner shouldn't be there, actually :
  • When you run ssh user@computer command, command is run non-interactively (source)
  • and there's no point in printing a connection banner to non-interactive shells (source)
  • so this should NOT receive a banner ()
mail

How to hop through a SSH host ?

Situation :

Considering : it is possible to open an SSH session from workstation directly to sshTarget. To do so :

Solution :

  1. On workstation, add to ~/.ssh/config :
    Host sshTarget
    	User stuart
    	ProxyCommand ssh %r@sshHop -W %h:%p
  2. then, from workstation : ssh sshTarget
The Host directive accepts wildcards to fit various scenarios :
Host *.preprod.acmecorp.com
	

Host *.prod.acmecorp.com
	
mail

SSH client configuration

Configuration files :

/etc/ssh/ssh_config
system-wide settings
~/.ssh/config
personal user configuration
~/.ssh/known_hosts
local cache of host (i.e. server) keys
~/.ssh/authorized_keys
list of public keys that will be accepted for key-based logins
Usage of ~/.ssh/authorized_keys2 for SSH protocol 2 is deprecated since 2001 (sources : 1, 2).

Configuration directives :

Flag Usage
BindInterface Use the address of the specified interface on the local machine as the source address of the connection
This feature was introduced by OpenSSH 7.7. As of June 2019, it must be installed —on Debian Stretch— via the testing repository (details, sources : 1, 2).
Include someFile
  • include the specified configuration file(s)
  • multiple pathnames may be specified and each pathname may contain wildcards (such as ~)
  • files without absolute paths are assumed to be in :
    • ~/.ssh if included in a user configuration file
    • /etc/ssh if included from the system configuration file
    For this reason, Included configuration files related to SSHFS mounts declared in /etc/fstab should have an absolute path.
  • Include may appear inside a Match or Host block to perform conditional inclusion
LogLevel LEVEL (explicit)
ProxyCommand Specifies the command to use to connect to the server, typically when there is an intermediate hop between the SSH client and server (examples : 1, 2, 3)
man -P 'less -p "^ +ProxyCommand$"' 5 ssh_config
man -P 'less -p ^TOKENS' 5 ssh_config
ProxyJump Specify one or more jump proxies :
  • syntax :
  • ProxyJump is intended as an equivalent (replacement?) for ProxyCommand, with a simpler syntax (details and examples).
  • Multiple proxies may be separated by comma characters and will be visited sequentially.
  • SSH will connect to the target host by first making a ssh connection to the specified jump host and then establishing a TCP forwarding to the ultimate target from there.
  • ProxyJump competes with ProxyCommand : whichever is specified 1st wins.
  • configuration for the destination host (either supplied via the command-line or the configuration file) is not generally applied to jump hosts. ~/.ssh/config should be used if specific configuration is required for jump hosts.
  • ProxyJump came with OpenSSH 7.3 (2016-08-01). It is absolutely stunning that so many hosts are not up-to-date and still lack this feature today .
OpenSSH/Cookbook/Proxies and Jump Hosts
ServerAliveInterval n send keepalive messages every n seconds when the connection is idle (details). Defaults to 0 (i.e. disabled).
StrictHostKeyChecking
  • yes :
    • never automatically add host keys to ~/.ssh/known_hosts
    • refuse to connect to hosts whose host key has changed
    • provide maximum protection against man-in-the-middle (MITM) attacks, though it can be annoying when /etc/ssh/ssh_known_hosts is poorly maintained or when connections to new hosts are frequently made. This option forces the user to manually add all new hosts.
  • accept-new :
    • automatically add new host keys to ~/.ssh/known_hosts
    • refuse to connect to hosts whose host key has changed
  • no or off :
    • automatically add new host keys to ~/.ssh/known_hosts
    • allow connections to hosts whose host key has changed (some restrictions, though)
  • ask (default) :
    • prompt the user before adding new host keys to ~/.ssh/known_hosts
    • refuse to connect to hosts whose host key has changed

Example :

A mashup of useful options :

Host HAL		this can be an alias, an IP address, a negated expression or a pattern (trick about patterns lists)

	HostName realHostname		if you specified an alias above
	Port 443				Port to connect to on the remote host. Defaults to 22
	User DrEinsteinVonBrainstorm
	IdentityFile ~/.ssh/myPrivateKey

	ProxyCommand ssh -e none hop exec nc -w 5 %h %p		Go through hop host. If hop is an HTTP proxy, read this.

	AddKeysToAgent yes			details
	ForwardAgent yes
Patterns lists are comma-separated (,), but when they apply to the Host directive, they are whitespace-separated.

My basic default configuration :

Host *				this is a valid statement (details : 1, 2)
	ServerAliveInterval 120	Keep SSH sessions alive
	LogLevel QUIET		hide the connection banner
If SSH ignores your ~/.ssh/config file, be more explicit with -F.
mail

SSH : how to authentify using a public/private key pair ?

Generate keys :

On Linux :

  • generates a private (keyName) + public (keyName.pub) key pair at the OpenSSH format. If not specified, keyName defaults to ~/.ssh/id_rsa
  • the type of key to generate can be specified with -t type (defaults to rsa for SSH protocol version 2).

generate a 2048-bit RSA key pair (~/.ssh/id_rsa + ~/.ssh/id_rsa.pub)
ssh-keygen -t rsa
generate a 256-bit ECDSA key pair (~/.ssh/id_ecdsa + ~/.ssh/id_ecdsa.pub)
ssh-keygen -t ecdsa -b 256
generate a fixed-length Ed25519 key pair (~/.ssh/id_ed25519 + ~/.ssh/id_ed25519.pub)
ssh-keygen -t ed25519
ssh-keygen -t ed25519 -a 100

On Windows, for PuTTY :

You'll need PuTTYgen and this procedure to generate a private (keyName.ppk) + public (keyName.pub) key pair at the PuTTY format.

The public key is a text file such as :

---- BEGIN SSH2 PUBLIC KEY ----
Comment: "this-is-my-key"
AAAAB3NzaC1yc2EAAAABJQAAAIBH+WrDPd3hTZMmZCIfn0olQYDkU3ay/GzSwsoq
gZe1NzNeUMIt45dYI6SoM2JTog8Qm04pyzb1FkB2N35TpNanY5B8fmtkVc/s4Dmp
7n++56VhU6gcceeuVTZuGwgJ17+CrmoAcBogHgR1Wwb32UJNsVXYs2TIzqlZa4n/
3GB0uw==
---- END SSH2 PUBLIC KEY ----
It contains a header line + a comment + the public key itself + a footer. You can convert it into the OpenSSH format :
  • with the dedicated utility
  • or manually, by editing it so that it looks like on a single line :
    ssh-rsa public key comment (usually the owner ID)

Copy the public key to a SSH server (source)

  1. ssh-copy-id -i ~/.ssh/id_rsa.pub stuart@sshServer
    This should automatically populate the ~/.ssh/authorized_keys file on the SSH server (read about some required chmod's)
  2. Configure PuTTY accordingly.

Installing the key on an SSH server for the impatients :

As these commands use the ~ wildcard, run them as the user owning the ~ directory.

  1. On the SSH server side : mkdir ~/.ssh; touch ~/.ssh/authorized_keys; chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys
  2. On the SSH client side : cat ~/.ssh/id_rsa.pub | ssh kevin@myServer "cat - >> ~/.ssh/authorized_keys"

Log in using the key :

  1. ssh kevin@myServer -i ~/.ssh/id_rsa
  2. which can be aliased :
    echo "alias ssh='ssh -i ~/.ssh/id_rsa'" >> ~/.bashrc && source ~/.bashrc
  3. then :
    ssh kevin@myServer
mail

sshd

sshd supports SSH1 and SSH2 protocols, but SSH1 is not secure, so it mustn't be used !

Existing connections can survive sshd restart (source) :

Configuration files :

File Purpose
/etc/ssh/sshd_config This is the main configuration file (Configuration directives). sshd can't start if this file is unavailable.
/etc/motd welcome message to be displayed after a successful login, either "normal" login or via SSH (or grep Banner /etc/ssh/sshd_config )
~/.ssh/authorized_keys list of public keys. This can also hold some configuration directives.
/etc/nologin If this file exists, sshd refuses to let anyone except root log in.
/etc/hosts.allow
/etc/hosts.deny
ACL that should be enforced by tcp-wrappers are defined here.

Server configuration directives (source) :

Directive Usage
AcceptEnv myEnvironmentVariable Declare environment variables that can be set by the SSH client (aka whitelist . A single AcceptEnv directive can declare several variables, separated by a space character.
AllowUsers SPACE-separated list of user names or user / user@host patterns. Only the matching ones are allowed to log in.
Banner points to a banner file that can be found anywhere. The content of this banner is displayed during an SSH login, between the login name and password input.
ClientAliveCountMax n Allow at most n unanswered requests sent by ClientAliveInterval before disconnecting the client.
The ClientAliveInterval timer is reset after sending every request.
ClientAliveInterval n Start a timer for n seconds before requesting client response over the encrypted channel (this has nothing to do with KeepAlive, which is a TCP setting).
0 disables this function.
GatewayPorts Specifies whether remote hosts are allowed to connect to ports forwarded for the client (details)
ListenAddress Specifies the local addresses sshd should listen on
PermitRootLogin value
  • yes : root can log in using ssh
  • prohibit-password or without-password : password and keyboard-interactive authentication are disabled for root
  • forced-commands-only : root login with public key authentication will be allowed, but only if the command option has been specified (which may be useful for taking remote backups even if root login is normally not allowed). All other authentication methods are disabled for root.
  • no : root is not allowed to log in
UseDNS Specifies whether sshd should look up the remote host name and check that the resolved host name for the remote IP address maps back to the very same IP address. Set this to no to disable server lookups.
X11DisplayOffset n Specifies the first display number available for sshd's X11 forwarding. This prevents sshd from interfering with real X11 servers. Defaults to 10.

Server configuration and security settings (sources : ANSSI, 1, 2)

In the configuration file :
Use SSH protocol version 2 only (version 1 has flaws allowing MitM attacks) :
Protocol 2
Deny root login :
PermitRootLogin no
Disable password authentication :
Disable port forwarding (unless this is explicitly required, by X2Go, for instance ) :
AllowTcpForwarding no
Disable X11 forwarding (which could allow : key logging, sending signals to applications, redirecting display) :
X11Forwarding no
ForwardX11Trusted no
Define ACL (or consider PAM) :
  • whitelist users : AllowUsers kevin stuart bob
  • whitelist users and the client IP address : AllowUsers admin@192.168.17/24
  • whitelist groups / IP addresses : AllowGroups developers wheel@192.168.17/24
  • blacklist users / groups / IPs : DenyUsers root alice foo
  • To explicitly blacklist all the existing local users (except kevin, stuart and bob), you can quickly generate the list with :
    cut -d: -f1 /etc/passwd | grep -Ev 'kevin|stuart|bob' | tr '\n' ' '
Check directories / key files permissions of the user side before opening a session :
StrictModes yes
Automatically logout idle users after n seconds of inactivity :
ClientAliveInterval n
ClientAliveCountMax 0
Ignore ~/.rhosts and ~/.shosts files (if they exist) :
IgnoreRhosts yes
Disable host-based authentication :
HostbasedAuthentication no
Disable empty passwords :
PermitEmptyPasswords no
Login restrictions :
MaxAuthTries 2
LoginGraceTime 30
Some extra directives for ssh_config and sshd_config :
Ciphers aes256-ctr, aes192-ctr, aes128-ctr
# Pour les versions 6.3+, OpenSSH supporte le ETM (encrypt-then-mac),
# plus sûr que les anciennes implémentations (mac-then-encrypt)
MACs hmac-sha2-512-etm@openssh.com, hmac-sha2-256-etm@openssh.com

# S'il s'agit d'une ancienne version, utilisez uniquement "hmac-sha1"
MACs hmac-sha2-512, hmac-sha2-256, hmac-sha1
By default SSH listens to all available interfaces and IP address on the system. You can limit this with :
Port 443
ListenAddress 192.168.1.5
Or :
ListenAddress 192.168.1.5:443
Filter sshd port (defaults to TCP 22) (See NetFilter) :
iptables -I INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 22 -j ACCEPT
Rate-limit incoming connections :
#!/bin/bash
interface=eth1
sshPort=22
iptables -I INPUT -p tcp --dport $sshPort -i $interface -m state --state NEW -m recent --set
iptables -I INPUT -p tcp --dport $sshPort -i $interface -m state --state NEW -m recent --update --seconds 60 --hitcount 5 -j DROP
Or consider fail2ban to block brute force attacks (if you don't mind it eating your CPU...)
Use TCP Wrappers : it's a host-based networking ACL system, used to filter network access to Internet.
Edit /etc/hosts.allow to allow SSH only from 192.168.1.2 and 172.16.23.12 :
sshd : 192.168.1.2 172.16.23.12
Last but not least :
  • analyze logs (logwatch, logcheck)
  • keep software up-to-date (apt upgrade, ...)

About the daemon sshd itself :

Start / Stop / ...

sshd is started at boot time. You can drive it with :
systemctl start|stop|restart|status|... sshd
It forks 1 new daemon for each new connection.

Advanced Features

  • log on a remote host as a specified user : ssh bob@sshServer
  • receive display of remote application :
    1. log in remote host : ssh -X stuart@sshServer
    2. start remote application
  • execute a remote application on its own (remote) display :
    1. log in remote host : ssh kevin@sshServer
    2. mangle its DISPLAY environment variable to use the local display : export DISPLAY=:0.0
    3. then start remote application
  • copy a file ("push" mode) : scp path/to/file sshServer:/remote/destination/directory
  • copy a file ("pull" mode) : scp sshServer:/path/to/file local/destination/directory
  • copy files with scp as a specified user on the remote system : scp /path/to/file steve@sshServer:/remote/destination/directory
  • Preserve file rights and timestamp with scp : use the -p flag : scp -p

Extra configuration directives in ~/.ssh/authorized_keys :

accept the key only for clients coming from the 192.168.15/24 network :
from="192.168.15.*" ssh-ecdsa AAAAE2Vj...
accept the key only for clients coming from ssi.gouv.fr but not public.ssi.gouv.fr
from="!*.public.ssi.gouv.fr, *.ssi.gouv.fr" ssh-ecdsa AAAAE2Vj...
disable the agent forwarding for the specified key
no-agent-forwarding ssh-ecdsa AAAAE2Vj...
mail

SSH tunneling

Tunnel types (source) :

  • local tunnels : forward a local port to a remote host
  • remote tunnels : forward a remote port to a local host. This is similar to a local tunnel, with reversed directions.

Local tunnels

SSH tunnel - local

ssh kevin@SSH -L 127.0.0.1:l_port:REMOTE:r_port

  • the local IP 127.0.0.1 is implicit, there's not need to specify it.
  • the remote IP is relative to the SSH host (=as seen by the SSH host)

Remote tunnels

SSH tunnel - remote

ssh kevin@SSH -R SSH:s_port:REMOTE:r_port

Notes

  • Don't forget that the tunnel entry is 127.0.0.1:s_port
  • When setting tunnels, you are prompted for the password of the user stuart on the host SSH. If successful, a shell opens on SSH with stuart's credentials. As long as this shell is active, the tunnel is up. So, to close the tunnel, just "exit".
  • To make sure the tunnel is up :
    netstat -a | grep ssh
    In netstat output, connections listed as TIME_WAIT are waiting for the protocol session end (=timeout).
  • With both tunnel types, sshd only accepts connections from the loopback address, so that only local programs can use the tunnel (better security). To workaround this, edit /etc/ssh/sshd_config and set GatewayPorts to yes. (details)