SSH - the HowTo's

mail

How to run GUI applications remotely through SSH ?

  • Even though the solution below is technically correct, you'll have a poor experience because
    X11 is slow "by design"

    To clarify why X11 over ssh will never be fast: the X protocol deals with low-level drawing like lines and circles, and with low-level events such as "the mouse moved 3 pixels to the left." Modern GUI toolkits like GTK and Qt don't draw lines, they draw images. When X11 goes over SSH, it must constantly send image data and low-level mouse events. A high-level protocol like NX, VNC, or Remote Desktop can reduce bandwidth and latency by being aware of how toolkits work. For example, they can avoid the need to send mouse events, they can avoid thousands of redraws when windows are moved, and they can cache areas of the screen like menus. If performance is even a minor concern, raw X11 is always the wrong choice. Fortunately, there are a multitude of fast alternatives that are easy to configure and use.
    (source)

  • few things can be done to speed up X11 over SSH, and it's likely it won't run smooth anyway
  • an alternate solution might be X2Go

Definitions

  • sshServer :
    • a machine which is far (far!) away
    • this is where a GUI application will be executed
  • sshClient :
    • the workstation you're facing right now, with your screen + keyboard + mouse
    • this will display the application running on sshServer

Procedure

  1. setup SSH both on sshServer and sshClient so that you can login in CLI mode
    Whether you use a password / key / anything else makes no difference here, as long as sshServer's sshd lets you in.
  2. on sshServer :
    1. enable X11Forwarding in /etc/ssh/sshd_config :
      
      X11Forwarding yes
      
    2. make sure xauth is installed
  3. on sshClient :
    1. open the session with :
      ssh -X sshServer
    2. To confirm SSH is forwarding X11, you may start the session with :
      ssh -X -v
      and check for a line such as :
      Requesting X11 forwarding
    3. You don't have to alter $DISPLAY nor $HOME/.Xauthority on sshServer once logged : this is managed by xauth
    4. you can now start any GUI application from the CLI

How to speed up X11 over SSH ?

Many answers found on the Internet are now obsolete :
  • SSH has no CompressionLevel option anymore
  • the suggested "faster" ciphers are not available anymore
The only option that works is enabling compression :
mail

How to check whether a given host is known to SSH (i.e. has its host key in ~/.ssh/known_hosts) ?

When ~/.ssh/known_hosts is clear text

It's straightforward : just search your host's hostname or IP.add.re.ss in ~/.ssh/known_hosts with your favorite text editor / grep /

When ~/.ssh/known_hosts is hashed

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

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 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

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 : how to authentify using a public/private key pair ?

Generate keys (details on SSH keys types) :

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 fixed-length Ed25519 key pair (~/.ssh/id_ed25519 + ~/.ssh/id_ed25519.pub)
ssh-keygen -t ed25519
generate a 2048-bit RSA key pair (~/.ssh/id_rsa + ~/.ssh/id_rsa.pub)
ssh-keygen -t rsa

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

  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 -p ~/.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 with 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