Secure you Debian Server

From munkjensen.net/wiki

This guide contain the steps i always do on first time login after installing Debian on a blank server.

  • You need root access for the first steps, so gain root access as secure as you possibly can.


Update Debian

  • This is a good idea to do before anything else.

- Using the -y switch on apt-get will assume "yes" to all questions from apt-get.

- Sometimes ca-certificates needs an upgrade, and to make sure you know this is done you will need to press q to continue the apt-get -y upgrade

Here is how:

root@pulspc:~# apt-get -y update
Ign http://ftp.debian.org jessie InRelease
Get:1 http://ftp.debian.org jessie-updates InRelease [145 kB]
Get:2 http://ftp.debian.org jessie Release.gpg [2,373 B]

........ Lots of lines removed for convienience !!

Get:15 http://ftp.debian.org jessie-updates/main amd64 2016-11-30-2028.41.pdiff [530 B]
Get:16 http://security.debian.org jessie/updates/main Translation-en [183 kB]
Fetched 19.5 MB in 7s (2,674 kB/s)
Reading package lists... Done
root@pulspc:~#apt-get -y upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:

........ Lots of lines removed for convienience !!

Setting up python-pil:amd64 (2.6.1-2+deb8u3) ...
Processing triggers for libc-bin (2.19-18+deb8u7) ...
Processing triggers for ca-certificates (20141019+deb8u2) ...
Updating certificates in /etc/ssl/certs... 10 added, 10 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.
root@pulspc:~#

Configure Automatic Security Updates

Here you can see my configuration files

This is my version of the file /etc/apt/apt.conf.d/50unattended-upgrades

// Unattended-Upgrade::Origins-Pattern controls which packages are
// upgraded.
//
// Lines below have the format format is "keyword=value,...".  A
// package will be upgraded only if the values in its metadata match
// all the supplied keywords in a line.  (In other words, omitted
// keywords are wild cards.) The keywords originate from the Release
// file, but several aliases are accepted.  The accepted keywords are:
//   a,archive,suite (eg, "stable")
//   c,component     (eg, "main", "crontrib", "non-free")
//   l,label         (eg, "Debian", "Debian-Security")
//   o,origin        (eg, "Debian", "Unofficial Multimedia Packages")
//   n,codename      (eg, "jessie", "jessie-updates")
//     site          (eg, "http.debian.net")
// The available values on the system are printed by the command
// "apt-cache policy", and can be debugged by running
// "unattended-upgrades -d" and looking at the log file.
//
// Within lines unattended-upgrades allows 2 macros whose values are
// derived from /etc/debian_version:
//   ${distro_id}            Installed origin.
//   ${distro_codename}      Installed codename (eg, "jessie")
Unattended-Upgrade::Origins-Pattern {
        // Codename based matching:
        // This will follow the migration of a release through different
        // archives (e.g. from testing to stable and later oldstable).
      "o=Debian,n=jessie";
      "o=Debian,n=jessie-updates";
      "o=Debian,n=jessie-proposed-updates";
      "o=Debian,n=jessie,l=Debian-Security";

        // Archive or Suite based matching:
        // Note that this will silently match a different release after
        // migration to the specified archive (e.g. testing becomes the
        // new stable).
//      "o=Debian,a=stable";
//      "o=Debian,a=stable-updates";
//      "o=Debian,a=proposed-updates";
        "origin=Debian,codename=${distro_codename},label=Debian-Security";
};

// List of packages to not update (regexp are supported)
Unattended-Upgrade::Package-Blacklist {
//      "vim";
//      "libc6";
//      "libc6-dev";
//      "libc6-i686";
};

// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run
//   dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
//Unattended-Upgrade::AutoFixInterruptedDpkg "false";

// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGUSR1. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
//Unattended-Upgrade::MinimalSteps "true";

// Install all unattended-upgrades when the machine is shuting down
// instead of doing it in the background while the machine is running
// This will (obviously) make shutdown slower
//Unattended-Upgrade::InstallOnShutdown "true";

// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed. E.g. "[email protected]"
Unattended-Upgrade::Mail "root";

// Set this value to "true" to get emails only on errors. Default
// is to always send a mail if Unattended-Upgrade::Mail is set
//Unattended-Upgrade::MailOnlyOnError "true";

// Do automatic removal of new unused dependencies after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Automatically reboot *WITHOUT CONFIRMATION* if
//  the file /var/run/reboot-required is found after the upgrade
Unattended-Upgrade::Automatic-Reboot "false";

// If automatic reboot is enabled and needed, reboot at the specific
// time instead of immediately
//  Default: "now"
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

// Use apt bandwidth limit feature, this example limits the download
// speed to 70kb/sec
//Acquire::http::Dl-Limit "70";

This is my version of the file /etc/apt/apt.conf.d/02periodic

// Control parameters for cron jobs by /etc/cron.daily/apt //

// Enable the update/upgrade script (0=disable)
APT::Periodic::Enable "1";

// Do "apt-get update" automatically every n-days (0=disable)
APT::Periodic::Update-Package-Lists "1";

// Do "apt-get upgrade --download-only" every n-days (0=disable)
APT::Periodic::Download-Upgradeable-Packages "1";

// Run the "unattended-upgrade" security upgrade script
// every n-days (0=disabled)
// Requires the package "unattended-upgrades" and will write
// a log in /var/log/unattended-upgrades
APT::Periodic::Unattended-Upgrade "1";

