Skip to content

Instantly share code, notes, and snippets.

@szocsbarni
Last active September 3, 2023 09:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szocsbarni/7b9dcadaefa54f0cec6783a49aae9f0e to your computer and use it in GitHub Desktop.
Save szocsbarni/7b9dcadaefa54f0cec6783a49aae9f0e to your computer and use it in GitHub Desktop.
Security Baby Steps

Security hardening configuration steps

Introduction

These are the steps that I am following to set up a new home Linux server. OS is assumed to be installed but nothing else. Tested on Debian 11.

Basic things

Disable SSH

I have decieded not to deal with remote SSH connections, I have physical access to the machine and can live without remote access to my server. To make sure that SSH service is disabled:

sudo systemctl status sshd

Limit who can use sudo

Follow the steps from: https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#limit-who-can-use-sudo

Limit who can use su

Follow the steps from: https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#limit-who-can-use-su

Securing /proc

Follow the steps from: https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#securing-proc

Setup Firewall (UFW)

Follow the steps from: https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#firewall-with-ufw-uncomplicated-firewall

Do not open the ssh port for UFW

UFW does not support the creation of user based restrictions, but using the after.rules configuration file and iptables commands it is possible to extend the ruleset created with UFW. The first step is to backup the after.rules and after6.rules:

sudo cp /etc/ufw/after.rules /etc/ufw/after.rules-COPY-$(date +"%Y%m%d%H%M%S")
sudo cp /etc/ufw/after6.rules /etc/ufw/after6.rules-COPY-$(date +"%Y%m%d%H%M%S")

Then use an editor (like nano) to insert new rules to the file, but make sure to add the before the 'COMMIT' line, otherwise the command will not be interpreted. Use the iptables-resore syntax. For example, letting any process of a specific user to create outbound connections to any port would look like this:

-A ufw-after-output -p udp -m owner --uid-owner NAME_OF_USER -m comment --comment "let NAME_OF_USER out anywhere" -j ACCEPT

Use additional package extensions of iptables, to restrict the above example to be able to connect only from a specific port from localhost to any server:

-A ufw-after-output -p udp -m udp --sport PORT_NUMBER -m owner --uid-owner NAME_OF_USER -m comment --comment "let NAME_OF_USER out anywhere from port PORT_NUMBER" -j ACCEPT

Reload UFW the changes have been saved: sudo ufw reload

List anytime the active rules in iptables: sudo iptables -L

Setup intrusion detection with PSAD

Follow the steps from: https://github.com/imthenachoman/How-To-Secure-A-Linux-Server#iptables-intrusion-detection-and-prevention-with-psad

On the psad.conf I have the following changes:

  • EMAIL_ADDRESSES changed to MY_USER@localhost
  • HOSTNAME changed to PC name
  • HOME_NET changed to any
  • ENABLE_PSADWATCHD changed to Y
  • ENABLE_AUTO_IDS changed to Y
  • AUTO_IDS_DANGER_LEVEL changed to 3

Whitelist home router by assigning your home router IP address an automatic danger level of 0. This can be done via editing psad configuration file:

nano /etc/psad/auto_dl 

where we need to add IP of the home router, a danger level (0 in this case) and a comment, something like this:

    IP.OF.HOME.ROUTER           0;             # Ignore home router

restart psad after the modification is saved:

sudo service psad restart 

Note: This step is maybe needed only for a specific type of routers, mine is a TP-LINK and sends a lot of port scans to my PC sadly.

Make sure NTP is running

During installation Debian 11 does the setup for the NTP service, check if it is running:

sudo systemctl status ntp.service 

Disable OS sleep

The motivation here is to make sure the system can never go to sleep/hibernate/etc

sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 

Disable wifi and bluetooth

Wifi and bluetooth are disabled from the BIOS, but the bluetooth service is automatically included in the setup. We need to manually disable it:

sudo systemctl disable bluetooth.service 
sudo systemctl stop bluetooth.service 
sudo systemctl mask bluetooth.service

(Optional) Disable bluetooth driver to even load, because on my motherboard the drivers are not available for Debian 11:

sudo nano /etc/default/bluetooth 

and set to false the variable BLUETOOTH_ENABLED:

BLUETOOTH_ENABLED=0

To disable wifi driver to be loaded the following steps were made (again same reason, not only the missing driver, but also security hardening):

sudo modprobe iwlwifi disable_11ac=true
sudo modprobe iwlwifi 11n_disable=1
echo "options iwlwifi 11n_disable=1" | sudo tee /etc/modprobe.d/iwlwifi.conf

Note: decided not to use unattended upgrades

Disable unused services

CUPS - printer discovery protocol

Check if CUPS is running:

sudo systemctl status cups.service

If yes then we need to verify before disabling if there is any other service relaying on cups.service, because if there is one, then for that service's request the cups.service will be started even if it is already disabled on startup. This can be done via:

sudo systemctl --reverse list-dependencies cups.service

Then stop and disable all the services listed there with:

sudo systemctl stop cups-browsed.service 
sudo systemctl disable cups-browsed.service 

Once done, the cups.service can be safely stopped and disabled:

sudo systemctl stop cups.service 
sudo systemctl disable cups.service 

One can ignore the dependencies and the repercussions of a stopped service and just mask the service, which would prevent any other service to start it. This can be done via:

sudo systemctl mask cups.service

AVAHI service discovery protocol

Check for dependencies:

sudo systemctl --reverse list-dependencies avahi-daemon.service 

If none found (outside of himself), then stop it, disable it, and mask it, to prevent anyone from starting it:

sudo systemctl stop avahi-daemon
sudo systemctl disable avahi-daemon
sudo systemctl mask avahi-daemon.service

Useful comands

System level

Setting kernel target to graphical interface, permanent:

systemctl set-default graphical.target

Setting kernel target to terminal interface, permanent:

systemctl set-default multi-user.target 

To do the same as above but only temporarily, then edit the grub menu manually. Reboot and press e on the grub menu screen to enter edit mode. Then navigate to the linux entry and remove the quiet and splash to disable the splashscreen and add the systemd target for the next boot systemd.unit=multi-user.target. Then press Ctrl+x to boot.

All system logs since boot time:

sudo journalctl -b

Last 10 minutes journal log of a service xyxy:

sudo journalctl -fu xyxy --since '10 min ago'

Managing services with systemctl:

sudo systemctl stop xyxy.service
sudo systemctl start xyxy.service
sudo systemctl daemon-reload

Monitor file changes on regular interval (half second in the below example) :

watch -n 0.5 sudo  cat /sys/kernel/debug/dri/0/amdgpu_pm_info

Check for an installed package by name:

dpkg -l | grep -i "string_you_look_for"

Listing running processes:

sudo ps aux 

A more nicer, process tree:

sudo pstree

List running services:

systemctl list-units --type=service --state=running

Hardware temperature monitoring with HwInfo:

sudo apt install hwinfo
sudo hwinfo --cpu --short

Hardware temperature monitoring with sensors package:

sudo apt install lm-sensors
sudo sensors-detect 
sudo sensors

Gui based:

sudo apt install psensor
psensor 

Network level

Listening the communication on a specific port:

sudo ss -tulpn | grep ':80'

UFW status:

sudo ufw status verbose
sudo ufw status numbered

UFW delete rule with ID:

sudo ufw delete 19

UFW reload ruleset:

sudo ufw reload

Check active internet connections (servers only):

netstat -utpln

Check all active internet connections (established too):

netstat -tapn

Check for psad status:

sudo psad --Status 

Filter iptables log history for a specific IP:

sudo cat /var/log/messages | grep IP.OF.INT.EREST

Create additional IP addresses on the default physical network interface:

sudo ip a add 192.168.XXX.YYY dev enp39s0:0

enp39s0 is the name of the physical network interface, :0 means an additional slot Note: such IP address is only live in the current OS session, a restart will purge it. In order to make it persistent, the changes needs to be done in the /etc/network/interfaces. Edit that file and append to the end of it:

# The secondary network interface - specially used for app xy 
iface enp39s0 inet static
 address 192.168.XXX.YYY
 netmask 255.255.255.0

Restart the network interface after the changes have been saved, use commands:

sudo ifup enp39s0 -v
sudo ifdown enp39s0 -v

Sometimes flushing the current IP adresses is needed, do it with:

sudo ip a flush dev enp39s0 

To route the outgoing traffic of a specific user through a specific local IP address:

sudo ip rule add uidrange UID_START-UID_END table WW
sudo ip route add default via 192.168.AAA.BBB src 192.168.XXX.YYY table WW

192.168.AAA.BBB is the local gateway address, 192.168.XXX.YYY is the ip address used for the traffic, WW is the index of the table, lower indexs have priorities, range 0-32K.

To check the results:

sudo ip route show table WW
sudo ip rule show all

Note: these routes are temporary and are purged with an OS restart. In order to make them persistent, they can be added to the /etc/network/interfaces configuration file, where every ip adress defintion can have additional rule and route configurations. Edit the file and navigate to the ip address entry which will be used by the routes and append:

 post-up ip route add table WW 192.168.XXX.0/24 via 192.168.AAA.BBB dev enp39s0 src 192.168.XXX.YYY
 post-up ip rule add uidrange UID_start-UID_end lookup WW

with the complete entry resulting like this:

# The secondary network interface - specially used for xy
iface enp39s0 inet static
 address 192.168.XXX.YYY
 netmask 255.255.255.0
 post-up ip route add table WW 192.168.XXX.0/24 via 192.168.AAA.BBB dev enp39s0 src 192.168.XXX.YYY
 post-up ip rule add uidrange UID_start-UID_end lookup WW

Restart the network interface after the changes have been saved, use commands:

sudo ifup enp39s0 -v
sudo ifdown enp39s0 -v

Storage level

Wipe data from device (sdX):

sudo shred --verbose --random-source=/dev/urandom -n1 --zero /dev/sdX

List all sub-directories sorted by size:

sudo du -sh /* | sort -h

List all partition's free space:

sudo df -lh

List partition hierarchy:

sudo lsblk

List disk and partition UUIDs:

sudo blkid

Monitor LVM:

sudo pvdisplay
sudo pvs
sudo vgdisplay 
sudo lvdisplay

Extending storage system with a newly added, LUKS encrypted SSD. First step is to format and mount new drive:

sudo cryptsetup luksFormat /dev/sdX
sudo cryptsetup open /dev/sdX luksX

(Optional) Test passphrase of an LUKS device:

sudo cryptsetup luksOpen --test-passphrase /dev/sdX

Then extend an LVM partition using the new space:

sudo pvcreate /dev/mapper/luksX
sudo vgextend NAME_OF_V_GROUP /dev/mapper/luksX
sudo lvextend -r --size +100G /dev/NAME_OF_V_GROUP/NAME_OF_PARTITION

Note: -r is need to resize the filesystem aswell

Using same key to unlock multiple LUKS drives:

  • edit the configuration file: sudo nano /etc/crypttab to use the following mounting options: luks,keyscript=decrypt_keyctl
  • the final configuration looking like this:
luksA UUID="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" none luks,keyscript=decrypt_keyctl
luksX UUID="ffffffff-gggg-hhhh-iiii-jjjjjjjjjjjj" none luks,keyscript=decrypt_keyctl

Don't forget to update kernel afterwards:

sudo update-initramfs -u -k all

Note: check the result of the above command, if it fails, one root cause can be that keyutils package is missing. It can be installed via: sudo apt install keyutils and rerun the kernel update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment