Linux Remote Access & Administration
Linux Remote Access & Administration
## SSH
SSH keys are based on the concept of public key cryptography. They come in two
parts: a public half, and a private half, the public part of which you can place
onto servers, and the private part of which you keep about your person, either on
your laptop, or maybe a secure USB stick (one that is itself encrypted and password
protected).
Once your public half of a key is on your server, you can SSH to your remote host
using the local, private half of your key for authentication.
#### RSA
```bash
$ ssh-keygen -b 4096 -C "Example RSA Key"
```
Next, we're going to copy our newly generated RSA key to centos2, providing the
password for centos2 when prompted:
```bash
$ ssh-copy-id 192.168.33.11
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed:
"/home/vagrant/.ssh/id_rsa.pub"
The authenticity of host '192.168.33.11 (192.168.33.11)' cant be established. ECDSA
key fingerprint is SHA256:LKhW+WOnW2nxKO/PY5UO/ny3GP6hIs3m/ui6uy+Sj2E. ECDSA key
fingerprint is MD5:d5:77:4f:38:88:13:e7:f0:27:01:e2:dc:17:66:ed:46.
Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id:
INFO: attempting to log in with the new key(s), to filter out any that are already
installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted
now it is to install the new keys [email protected] password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '192.168.33.11'" and check to make
sure that only the key(s) you wanted were added
```
Finally, we're going to check that we can access centos2, by means of the key we
just generated.
We will be prompted for the passphrase we set when the key was generated. Type it
in when required:
```bash
[vagrant@centos1 ~]$ ssh 192.168.33.11
Enter passphrase for key '/home/vagrant/.ssh/id_rsa':
[vagrant@centos2 ~]$
```
#### Ed25519
As with our RSA example, we will start by generating a new key, this time
specifying the type as 'ed25519'.
---
Ed25519 keys are elliptical-curve based and a lot of very clever people believe
they offer superior security to RSA. The keys themselves are also much shorter
(which we'll touch on later,) meaning if you've ever got to type one out, it's a
lot less work. Annoyingly you can't use the public half of an Ed25519 key for
encrypting files, as you can with an RSA public half, so there's a trade off but it
depends on your needs.
---
```bash
[vagrant@centos1 ~]$ ssh-keygen -t ed25519 -C "Example Ed25519 key"
```
We're going to copy our new key over to centos2. Note that we're also specifying
the id_ed25519.pub file as the one to copy over:
```bash
[vagrant@centos1 ~]$ ssh-copy-id -i .ssh/id_ed25519.pub 192.168.33.11
```
Once installed, attempt to SSH to centos2, specifying the private half of the
Ed25519 key:
```bash
[vagrant@centos1 ~]$ ssh 192.168.33.11 -i .ssh/id_ed25519
Enter passphrase for key '.ssh/id_ed25519':
Last login: Wed Aug 8 10:06:33 2018 from 192.168.33.10
[vagrant@centos2 ~]$
```
In our example, we used the ssh-copy-id command to place our keys on the remote
server. What this actually does is put it in a specific file of the home user
you're connecting to.
On our centos2 host, we can find this file in the user's home directory,
under .ssh:
```bash
[vagrant@centos2 ~]$ pwd
/home/vagrant
[vagrant@centos2 ~]$ ls .ssh/
authorized_keys
```
Looking inside this file reveals the two keys we sent from centos1:
```bash
[vagrant@centos2 ~]$ cat .ssh/authorized_keys
```
The first one is our generated RSA key and the second one is the Ed25519 key.
As with any software, checking the manual page for the command you're running can
provide a sometimes overwhelming amount of additional detail:
```bash
$ man ssh-keygen
```
To save a little bit of a headache, I'm going to highlight some options that may be
of interest to you, starting with -b:
```bash
-b bits
```
We used the -b flag to specify a large amount of bits during the generation of our
RSA key. The minimum is 1024 and the default is 2048. Your place of business may
have requirements on the length of RSA keys.
```bash
-C comment
```
We used this to add a bit of description to our keys. It might be useful if you use
different keys for different things (this is my GitLab key, this is my personal
server key, this is my company server key, and so on).
If you do need multiple keys, you may want to pass the name of your new key within
the generation command (as opposed to typing it out when prompted):
```bash
-f filename
```
We also have -l to print the fingerprint of a key, and/or the ASCII art if you so
wish.
This can be very useful for verifying key pairs:
```bash
-l (or -lv for a pretty picture)
```
If you want to change the passphrase of a private half, but don't want to generate
a new key, you can use the -p option:
```bash
-p
```
To specify the type of key you wish to generate, you can use the -t option:
```bash
-t dsa | ecdsa | ed25519 | rsa
```
When choosing the type of key to generate, consider your requirements. RSA is
generally the most compatible, but your company may have other policies, or you may
have a personal preference. I've come across two scenarios where Ed25519 keys
couldn't be used – one was an in-house script that required RSA for encrypting
files, and the other was OpenStack, at the time.
Finally, there's good old -v, providing verbose output since the early days:
```bash
-v
```
This can be passed multiple times, that is, -vvv is also valid, with each v
increasing the debug level
- Port
Specifies the port number that
**[sshd(8)](http://man.he.net/man8/sshd)** listens on. The default
is 22. Multiple options of this type are permitted. See also
ListenAddress.
We're going to start with a simple one, that is, changing the default port on which
the SSH daemon runs:
```bash
# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
```
Change the preceding code so that the Port line is uncommented and now reads 2222:
```bash
#
Port 2222
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
```
```bash
$ sudo systemctl restart sshd
```
You can confirm this from within the OS with the following command:
```bash
$ ss -nl sport = :2222
- AddressFamily
Specifies which address family should be used by sshd. Valid
arguments are any (the default), inet (use IPv4 only), or inet6
(use IPv6 only).
- ListenAddress
Specifies the local addresses
**[sshd(8)](http://man.he.net/man8/sshd)** should listen on. The fol-
lowing forms may be used:
ListenAddress host|IPv4_addr|IPv6_addr
ListenAddress host|IPv4_addr:port
ListenAddress [host|IPv6_addr]:port
If port is not specified, sshd will listen on the address and all
Port options specified. The default is to listen on all local
addresses. Multiple ListenAddress options are permitted.
By default, SSH will listen on all addresses and interfaces:
```shell
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
```
We're going to change this so that it's only listening on IPv4 and our eth1
address.
```shell
AddressFamily inet
ListenAddress 192.168.10.115
#ListenAddress ::
# Here, :: is the IPv6 equivalent of 0.0.0.0 in IPv4.
```
```bash
$ sudo systemctl restart sshd
```
```bash
$ ss -nl sport = :2222
Some distributions deny root login by default, and this is widely considered a good
idea. Here, we have a user (vsur) that we can use to get around so that we don't
need to log in as root.
- PermitRootLogin
Specifies whether root can log in using
**[ssh(1)](http://man.he.net/man1/ssh)**. The argument
must be yes, prohibit-password, without-password,
forced-commands-only, or no. The default is prohibit-password.
```bash
#LoginGraceTime 2m
#PermitRootLogin yes
#StrictModes yes
```
Change it to no:
```bash
#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
```
```bash
$ sudo systemctl restart sshd
```
- PasswordAuthentication
Specifies whether password authentication is allowed. The
default is yes.
Because we've got our public keys on this host, we no longer need to allow
password-based access.
```bash
#PermitEmptyPasswords no
PasswordAuthentication yes
```
```bash
#PermitEmptyPasswords no
PasswordAuthentication no
```
```bash
$ sudo systemctl restart sshd
```
- PrintMotd
Specifies whether **[sshd(8)](http://man.he.net/man8/sshd)** should
print /etc/motd when a user logs
in interactively. (On some systems it is also printed by the
shell, /etc/profile, or equivalent.) The default is yes.
Providing your PrintMotd setting is set to yes, you can have users see the contents
of /etc/motd when they log in.
```bash
#PermitTTY yes
PrintMotd yes
#PrintLastLog yes
```
Next, restart the SSH daemon, and then modify the /etc/motd file to something
sensible.
```bash
$ sudo systemctl restart sshd && sh -c 'echo "This is a testing system, how did you
get here?" > /etc/motd'
```
- UseDNS
Specifies whether **[sshd(8)](http://man.he.net/man8/sshd)**
should look up the remote host name,
and to check that the resolved host name for the remote IP
address maps back to the very same IP address.
The last option I'm going to cover is the UseDNS entry, as it's a source of pain
for quite a few people:
```bash
#UseDNS yes
UseDNS no
```
Here, we can see that UseDNS has been explicitly set to no in our configuration
file. This is the default.
When set to no, the SSH daemon will not look up the remote host name, and check
that the remote IP maps back to the expected IP, based on that host name.
What this means is that when UseDNS is set to yes, and the machine you're
connecting from doesn't have a reverse DNS entry set, SSH will try and match the IP
it expects with what it's seeing, and likely fail to do so.
---
**In practice, all this means is that if your DNS is broken on the box you're
trying to connect to, you have to wait around like a lemon for a bit while the DNS
request times out, and eventually let you in.**
---
#### AllowUsers
We've already denied the root user access to our system, but what if we wanted to
take this a step further and specify the users we want to grant access to? For
that, we need the AllowUsers setting.
- AllowUsers
This keyword can be followed by a list of user name patterns,
separated by spaces. If specified, login is allowed only for
user names that match one of the patterns. Only user names are
valid; a numerical user ID is not recognized. By default, login
is allowed for all users.
If the pattern takes the form USER@HOST then USER and HOST are
separately checked, restricting logins to particular users from particular hosts.
HOST criteria may additionally contain addresses to match in CIDR
address/masklen format. The allow/deny directives are processed
in the following order: DenyUsers, AllowUsers, DenyGroups, and
finally AllowGroups.
See PATTERNS in
**[ssh_config(5)](http://man.he.net/man5/ssh_config)**
for more information on patterns.
This is rarely a default setting, or even commented out in the sshd_config file, so
we're going to add it to the bottom:
```bash
# PermitTTY no
# ForceCommand cvs server
AllowUsers vagrant
```
```bash
$ sudo systemctl restart sshd
```
Now, you've got a system that only the vsur user will be able to SSH to. You can
also add multiple names to this list, or even substitute this whitelist for a
blacklist, with DenyUsers.
SSH's systemd unit file will look similar to this, though your system may vary:
```bash
$ cat /etc/systemd/system/multiuser.target.wants/sshd.service
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
```
By default, we can see that the binary used is /usr/sbin/sshd with $OPTIONS passed
from elsewhere (in this case the EnvironmentFile value, as listed previously)
Here, we have the answer of why sshd_config is read by default—it's baked in.
One thing we've not mentioned yet are host keys, and the known_hosts file. This is
something that is often overlooked, so I'd like to take a few minutes to go over
these otherwise-ignored treasures.
In this section, we will inspect what happens when you first SSH to a new machine,
and then we will change the keys of that machine to see what problems this causes
us.