// Do "apt-get autoclean" every n-days (0=disable)
APT::Periodic::AutocleanInterval "21";

// Send report mail to root
//     0:  no report             (or null string)
//     1:  progress report       (actually any string)
//     2:  + command outputs     (remove -qq, remove 2>/dev/null, add -d)
//     3:  + trace on
APT::Periodic::Verbose "2";

This is my version of the file /etc/apt/listchanges.conf

[apt]
frontend=pager
email_address=root
confirm=0
save_seen=/var/lib/apt/listchanges.db
which=both

Create and use a non-root user account

  • It is not a good idea to use the root account all the time. It is so powerful that even the smallest mistake can have devastating results if executed as root. Logging in as root directly is also considered bad practice so we will fix that now.

The 7 steps:

1. The sudo feature is not installed by default on Debian so we will do this first, since we rely heavily on this command when logging in as a "normal" user that needs to do stuff that requires root privileges.

apt-get install sudo

root@pulspc:~# apt-get install sudo
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  sudo
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 855 kB of archives.
After this operation, 2,390 kB of additional disk space will be used.

....................

Setting up sudo (1.8.10p3-1+deb8u3) ...
Processing triggers for systemd (215-17+deb8u6) ...
root@pulspc:~#

2. Create the user, replacing new_user with your desired username. You’ll then be asked to assign the user a password:

adduser new_user

root@pulspc:~# adduser new_user
Adding user `new_user' ...
Adding new group `new_user' (1000) ...
Adding new user `new_user' (1000) with group `new_user' ...
Creating home directory `/home/new_user' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for new_user
Enter the new value, or press ENTER for the default
        Full Name []: New User
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] Y
root@pulspc:~#

3. Add the new_user to the sudo group so it will have the option to do stuff that needs root-privileges.

adduser new_user sudo

root@pulspc:~# adduser new_user sudo
Adding user `new_user' to group `sudo' ...
Adding user new_user to group sudo
Done.
root@pulspc:~#

4. Make sure your new user is working by logging in to localhost from you current shell terminal using this command

ssh new_user@localhost

root@pulspc:~# ssh new_user@localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
RSA key fingerprint is 12:34:56:78:90:12:34:56:78:90:12:34:56:78:90
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
new_user@localhost's password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
new_user@pulspc:~$

5. Test that new_user can use the sudo command by calling the harmless ls command using sudo.

sudo ls /

fm@pulspc:~$ sudo ls /

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

[sudo] password for fm:
bin   etc         lib    lost+found  opt   run   sys  var
boot  home        lib32  media       proc  sbin  tmp  vmlinuz
dev   initrd.img  lib64  mnt         root  srv   usr
fm@pulspc:~$

6. Exit the new_user ssh connection and your root login.

exit

root@pulspc:~# fm@pulspc:~$ exit
logout
Connection to localhost closed.
root@pulspc:~# exit

7. ALWAYS login as the new_user from now on!

login as: new_user

login as: new_user
new_user@<IP or HOST name>'s password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Feb 22 09:55:27 2017 from localhost
new_user@pulspc:~$

Make SSH Access more secure

Install authentication key-pair

The crypto key-pairs is created on your local workstation.

Follow the guide that fit your workstation:

Harden the SSH Daemon

  1. Do not allow direct root login.
  2. Do not allow login without crypto key-pairs.
  3. Make SSH listen only on the IP protocol you will be using.

This is my /etc/ssh/sshd_config file

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

# What ports, IPs and protocols we listen for
Port 22
# 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
#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 no
StrictModes yes

RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile     %h/.ssh/authorized_keys

# 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

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no

#MaxStartups 10:30:60
#Banner /etc/issue.net

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

Subsystem sftp /usr/lib/openssh/sftp-server

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

Remember to restart the SSH daemon: sudo systemctl restart sshd

Brute force SSH Login Protection

Fail2ban scans log files (e.g. /var/log/apache/error_log) and bans IPs that show the malicious signs of brute force attacks

sudo apt-get -y install fail2ban

new_user@pulspc:~$ sudo apt-get -y install fail2ban
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  python-pyinotify
Suggested packages:
  python-gamin python-pyinotify-doc
The following NEW packages will be installed:
  fail2ban python-pyinotify
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 192 kB of archives.
After this operation, 713 kB of additional disk space will be used.
Get:1 http://ftp.debian.org/debian/ jessie/main fail2ban all 0.8.13-1 [165 kB]
Get:2 http://ftp.debian.org/debian/ jessie/main python-pyinotify all 0.9.4-1 [26.4 kB]
Fetched 192 kB in 0s (934 kB/s)
Selecting previously unselected package fail2ban.
(Reading database ... 37932 files and directories currently installed.)
Preparing to unpack .../fail2ban_0.8.13-1_all.deb ...
Unpacking fail2ban (0.8.13-1) ...
Selecting previously unselected package python-pyinotify.
Preparing to unpack .../python-pyinotify_0.9.4-1_all.deb ...
Unpacking python-pyinotify (0.9.4-1) ...
Processing triggers for man-db (2.7.0.2-5) ...
Processing triggers for systemd (215-17+deb8u6) ...
Setting up fail2ban (0.8.13-1) ...
Setting up python-pyinotify (0.9.4-1) ...
Processing triggers for systemd (215-17+deb8u6) ...
new_user@pulspc:~$

Configure it to your needs: http://www.fail2ban.org/wiki/index.php/Main_Page

Inspiration was found at http://www.linode.com/docs/security/securing-your-server/