SSH - Secure Shell

OpenSSH Logo

OpenSSH is the premier connectivity tool for remote login with the SSH protocol. It encrypts all traffic to eliminate eavesdropping, connection hijacking, and other attacks. In addition, OpenSSH provides a large suite of secure tunneling capabilities, several authentication methods, and sophisticated configuration options.

The OpenSSH suite consists of the following tools:

  • Remote operations are done using ssh, scp, and sftp.

  • Key management with ssh-add, ssh-keysign, ssh-keyscan, and ssh-keygen.

  • The service side consists of sshd, sftp-server, and ssh-agent.

OpenSSH is developed by a few developers of the OpenBSD Project and made available under a BSD-style license.

Note

The following is valid for OpenSSH_8.2p1 Ubuntu-4, OpenSSL 1.1.1f 31 March 2020 as shipped with Ubuntu 20.04 LTS “Focal Fossa”. See the OpenSSH release notes for changes since the 7.6 release that came with Ubuntu 18.04.

SSH Server

On Ubuntu Desktop the SSH server is not installed by default:

$ sudo apt install ssh molly-guard

For configuration, see our SSH server configuration.

SSH Client

System-Wide Client Configuration

Note

The following configuration options can also be just kept in your personal user settings in the ~/.ssh/config file. But if you services or scripts running under other users or if this system is used by multiple user profiles, it might be easier to maintain a system-wide configuration.

The system-wide default client settings are stored in /etc/ssh/ssh_config. The options are described in the ssh_config(5) man page.

# ************************************************************************
# System-Wide SSH Client Configuration
# ************************************************************************

