Build a fortress for Debian based distributions in 15 minutes
The first thing to think of once the instance is delivered is, “How can I secure the instance before putting any workloads on the server?"; so we can reduce the risk of illegal accesses, data breaches, and server compromises.
This article covers how to :
- Update root credentials and the creation of a non-root user
- Harden the SSH configuration
- Configure the firewall
- Have a system up-to-date
Update the root credentials
The first thing to do is to update the _root _’s password. Login to the instance with the credentials provided.
# Connect to the server as root ssh root@ip_address # Modify the root's password passwd root
Harden the SSH configuration
Limit the access to critical information by creating a user. This user replaces the root during login with SSH.
# Create a user with a HOME directory useradd -m guest # And then change the password passwd guest
Then, set up the SSH key pair, on the local machine, run the following command to generate the keys.
ssh-keygen -t ecdsa -b 521 -C "$(whoami)@$(hostname)-$(date -I)"
Copy the public key to the instance.
ssh-copy-id -i ~/.ssh/id_ecdsa.pub guest@ip_address
The public key is uploaded in the file
/home/guest/.ssh/authorized_keys. To avoid any unauthorized modification, the file access will only allow the guest user and block all modifications.
mkdir /home/guest/.ssh # Protect the folder, only guest user can access to the folder chmod 700 /home/guest/.ssh # Protect the authorized key file chmod 400 /home/guest/.ssh/authorized_keys # Set the folder ownership and its content to the guest user chown guest:guest /home/guest -R # Block all permsission modifications on the file chattr +i ~/.ssh/authorized_keys # Block all permsission modifications on the folder chattr +i ~/.ssh
To validate the configuration, try to connect with the SSH key with the following command. Keep a terminal opened with root access, in case you get lockout.
ssh -i ~/.ssh/id_ecdsa deploy@ip_address
If the connection succeeds, disconnect and come back in the root terminal. Otherwise, something is missing in the configuration performed above. Try to fix the issue in the root terminal.
Everything is set up to configure the SSH configuration, open the file with the editor of your choice
/etc/ssh/sshd_config and apply the following configuration:
# Block root login by SSH PermitRootLogin no # Block login when the user's password is empty PermitEmptyPasswords no # Block graphical application to be run X11 Forwarding no # Block all connexions by password (keys will be used instead) PasswordAuthentication no # Use protocol v2 Protocol 2 # Enable RSA keys authentication RSAAuthentication yes # Security reason (https://access.redhat.com/site/solutions/336773) ChallengeResponseAuthentication no # Limit the number of attempts by password to 5 MaxAuthTries 5 # Limit the number of simultaneous connexion by SSH to 5 MaxStartups 5 # Period allowed to the user to enter the password, otherwise he will be disconnected LoginGraceTime 1m # Disconnect the client after 600sec (10min) of inactivity ClientAliveInterval 600 ClientAliveCountMax 0 # Allow only the guest user to connect by SSH AllowUsers guest # Modify the location where the public keys are stored AuthorizedKeysFile %h/.ssh/authorized_keys
To apply the modification, restart the SSH service with the following command.
systemctl restart ssh
Configure the firewall
Create a folder where the custom scripts will be stored.
mkdir -p /homez/scripts/firewall
Create the script,
firewall.sh, that will be executed on each boot run. Then open it with the editor of your choice. The policy applied for the firewall is “everything is blocked by default”.
Copy and paste the below script, modify it according to your needs.
#!/bin/bash # Flush the tablesiptables -F iptables -X # Reject all incoming and outgoing connexions, the policy applied is a "blocked by default" iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT DROP # Reject invalid package iptables -A INPUT -m conntrack --ctstate INVALID -j DROP # Reject packets incoming from adresses defined in the RFC1918 standard iptables -A INPUT -i enp1s0 -s 10.0.0.0/8 -j DROP iptables -A INPUT -i enp1s0 -s 169.254.0.0/16 -j DROP iptables -A INPUT -i enp1s0 -s 127.0.0.0/8 -j DROP iptables -A INPUT -i enp1s0 -s 22.214.171.124/4 -j DROP iptables -A INPUT -i enp1s0 -d 126.96.36.199/4 -j DROP iptables -A INPUT -i enp1s0 -s 240.0.0.0/5 -j DROP iptables -A INPUT -i enp1s0 -d 240.0.0.0/5 -j DROP iptables -A INPUT -i enp1s0 -s 0.0.0.0/8 -j DROP iptables -A INPUT -i enp1s0 -d 0.0.0.0/8 -j DROP iptables -A INPUT -i enp1s0 -d 188.8.131.52/24 -j DROP iptables -A INPUT -i enp1s0 -d 255.255.255.255-j DROP # Reject SMURF attacks iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP # Reject packets that do not initiate the communication with a SYN packet type iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP # Reject incoming frament packets iptables -A INPUT -f -j DROP # Reject malformed NULL packets iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # Reject XMAS packets type iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP # Allow established/active/in progress connections iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT # Allow loopback iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # ICMP (Ping) iptables -A OUTPUT -p icmp -j ACCEPT iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # SSH iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT # DNS iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT iptables -A OUTPUT -p udp --dport 53 -j ACCEPT # NTP iptables -A OUTPUT -p udp --dport 123 -j ACCEPT # HTTP iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT # HTTPS iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
Save the script and modify the script permission to be only visible and executable by the root user.
chmod 700 /homez/scripts/firewall/firewall.sh
The script needs to be executed at each boot; to do so, create a file in the
/etc/systemd/system/ folder named
Copy and paste the following content.
[Unit]Description=Add firewall rules to iptables [Service]Type=oneshotExecStart=/homez/scripts/firewall/firewall.sh [Install]WantedBy=multi-user.target
And, activate the service
systemctl start firewall.service
To validate that your are not lock out, try to logout and login to the instance. If you can not login, reboot the instance with an hard reboot, and the firewall rules will be restored. And try to find where the issue in the script.
At any moment, it is possible to display the firewall rules with the command.
iptables -L -v -n
Now that the rules are validated enable the service to be run at each boot.
systemctl enable firewall.service
Get the latest software updates
Get the latest vulnerability fixes by upgrading the system, and the packages installed.
# Update the package list and upgrade the packages apt-get update && apt-get upgrade # Remove unused and orphan packages apt-get autoremove && apt-get autoclean