diff --git a/harden b/harden index 797f254..063b15a 100755 --- a/harden +++ b/harden @@ -78,16 +78,16 @@ function install_packages { export NEEDRESTART_MODE=a export DEBIAN_PRIORITY=critical # Running sudo with -E will preserve the environment variables set in the script - sudo -E apt update -y && sudo apt upgrade -y # Update the package list and upgrade the packages - sudo -E apt install -y "$@" # Install the packages passed as arguments + sudo -E apt update -y && sudo apt upgrade -y > /dev/null 2>&1 # Update the package list and upgrade the packages + sudo -E apt install -y "$@" > /dev/null 2>&1 # Install the packages passed as arguments ;; "dnf") # If the package manager is dnf - sudo dnf upgrade -y # Update the package list - sudo dnf install -y "$@" # Install the packages passed as arguments + sudo dnf upgrade -y > /dev/null 2>&1 # Update the package list + sudo dnf install -y "$@" > /dev/null 2>&1 # Install the packages passed as arguments ;; "zypper") # If the package manager is zypper - sudo zypper update -y # Update the package list - sudo zypper install -y "$@" # Install the packages passed as arguments + sudo zypper update -y > /dev/null 2>&1 # Update the package list + sudo zypper install -y "$@" > /dev/null 2>&1 # Install the packages passed as arguments ;; *) # If the package manager is not one of the above, output unsupported package manager @@ -165,16 +165,16 @@ function getCorrectFirewall { export DEBIAN_FRONTEND=noninteractive export NEEDRESTART_MODE=a export DEBIAN_PRIORITY=critical - sudo -E apt install ufw -y # Install ufw + sudo -E apt install ufw -y > /dev/null 2>&1 # Install ufw printf "%s" "ufw" # Output ufw ;; "CentOS Linux" | "Fedora" | "Red Hat Enterprise Linux Server") # If the distribution is CentOS, Fedora or RHEL - sudo dnf install firewalld -y # Install firewalld + sudo dnf install firewalld -y > /dev/null 2>&1 # Install firewalld printf "%s" "firewalld" # Output firewalld ;; "openSUSE Leap") # If the distribution is OpenSUSE - sudo zypper install firewalld -y # Install firewalld + sudo zypper install firewalld -y > /dev/null 2>&1 # Install firewalld printf "%s" "firewalld" # Output firewalld ;; *) @@ -191,7 +191,7 @@ function getCorrectKernelSecurityModule { distro="$(get_distro)" # Get the distribution name case "$distro" in # Use case to check for the distribution name "Ubuntu") # If the distribution is Ubuntu - sudo apt install apparmor-profiles apparmor-utils apparmor-profiles-extra -y # Install apparmor + sudo apt install apparmor-profiles apparmor-utils apparmor-profiles-extra -y > /dev/null 2>&1 # Install apparmor printf "%s" "apparmor" # Output apparmor ;; "Debian GNU/Linux") # If the distribution is Debian @@ -199,15 +199,15 @@ function getCorrectKernelSecurityModule { export DEBIAN_FRONTEND=noninteractive export NEEDRESTART_MODE=a export DEBIAN_PRIORITY=critical - sudo -E apt install apparmor apparmor-profiles apparmor-profiles-extra apparmor-utils auditd python3-apparmor -y # Install apparmor + sudo -E apt install apparmor apparmor-profiles apparmor-profiles-extra apparmor-utils auditd python3-apparmor -y > /dev/null 2>&1 # Install apparmor printf "%s" "apparmor" # Output apparmor ;; "CentOS Linux" | "Fedora" | "Red Hat Enterprise Linux Server") # If the distribution is CentOS, Fedora or RHEL - sudo dnf install selinux container-selinux -y # Install selinux + sudo dnf install selinux container-selinux -y > /dev/null 2>&1 # Install selinux printf "%s" "selinux" # Output selinux ;; "openSUSE Leap") # If the distribution is OpenSUSE - sudo zypper install -t pattern apparmor -y # Install apparmor + sudo zypper install -t pattern apparmor -y > /dev/null 2>&1 # Install apparmor printf "%s" "apparmor" # Output apparmor ;; *) @@ -230,12 +230,14 @@ function firewallInit { sudo ufw allow 22100/tcp # Allow ssh connections on port 22100 sudo ufw allow 8000/tcp # Allow portainer connections on port 8000 sudo ufw allow 9443/tcp # Allow portainer connections on port 9443 + sudo ufw allow 8080/tcp # Allow watchtower connections on port 8080 ;; firewalld) sudo systemctl enable firewalld # Enable the firewall on boot sudo firewall-cmd --permanent --add-port=22100/tcp # Allow ssh connections on port 22100 sudo firewall-cmd --permanent --add-port=8000/tcp # Allow portainer connections on port 8000 sudo firewall-cmd --permanent --add-port=9443/tcp # Allow portainer connections on port 9443 + sudo firewall-cmd --permanent --add-port=8080/tcp # Allow watchtower connections on port 8080 ;; *) printf "%s" "Unsupported firewall" @@ -310,7 +312,7 @@ EOF set -e ARCH=$(uname -m) URL=https://storage.googleapis.com/gvisor/releases/release/latest/${ARCH} - wget "${URL}"/runsc "${URL}"/runsc.sha512 \ + wget -q "${URL}"/runsc "${URL}"/runsc.sha512 \ "${URL}"/containerd-shim-runsc-v1 "${URL}"/containerd-shim-runsc-v1.sha512 sha512sum -c runsc.sha512 \ -c containerd-shim-runsc-v1.sha512 @@ -412,7 +414,7 @@ FAIL2BAN_LOCAL=$(cat <<'EOF' allowipv6 = auto EOF ) -printf "%s\n" "$FAIL2BAN_LOCAL" | sudo tee /etc/fail2ban/fail2ban.local +printf "%s\n" "$FAIL2BAN_LOCAL" | sudo tee /etc/fail2ban/fail2ban.local > /dev/null 2>&1 FAIL2BAN_SSH_JAIL_LOCAL=$(cat <<'EOF' [sshd] enabled = true @@ -431,18 +433,18 @@ FAIL2BAN_JAIL_LOCAL=$(cat <<'EOF' bantime = 1d EOF ) -printf "%s\n" "$FAIL2BAN_JAIL_LOCAL" | sudo tee /etc/fail2ban/jail.local +printf "%s\n" "$FAIL2BAN_JAIL_LOCAL" | sudo tee /etc/fail2ban/jail.local > /dev/null 2>&1 sudo rm -f /etc/fail2ban/jail.d/* -printf "%s\n" "$FAIL2BAN_SSH_JAIL_LOCAL" | sudo tee /etc/fail2ban/jail.d/sshd.local +printf "%s\n" "$FAIL2BAN_SSH_JAIL_LOCAL" | sudo tee /etc/fail2ban/jail.d/sshd.local > /dev/null 2>&1 FAIL2BAN_FILTER=$(cat <<'EOF' [Definition] failregex = ^.*DROP_.*SRC= DST=.*$ journalmatch = _TRANSPORT=kernel EOF ) -printf "%s\n" "$FAIL2BAN_FILTER" | sudo tee /etc/fail2ban/filter.d/fwdrop.local +printf "%s\n" "$FAIL2BAN_FILTER" | sudo tee /etc/fail2ban/filter.d/fwdrop.local > /dev/null 2>&1 sudo systemctl enable --now fail2ban -printf "%s\n" "LogLevel VERBOSE" | sudo tee -a /etc/ssh/sshd_config +printf "%s\n" "LogLevel VERBOSE" | sudo tee -a /etc/ssh/sshd_config > /dev/null 2>&1 } function enableServices { @@ -475,7 +477,7 @@ function deleteRemainingUsers { # Set the correct timezone for Greece before using at sudo timedatectl set-timezone Europe/Athens # Delete possible remaining users - cat << EOF | sudo tee /root/delete_users.sh + cat << EOF | sudo tee /root/delete_users.sh > /dev/null 2>&1 [[ -d /home/admin ]] && sudo userdel -r admin && sudo groupdel admin [[ -d /home/ec2-user ]] && sudo userdel -r ec2-user && sudo groupdel ec2-user [[ -d /home/centos ]] && sudo userdel -r centos && sudo groupdel centos @@ -486,19 +488,18 @@ EOF # Restart atd after setting the timezone sudo systemctl restart atd # Use at as root because if it is run as one of the users above it will fail - sudo at now + 1 minute <<< "bash /root/delete_users.sh" + sudo at now + 2 minute <<< "bash /root/delete_users.sh" } function dynamicDockerPortsCronjob { sudo mkdir -p /root/bin - cat << 'TOHERE' | sudo tee /root/bin/dynamic_docker_ports_cronjob.sh + cat << 'TOHERE' | sudo tee /root/bin/dynamic_docker_ports_cronjob.sh > /dev/null 2>&1 #!/usr/bin/env bash # Get the current ports used by docker -CURRENT_DOCKER_PORTS_CMD="docker ps --format '{{.Ports}}' | rev | cut -d'/' -f2 | sed 's@^[^0-9]*\([0-9]\+\).*@\1@' | rev | sort -u | tr '\n' ' ')" -CURRENT_DOCKER_PORTS="$(sudo machinectl shell secdep@ /bin/bash -c "$CURRENT_DOCKER_PORTS_CMD")" +CURRENT_DOCKER_PORTS="$(DOCKER_HOST=unix:///run/user/"$(id -u secdep)"/docker.sock /home/secdep/bin/docker ps --format '{{.Ports}}' | rev | cut -d'/' -f2 | sed 's@^[^0-9]*\([0-9]\+\).*@\1@' | rev | sort -u | tr '\n' ' ')" # Get the current ports allowed by the firewall -CURRENT_FIREWALL_PORTS_FIREWALLD_CMD="sudo firewall-cmd --list-ports | tr '\n' ' '" -CURRENT_FIREWALL_PORTS_UFW_CMD="sudo ufw status numbered | awk '{print \$3}' | sed '/^[[:space:]]*$/d' | \grep -Eow '[[:digit:]]+' | sort -u | tr '\n' ' '" +CURRENT_FIREWALL_PORTS_FIREWALLD_CMD="$(sudo firewall-cmd --list-ports | tr '\n' ' ')" +CURRENT_FIREWALL_PORTS_UFW_CMD="$(sudo ufw status numbered | awk '{print $3}' | sed '/^[[:space:]]*$/d' | \grep -Eow '[[:digit:]]+' | sort -u | tr '\n' ' ')" # Determine if ufw or firewalld is currently used whereis ufw | grep -q /ufw && currentFirewall="ufw" || currentFirewall="firewalld" # Find which ports are not allowed by the firewall but are used by docker @@ -569,8 +570,8 @@ else sudo ufw reload fi TOHERE -cat << TOHERE | sudo tee -a /var/spool/cron/crontabs/root # Every 30 minutes check if there are any new ports used by docker and allow them in the firewall +cat << TOHERE | sudo tee -a /var/spool/cron/crontabs/root > /dev/null 2>&1 */30 * * * * /root/bin/dynamic_docker_ports_cronjob.sh TOHERE sudo chmod +x /root/bin/dynamic_docker_ports_cronjob.sh @@ -579,7 +580,7 @@ sudo systemctl restart cron function automaticUpdatesCronjob { sudo mkdir -p /root/bin - cat << 'TOHERE' | sudo tee /root/bin/automatic_updates_cronjob.sh + cat << 'TOHERE' | sudo tee /root/bin/automatic_updates_cronjob.sh > /dev/null 2>&1 #!/usr/bin/env bash function get_distro { if [[ -e /etc/os-release ]] && [[ -r /etc/os-release ]]; then # Check if file exists and is readable @@ -617,7 +618,7 @@ function get_package_manager { # The update_system function will take the output of the get_package_manager function and update the system # It will also check if the package manager is known and exit if it is not. -function install_packages { +function update_system { local package_manager # Declare package_manager as a local variable package_manager="$(get_package_manager)" # Get the package manager case "$package_manager" in # Use case to check for the package manager @@ -648,8 +649,8 @@ function install_packages { } update_system TOHERE -cat << TOHERE | sudo tee -a /var/spool/cron/crontabs/root # Every day at 4:00 AM update the system +cat << TOHERE | sudo tee -a /var/spool/cron/crontabs/root > /dev/null 2>&1 0 4 * * * /root/bin/automatic_updates_cronjob.sh TOHERE sudo chmod +x /root/bin/automatic_updates_cronjob.sh @@ -660,33 +661,33 @@ sudo systemctl restart cron # It will also pass any arguments passed to the script to the dockerInit function. # Then it will output a message to the user and reboot the system in 2 minutes. function main { - printf "%s" "$SCRIPT_NAME script started" + printf "%s\n" "$SCRIPT_NAME script started" check_dependencies || exit 1 # Check dependencies and exit if it fails - printf "%s" "Dependencies installed" + printf "%s\n" "Dependencies installed" hardenSSH || exit 1 # Harden ssh and exit if it fails - printf "%s" "SSH hardened" + printf "%s\n" "SSH hardened" firewallInit || exit 1 # Initialize the firewall and exit if it fails - printf "%s" "Firewall initialized" + printf "%s\n" "Firewall initialized" kernelSecurityModuleInit || exit 1 # Initialize the kernel security module and exit if it fails - printf "%s" "Kernel security module initialized" + printf "%s\n" "Kernel security module initialized" configureFail2ban || exit 1 # Initialize fail2ban and exit if it fails - printf "%s" "Fail2ban configured" + printf "%s\n" "Fail2ban configured" # Call the dockerInit function with the arguments passed to the script dockerInit "$@" || exit 1 # Initialize docker and exit if it fails - printf "%s" "Docker Rootless, docker-compose and gVisor installed and configured" - printf "%s" "Portainer and Watchtower along with any specified docker images from the command line or a docker-compose.yml file installed" + printf "%s\n" "Docker Rootless, docker-compose and gVisor installed and configured" + printf "%s\n" "Portainer and Watchtower along with any specified docker images from the command line or a docker-compose.yml file installed" enableServices || exit 1 # Enable the services that need to be restarted and the firewall - printf "%s" "Services restarted and firewall enabled" + printf "%s\n" "Services restarted and firewall enabled" dynamicDockerPortsCronjob || exit 1 # Allow the ports used by docker in the firewall - printf "%s" "CronJob to allow the ports used by docker in the firewall installed" + printf "%s\n" "CronJob to allow the ports used by docker in the firewall installed" automaticUpdatesCronjob || exit 1 # Install a cronjob to update the system periodically - printf "%s" "CronJob to update the system installed" + printf "%s\n" "CronJob to update the system installed" deleteRemainingUsers || exit 1 # Delete possible remaining users - printf "%s" "Any unnecessary users deleted" - printf "%s" "$SCRIPT_NAME script finished" # Output message to the user - printf "%s" "System will reboot momentarily" # Output message to the user - # Reboot the system in 2 minutes with the shutdown command so that login before the reboot is not possible - sudo shutdown -r +2 + printf "%s\n" "Any unnecessary users deleted" + printf "%s\n" "$SCRIPT_NAME script finished" # Output message to the user + printf "%s\n" "System will reboot momentarily" # Output message to the user + # Reboot the system in 3 minutes with the shutdown command so that login before the reboot is not possible + sudo shutdown -r +3 } # Call the main function