SSH - Secure Shell
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: