back to index

Securing a New Linux Server

First-pass hardening on a fresh DigitalOcean Droplet: non-root user, SSH port, key-only login.

published Mar 14, 2018 tags #linux #security #ssh

~/posts/securing-new-linux-server $ cat post.md

/ LANG EN / 中文
/ THEME / /

Overview

When standing up a new server, do a baseline pass: create a non-root user, change the SSH port, disable password login, and so on. This walks through the steps using a DigitalOcean Droplet as the example.

Log in

Start by SSH-ing in. DigitalOcean emails you the initial root password when the Droplet is created. After login, it forces a password change; make it as strong as you can since you won’t be using root much afterwards.

Create a non-root user

addgroup manager
useradd -d /home/deploy -s /bin/bash -m deploy
passwd deploy
usermod -a -G manager deploy

This creates the manager group, adds a deploy user under it, sets their password, and puts them in the group. deploy is just an example name — use whatever you’ll remember. All later service deployment runs as this non-root user.

visudo

This opens /etc/sudoers in nano by default. Under the line root ALL=(ALL:ALL) ALL add:

deploy    ALL=(ALL) NOPASSWD: ALL

Now deploy won’t be prompted for a password on sudo. If you’d prefer to require one, use deploy ALL=(ALL:ALL) ALL instead.

For reference, the resulting sudoers on a default DigitalOcean image looks roughly like:

#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults    env_reset
Defaults    mail_badpass
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL
deploy  ALL=(ALL) NOPASSWD: ALL    # <== add this

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo    ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d

Once that’s saved, log out and log back in as deploy:

exit
ssh deploy@<your-ip>

SSH hardening

The ideal end state is to disable SSH password login entirely and rely on keys. That’s a meaningful security gain, but losing the only machine with your key can be painful, so there are two recipes below. For production, use option one.

Option 1: disable password login

Generate a key locally and push the public half to the server:

ssh-keygen
ssh-copy-id user@host

On the server, back up and edit sshd_config:

sudo cp /etc/ssh/sshd_config ~
sudo nano /etc/ssh/sshd_config

The DigitalOcean default looks roughly like this — annotated lines are the ones to change:

# Package generated configuration file
# See the sshd_config(5) manpage for details

# What ports, IPs and protocols we listen for
Port 22                        # ==> change
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes

# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 1024

# Logging
SyslogFacility AUTH
LogLevel INFO

# Authentication:
LoginGraceTime 120
PermitRootLogin yes            # ==> set to no
StrictModes yes

RSAAuthentication yes          # ==> keep yes
PubkeyAuthentication yes       # ==> keep yes
#AuthorizedKeysFile %h/.ssh/authorized_keys  # ==> uncomment

# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes

# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no        # ==> keep no

# Change to yes to enable challenge-response passwords
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication yes     # ==> set to no

# ... rest omitted

UsePAM yes
UseDNS no                      # ==> add
AllowUsers deploy              # ==> add

Summary of edits:

  1. Change the port to something in > 1024 and <= 65535 — I tend to use something like 35245.
  2. PermitRootLogin no.
  3. PermitEmptyPasswords no.
  4. PasswordAuthentication no.
  5. UseDNS no.
  6. RSAAuthentication yes.
  7. PubkeyAuthentication yes.
  8. AuthorizedKeysFile .ssh/authorized_keys.
  9. Add AllowUsers deploy.

The list above covers what you’d need on a stock image; DigitalOcean already does some of these by default.

Restart sshd:

sudo service ssh restart           # whichever works
sudo /etc/init.d/ssh restart       # whichever works

On your laptop, add a stanza to ~/.ssh/config:

Host my-server
    HostName <your-ip>
    User deploy
    Port <your-port>

After that, ssh my-server is enough.

Option 2: keep password login

The security gap here vs option 1 is real. Weigh it.

Same sshd_config template, but only change three things:

  1. Port (as above).
  2. PermitRootLogin no.
  3. Add AllowUsers deploy.
back to index