Include /etc/ssh/ssh_config.d/*.conf

Host *

    # ----------------------------------------------
    # Ciphers suite selection
    # See https://sshaudit.com hardening guide
    # ----------------------------------------------

    # Ciphers allowed and their order of preference
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

    # Host key algorithms that the client wants to use in order of preference
    HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com

    # KEX (Key Exchange) algorithms allowed
    KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256

    # MAC (message authentication code) algorithms in order of preference.
    MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com

    # Key types that will be used for public key authentication
    PubkeyAcceptedKeyTypes ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com


    # ----------------------------------------------
    # Network Connection
    # ----------------------------------------------

    # Try to share multiple sessions over a single network connection
    #ControlMaster auto
    #ControlPath /run/user/%i/ssh-control-%C.sock

    # Keep the control connection open for 5 minutes
    #ControlPersist 300

    # Seconds to wait for the server to answer alive messages
    #ServerAliveInterval 15

    # Number of missed server alive messages, before disconnecting
    #ServerAliveCountMax 3


    # --------------------------------------------------
    # Server Authentication
    # --------------------------------------------------

    # Verify the remote key using DNS and SSHFP resource records
    # Note: This implies that we can always trust our DNS resolver and providers,
    # wherever we are connecting from!
    VerifyHostKeyDNS yes

    # Keep the known_hosts file unreadable
    HashKnownHosts yes

    # Accept and store new and additional hostkeys sent by the server
    UpdateHostKeys yes

    # Also check and store the servers IP address along the hostnane in the
    # known_hosts file.
    CheckHostIP yes


    # --------------------------------------------------
    # Client and User Authentication
    # --------------------------------------------------

    # Don't attempt GSSAPI authentication
    GSSAPIAuthentication no

    # Don't allow password authentication
    PasswordAuthentication no

    # Order of authentication methods to try with the server
    PreferredAuthentications publickey


    # --------------------------------------------------
    # Allowed Client Features
    # --------------------------------------------------

    # Which variables from the local environ(7) should be sent to the server
    SendEnv LANG LC_*


# -*- mode: ssh_config; indent-tabs-mode: nil; tab-width: 4; -*-

In case you where wondering about the HashKnownHosts options, I suggest reading Joey’s [former] Blog about this

Specific settings for certain domains and networks, like your own, friends or customers might be better placed in their onwn files for easier maintenance and distribution. Tha’s what the “Include” statement and the /etc/ssh/ssh_config.d/ directory are for.

Create a file like /etc/ssh/ssh_config.d/example.net.conf and make changes according your needs:

# ----------------------------------------------------------------------
# System-wide SSH Client Configuration for the .local (mDNS) domain.
# ----------------------------------------------------------------------

Host *.local

    # Don't verify remote host key using DNS and SSHFP resource records for
    # .local domain servers.
    VerifyHostKeyDNS no

    # Don't check and don't store the IP addresses in the known_hosts file for
    # .local domain servers.
    CheckHostIP no


# -*- mode: ssh_config; indent-tabs-mode: nil; tab-width: 4; -*-
# ----------------------------------------------------------------------
# System-wide SSH Client Configuration for example.net.
# ----------------------------------------------------------------------


# --------------------------------------------------
# Our servers custom SSH ports
# --------------------------------------------------

# Cloud server at Hetzner, San Francisco
Host dolores.example.net
    Port 60403

# VPS host at Rackspace, London
Host maeve.example.net
    Port 1488

# Home router remote access
Host arnold.home.example.net
    Port 38984

# Office router remote access
Host teddy.office.example.net
    Port 27464


# Synology NAS servers allow only admin and root users to the SSH
# terminal service. All other users are restricted to SFTP.
# The SSH terminal service and the SFTP-server might listen to different TCP
# ports.

# SSH terminal service (root and admin connect here):
Match Host logan.example.net User admin,root
    Port 56670

# SFTP service (all others connect here):
Match Host logan.example.net User *
    Port 22706

Host *.example.net

    # Never automatically add or update host keys to the known_hosts file
    # (Except when learned trough SSFP and verified by DNSSEC)
    StrictHostKeyChecking Yes

# -*- mode: ssh_config; indent-tabs-mode: nil; tab-width: 4; -*-

User Configuration

The client settings for users are stored in /etc/ssh/ssh_config. The options are the same as described in the ssh_config(5) man page

In the file ~/.ssh/config you can customize your client (like specific user names) or add 3rd-party systems which are not covered by system-wide settings:

# ************************************************************************
# SSH Client Configuration for John Doe
# ************************************************************************

Include config.d/*.conf


# -*- mode: ssh_config; indent-tabs-mode: nil; tab-width: 4; -*-

Again we create several include files for different networks.

In the file ~/.ssh/config.d/local.conf we set options for discoverable hosts in our LAN:

# ----------------------------------------------------------------------
# SSH Client Configuration for the .local (mDNS) domain.
# ----------------------------------------------------------------------

# Fully tusted systems on the local network, which we can afford to enable GnuPG
# agent forwarding and SSH agent forwarding for our own user accounts.

Match Host desktop.local User john
    StreamLocalBindUnlink yes
    RemoteForward /run/user/1000/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra
    ForwardAgent yes

Match Host laptop.local User john
    StreamLocalBindUnlink yes
    RemoteForward /run/user/1000/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra
    ForwardAgent yes

Match Host notebook.local User john
    StreamLocalBindUnlink yes
    RemoteForward /run/user/1000/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra
    ForwardAgent yes

# -*- mode: ssh_config; indent-tabs-mode: nil; tab-width: 4; -*-

The file ~/.ssh/config.d/example.net.conf contains settings for our own servers:

# ---------------------------------------------------
# SSH Client Configuration for example.net servers
# ---------------------------------------------------

# Home router remote access
Host arnold.home.example.net
    User root
    ForwardAgent yes

# Office router remote access
Host teddy.office.example.net
    User root
    ForwardAgent yes

# Cloud server at Hetzner, San Francisco
Match Host dolores.example.net User john
    StreamLocalBindUnlink yes
    RemoteForward /run/user/1000/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra
    ForwardAgent yes

# VPS host at Rackspace, London
Match Host maeve.example.net User john
    StreamLocalBindUnlink yes
    RemoteForward /run/user/1000/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra
    ForwardAgent yes

# Home NAS and Office NAS
Match Host hector.home.example.net,logan.office.example.net User admin,john
    ForwardAgent yes

# -*- mode: ssh_config; indent-tabs-mode: nil; tab-width: 4; -*-
#
# 3rd-party systems
#
Host kissy.example.org
    Port 54393
    User johnd

Host holden.example.org
    Port 51193

Host github.com
    User git

Host *.synology.me
    VerifyHostKeyDNS No

OpenSSH Trust in DNSSEC

In the previous section, we have set our SSH client to verify the servers SSH public key with the fingerprints published in DNS trough the VerifyHostKeyDNS configuration option. Unfortunately this wont work out of the box, as the following tests will show:

Set this to your own servers hostname for the following checks to work:

$ export TEST_HOST=dolores.example.net

Let’s check if the fingerprints of our server are present in DNS and that these DNS records are secured by DNSSEC:

$ dig $TEST_HOST SSHFP | egrep "ad|$"
flags: qr rd ra ad

The ad flag in the DNS answer stands for “authenticated data” and confirms that the DNS records requested have been successfully verified with valid DNSSEC signatures. But the OpenSSH client will still insist, that the fingerprints, while visible, are not to be trusted:

$ ssh -v $TEST_HOST logout 2>&1 | egrep "found .* in DNS|$"
debug1: found 2 insecure fingerprints in DNS

This is caused by the GNU C library and its not just a simple bug, but a rather complex trust issue described in Glibc support encryption by modifying the DNS.

Unless /etc/resolv.conf contains edns0 and trust-ad as configuration options, programs who use the GNU C library (glibc) like OpenSSH and many others, aren’t able to see that the DNSSEC validation was successful.

Nowadays the /etc/resolv.conf file is managed by systemd, NetworkManager, the resolvconf service or whatever you use as your local DNS resolver. Its therefore no longer possible and not recommended to change anything in this file manually.

As as described in the manpage for resolv.conf(5) as sn alternative, the options can also be set as space separated list in the RES_OPTIONS environment variable, :

Let’s try this out:

$ RES_OPTIONS="edns0 trust-ad"
$ ssh -v $TEST_HOST logout 2>&1 | egrep "found .* in DNS|$"
debug1: found 2 secure fingerprints in DNS

Warning

The following system-wide configuration settings should only be made, if trust your DNS resolvers and providers. dnssec-trigger can help to establish this trust.

Bash Environment

To set this as a system-wide default for terminal sessions and shell scripts, add the following file to /etc/profile.d directory:

#!/usr/bin/env bash
#
# Let programs who use the GNU C library (glibc) see if DNS answers are
# authenticated by DNSSEC. Required for OpenSSH to trust in DNSSEC-signed
# SSHFP records.
# See man resolv.conf(5)

# Set the value, preserve existing if already set.
export RES_OPTIONS="$RES_OPTIONS edns0 trust-ad"

Systemd Environment

Gnome desktop applications, like remote SFTP folders in Nautilus, may not read your bash environment, as they are not running in your terminal session. Since these are managed by Systemd, we set these trough a systemd environment file generator.

Create the systemd user environment directory:

$ sudo mkdir -p /etc/systemd/user-environment-generators

Create the file /etc/systemd/user-environment-generators/90res-options or download it

#!/bin/bash
#
# Systemd user environment generator
#
# Let programs who use the GNU C libary (glibc) see if DNS answers are
# authenticated by DNSSEC. Required for OpenSSH (and subsequently gvfs-daemon
# and Nautilus) to trust DNSSEC-signed SSHFP records.
# See man resolv.conf(5)

# Set the value, preserve existing if already set.
RES_OPTIONS="$RES_OPTIONS edns0 trust-ad"

# Write this out to the sytemd user environment
echo RES_OPTIONS="${RES_OPTIONS}"

It needs to be executable:

$ sudo chmod +x /etc/systemd/user-environment-generators/90res-options

See also

You may also look at these related pages: