Linux Security Basics

Limit Who Can Use sudo

sudo lets accounts run commands as other accounts, including root. We want to make sure that only the accounts we want can use sudo.

Goals

  • sudo privileges limited to those who are in a group we specify

Notes

Steps

  1. Create a group:

     sudo groupadd sudousers
    
  2. Add account(s) to the group:

     sudo usermod -a -G sudousers user1
     sudo usermod -a -G sudousers user2
     sudo usermod -a -G sudousers  ...
    

    You’ll need to do this for every account on your server that needs sudo privileges.

  3. Make a backup of the sudo’s configuration file /etc/sudoers:

     sudo cp --archive /etc/sudoers /etc/sudoers-COPY-$(date +"%Y%m%d%H%M%S")
    
  4. Edit sudo’s configuration file /etc/sudoers:

     sudo visudo
    
  5. Tell sudo to only allow users in the sudousers group to use sudo by adding this line if it is not already there:

     %sudousers   ALL=(ALL:ALL) ALL
    

Limit Who Can Use su

su also lets accounts run commands as other accounts, including root. We want to make sure that only the accounts we want can use su.

Goals

  • su privileges limited to those who are in a group we specify

Steps

  1. Create a group:

     sudo groupadd suusers
    
  2. Add account(s) to the group:

     sudo usermod -a -G suusers user1
     sudo usermod -a -G suusers user2
     sudo usermod -a -G suusers  ...
    

    You’ll need to do this for every account on your server that needs sudo privileges.

  3. Make it so only users in this group can execute /bin/su:

     sudo dpkg-statoverride --update --add root suusers 4750 /bin/su
    

Run applications in a sandbox with FireJail

It’s absolutely better, for many applications, to run in a sandbox.

Browsers (even more the Closed Source ones) and eMail Clients are highly suggested.

Goals

  • confine applications in a jail (few safe directories) and block access to the rest of the system

Steps

  1. Install the software:

     sudo apt install firejail firejail-profiles
    

    Note: for Debian 10 Stable, official Backport is suggested:

     sudo apt install -t buster-backports firejail firejail-profiles
    
  2. Allow an application (installed in /usr/bin or /bin) to run only in a sandbox (see few examples below here):

     sudo ln -s /usr/bin/firejail /usr/local/bin/google-chrome-stable
     sudo ln -s /usr/bin/firejail /usr/local/bin/firefox
     sudo ln -s /usr/bin/firejail /usr/local/bin/chromium
     sudo ln -s /usr/bin/firejail /usr/local/bin/evolution
     sudo ln -s /usr/bin/firejail /usr/local/bin/thunderbird
    
  3. Run the application as usual (via terminal or launcher) and check if is running in a jail:

     firejail --list
    
  4. Allow a sandboxed app to run again as it was before (example: firefox)

     sudo rm /usr/local/bin/firefox
    

NTP Client

Many security protocols leverage the time. If your system time is incorrect, it could have negative impacts to your server. An NTP client can solve that problem by keeping your system time in-sync with global NTP servers

How It Works

NTP stands for Network Time Protocol. In the context of this guide, an NTP client on the server is used to update the server time with the official time pulled from official servers. Check https://www.pool.ntp.org/en/ for all of the public NTP servers.

Goals

  • NTP client installed and keeping server time in-sync

Steps

  1. Install ntp.

    On Debian based systems:

     sudo apt install ntp
    
  2. Make a backup of the NTP client’s configuration file /etc/ntp.conf:

     sudo cp --archive /etc/ntp.conf /etc/ntp.conf-COPY-$(date +"%Y%m%d%H%M%S")
    
  3. The default configuration, at least on Debian, is already pretty secure. The only thing we’ll want to make sure is we’re the pool directive and not any server directives. The pool directive allows the NTP client to stop using a server if it is unresponsive or serving bad time. Do this by commenting out all server directives and adding the below to /etc/ntp.conf.

     pool pool.ntp.org iburst
    
     sudo sed -i -r -e "s/^((server|pool).*)/# \1         # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/" /etc/ntp.conf
     echo -e "\npool pool.ntp.org iburst         # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/ntp.conf
    

    Example /etc/ntp.conf:

    driftfile /var/lib/ntp/ntp.drift
    statistics loopstats peerstats clockstats
    filegen loopstats file loopstats type day enable
    filegen peerstats file peerstats type day enable
    filegen clockstats file clockstats type day enable
    restrict -4 default kod notrap nomodify nopeer noquery limited
    restrict -6 default kod notrap nomodify nopeer noquery limited
    restrict 127.0.0.1
    restrict ::1
    restrict source notrap nomodify noquery
    pool pool.ntp.org iburst         # added by user on 2019-03-09 @ 10:23:35
    
  4. Restart ntp:

     sudo service ntp restart
    
  5. Check the status of the ntp service:

     sudo systemctl status ntp
    
    ● ntp.service - LSB: Start NTP daemon
       Loaded: loaded (/etc/init.d/ntp; generated; vendor preset: enabled)
       Active: active (running) since Sat 2019-03-09 15:19:46 EST; 4s ago
         Docs: man:systemd-sysv-generator(8)
      Process: 1016 ExecStop=/etc/init.d/ntp stop (code=exited, status=0/SUCCESS)
      Process: 1028 ExecStart=/etc/init.d/ntp start (code=exited, status=0/SUCCESS)
        Tasks: 2 (limit: 4915)
       CGroup: /system.slice/ntp.service
               └─1038 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 108:113
    
    Mar 09 15:19:46 host ntpd[1038]: Listen and drop on 0 v6wildcard [::]:123
    Mar 09 15:19:46 host ntpd[1038]: Listen and drop on 1 v4wildcard 0.0.0.0:123
    Mar 09 15:19:46 host ntpd[1038]: Listen normally on 2 lo 127.0.0.1:123
    Mar 09 15:19:46 host ntpd[1038]: Listen normally on 3 enp0s3 10.10.20.96:123
    Mar 09 15:19:46 host ntpd[1038]: Listen normally on 4 lo [::1]:123
    Mar 09 15:19:46 host ntpd[1038]: Listen normally on 5 enp0s3 [fe80::a00:27ff:feb6:ed8e%2]:123
    Mar 09 15:19:46 host ntpd[1038]: Listening on routing socket on fd #22 for interface updates
    Mar 09 15:19:47 host ntpd[1038]: Soliciting pool server 108.61.56.35
    Mar 09 15:19:48 host ntpd[1038]: Soliciting pool server 69.89.207.199
    Mar 09 15:19:49 host ntpd[1038]: Soliciting pool server 45.79.111.114
    
  6. Check ntp’s status:

     sudo ntpq -p
    
         remote           refid      st t when poll reach   delay   offset  jitter
    ==============================================================================
     pool.ntp.org    .POOL.          16 p    -   64    0    0.000    0.000   0.000
    *lithium.constan 198.30.92.2      2 u    -   64    1   19.900    4.894   3.951
     ntp2.wiktel.com 212.215.1.157    2 u    2   64    1   48.061   -0.431   0.104
    

Securing /proc

To quote https://linux-audit.com/linux-system-hardening-adding-hidepid-to-proc/:

When looking in /proc you will discover a lot of files and directories. Many of them are just numbers, which represent the information about a particular process ID (PID). By default, Linux systems are deployed to allow all local users to see this all information. This includes process information from other users. This could include sensitive details that you may not want to share with other users. By applying some filesystem configuration tweaks, we can change this behavior and improve the security of the system.

Note: This may break on some systemd systems. Please see https://github.com/imthenachoman/How-To-Secure-A-Linux-Server/issues/37 for more information. Thanks to nlgranger for sharing.

Goals

  • /proc mounted with hidepid=2 so users can only see information about their processes

Steps

  1. Make a backup of /etc/fstab:

     sudo cp --archive /etc/fstab /etc/fstab-COPY-$(date +"%Y%m%d%H%M%S")
    
  2. Add this line to /etc/fstab to have /proc mounted with hidepid=2:

     proc     /proc     proc     defaults,hidepid=2     0     0
    
     echo -e "\nproc     /proc     proc     defaults,hidepid=2     0     0         # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/fstab
    
  3. Reboot the system:

     sudo reboot now
    

    Note: Alternatively, you can remount /proc without rebooting with sudo mount -o remount,hidepid=2 /proc

Force Accounts To Use Secure Passwords

By default, accounts can use any password they want, including bad ones. pwquality/pam_pwquality addresses this security gap by providing “a way to configure the default password quality requirements for the system passwords” and checking “its strength against a system dictionary and a set of rules for identifying poor choices.”

How It Works

On Linux, PAM is responsible for authentication. There are four tasks to PAM that you can read about at https://en.wikipedia.org/wiki/Linux_PAM. This section talks about the password task.

When there is a need to set or change an account password, the password task of PAM handles the request. In this section we will tell PAM’s password task to pass the requested new password to libpam-pwquality to make sure it meets our requirements. If the requirements are met it is used/set; if it does not meet the requirements it errors and lets the user know.

Goals

  • enforced strong passwords

Steps

  1. Install libpam-pwquality.

    On Debian based systems:

     sudo apt install libpam-pwquality
    
  2. Make a backup of PAM’s password configuration file /etc/pam.d/common-password:

     sudo cp --archive /etc/pam.d/common-password /etc/pam.d/common-password-COPY-$(date +"%Y%m%d%H%M%S")
    
  3. Tell PAM to use libpam-pwquality to enforce strong passwords by editing the file /etc/pam.d/common-password and change the line that starts like this:

     password        requisite                       pam_pwquality.so
    

    to this:

     password        requisite                       pam_pwquality.so retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec
    

    The above options are:

    • retry=3 = prompt user 3 times before returning with error.
    • minlen=10 = the minimum length of the password, factoring in any credits (or debits) from these:
      • dcredit=-1 = must have at least one digit
      • ucredit=-1 = must have at least one upper case letter
      • lcredit=-1 = must have at least one lower case letter
      • ocredit=-1 = must have at least one non-alphanumeric character
    • difok=3 = at least 3 characters from the new password cannot have been in the old password
    • maxrepeat=3 = allow a maximum of 3 repeated characters
    • gecoschec = do not allow passwords with the account’s name
     sudo sed -i -r -e "s/^(password\s+requisite\s+pam_pwquality.so)(.*)$/# \1\2         # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")\n\1 retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec         # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/" /etc/pam.d/common-password
    

Automatic Security Updates and Alerts

It is important to keep a server updated with the latest critical security patches and updates. Otherwise you’re at risk of known security vulnerabilities that bad-actors could use to gain unauthorized access to your server.

Unless you plan on checking your server every day, you’ll want a way to automatically update the system and/or get emails about available updates.

You don’t want to do all updates because with every update there is a risk of something breaking. It is important to do the critical updates but everything else can wait until you have time to do it manually.

Why you shouldn’t enable automatic updates?

Automatic and unattended updates may break your system and you may not be near your server to fix it. This would be especially problematic if it broke your SSH access.

Notes:

  • Each distribution manages packages and updates differently. So far I only have steps for Debian based systems.
  • Your server will need a way to send e-mails for this to work

Goals

  • Automatic, unattended, updates of critical security patches
  • Automatic emails of remaining pending updates

Debian Based Systems

How It Works

On Debian based systems you can use:

  • unattended-upgrades to automatically do system updates you want (i.e. critical security updates)
  • apt-listchanges to get details about package changes before they are installed/upgraded
  • apticron to get emails for pending package updates

We will use unattended-upgrades to apply critical security patches. We can also apply stable updates since they’ve already been thoroughly tested by the Debian community.

Steps

  1. Install unattended-upgrades, apt-listchanges, and apticron:

     sudo apt install unattended-upgrades apt-listchanges apticron
    
  2. Now we need to configure unattended-upgrades to automatically apply the updates. This is typically done by editing the files /etc/apt/apt.conf.d/20auto-upgrades and /etc/apt/apt.conf.d/50unattended-upgrades that were created by the packages. However, because these file may get overwritten with a future update, we’ll create a new file instead. Create the file /etc/apt/apt.conf.d/51myunattended-upgrades and add this:

     // 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";
    
     // Do "apt-get autoclean" every n-days (0=disable)
     APT::Periodic::AutocleanInterval "7";
    
     // 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";
     APT::Periodic::Unattended-Upgrade "1";
    
     // Automatically upgrade packages from these
     Unattended-Upgrade::Origins-Pattern {
           "o=Debian,a=stable";
           "o=Debian,a=stable-updates";
           "origin=Debian,codename=${distro_codename},label=Debian-Security";
     };
    
     // You can specify your own packages to NOT automatically upgrade here
     Unattended-Upgrade::Package-Blacklist {
     };
    
     // Run dpkg --force-confold --configure -a if a unclean dpkg state is detected to true to ensure that updates get installed even when the system got interrupted during a previous run
     Unattended-Upgrade::AutoFixInterruptedDpkg "true";
    
     //Perform the upgrade when the machine is running because we wont be shutting our server down often
     Unattended-Upgrade::InstallOnShutdown "false";
    
     // Send an email to this address with information about the packages upgraded.
     Unattended-Upgrade::Mail "root";
    
     // Always send an e-mail
     Unattended-Upgrade::MailOnlyOnError "false";
    
     // Remove all unused dependencies after the upgrade has finished
     Unattended-Upgrade::Remove-Unused-Dependencies "true";
    
     // Remove any new unused dependencies after the upgrade has finished
     Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
    
     // Automatically reboot WITHOUT CONFIRMATION if the file /var/run/reboot-required is found after the upgrade.
     Unattended-Upgrade::Automatic-Reboot "true";
    
     // Automatically reboot even if users are logged in.
     Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
    

    Notes:

    • Check /usr/lib/apt/apt.systemd.daily for details on the APT::Periodic options
    • Check https://github.com/mvo5/unattended-upgrades for details on the Unattended-Upgrade options
  3. Run a dry-run of unattended-upgrades to make sure your configuration file is okay:

     sudo unattended-upgrade -d --dry-run
    

    If everything is okay, you can let it run whenever it’s scheduled to or force a run with unattended-upgrade -d.

  4. Configure apt-listchanges to your liking:

     sudo dpkg-reconfigure apt-listchanges
    
  5. For apticron, the default settings are good enough but you can check them in /etc/apticron/apticron.conf if you want to change them. For example, my configuration looks like this:

    EMAIL="root"
    NOTIFY_NO_UPDATES="1"
    

More Secure Random Entropy Pool (WIP)

Steps

  1. Install rng-tools.

    On Debian based systems:

     sudo apt-get install rng-tools
    
  2. Now we need to set the hardware device used to generate random numbers by adding this to /etc/default/rng-tools:

     HRNGDEVICE=/dev/urandom
    
     echo "HRNGDEVICE=/dev/urandom" | sudo tee -a /etc/default/rng-tools
    
  3. Restart the service:

     sudo systemctl stop rng-tools.service
     sudo systemctl start rng-tools.service
    
  4. Test randomness:

    • https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generator
    • https://wiki.archlinux.org/index.php/Rng-tools

Licenses and Attributions


Speak Your Mind