From 8edb5737bc57091e6cce776aa70fcc8dff158f12 Mon Sep 17 00:00:00 2001 From: konsthol Date: Tue, 5 Sep 2023 05:12:24 +0300 Subject: [PATCH] I'm just a grunt. Don't blame me for this awful PoS. --- harden | 255 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 128 insertions(+), 127 deletions(-) diff --git a/harden b/harden index 81366e7..34d6fad 100755 --- a/harden +++ b/harden @@ -33,85 +33,84 @@ SCRIPT_NAME="${0##*/}" # The get_distro function will use short if statements to check for the os-release file existence and readability. # Then it will source it and output the distribution's name or exit in case of failure of either case. function get_distro { - if [[ -e /etc/os-release ]] && [[ -r /etc/os-release ]]; then # Check if file exists and is readable - . /etc/os-release # Source the file - printf "%s" "$NAME" # Output the distribution's name - else # If the file does not exist or is not readable - printf "%s" "File os-release not found or not readable" # Output error message - exit 1 # Exit with error code 1 - fi + if [[ -e /etc/os-release ]] && [[ -r /etc/os-release ]]; then # Check if file exists and is readable + . /etc/os-release # Source the file + printf "%s" "$NAME" # Output the distribution's name + else # If the file does not exist or is not readable + printf "%s" "File os-release not found or not readable" # Output error message + exit 1 # Exit with error code 1 + fi } # The get_package_manager function will take the output of the get_distro function and determine # which is the package manager used for the most popular server distros and exit if it is not found. function get_package_manager { - local distro # Declare distro as a local variable - distro="$(get_distro)" # Get the distribution name - case "$distro" in # Use case to check for the distribution name - "Ubuntu" | "Debian GNU/Linux") # If the distribution is Ubuntu or Debian - printf "%s" "apt" # Output apt - ;; - "CentOS Linux" | "Fedora" | "Red Hat Enterprise Linux Server") # If the distribution is CentOS, Fedora or RHEL - printf "%s" "dnf" # Output dnf - ;; - - "openSUSE Leap") # If the distribution is OpenSUSE - printf "%s" "zypper" # Output zypper - ;; - *) - # If the distribution is none of the above, output unsupported distribution - # and exit with error code 1 - printf "%s" "Unsupported distribution" - exit 1 # Exit with error code 1 - ;; - esac + local distro # Declare distro as a local variable + distro="$(get_distro)" # Get the distribution name + case "$distro" in # Use case to check for the distribution name + "Ubuntu" | "Debian GNU/Linux") # If the distribution is Ubuntu or Debian + printf "%s" "apt" # Output apt + ;; + "CentOS Linux" | "Fedora" | "Red Hat Enterprise Linux Server") # If the distribution is CentOS, Fedora or RHEL + printf "%s" "dnf" # Output dnf + ;; + "openSUSE Leap") # If the distribution is OpenSUSE + printf "%s" "zypper" # Output zypper + ;; + *) + # If the distribution is none of the above, output unsupported distribution + # and exit with error code 1 + printf "%s" "Unsupported distribution" + exit 1 # Exit with error code 1 + ;; + esac } # The install_packages function will take the output of the get_package_manager function and install any # package passed as an argument to it. It will also check if the package manager is known and exit if it is not. function install_packages { - 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 - "apt") # If the package manager is apt + 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 + "apt") # If the package manager is apt printf "%s" 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections - export DEBIAN_FRONTEND=noninteractive + export DEBIAN_FRONTEND=noninteractive 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 - ;; - "dnf") # If the package manager is dnf + sudo -E apt install -y "$@" # 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 - ;; - "zypper") # If the package manager is zypper + sudo dnf install -y "$@" # 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 - ;; - *) - # If the package manager is not one of the above, output unsupported package manager - # and exit with error code 1 - printf "%s" "Unsupported package manager" - exit 1 # Exit with error code 1 - ;; - esac + sudo zypper install -y "$@" # Install the packages passed as arguments + ;; + *) + # If the package manager is not one of the above, output unsupported package manager + # and exit with error code 1 + printf "%s" "Unsupported package manager" + exit 1 # Exit with error code 1 + ;; + esac } # The check_dependencies function will check if the dependencies defined in a local array are not installed # and store the ones that are indeed absent in another local array. # Then it will install the packages that are missing by invoking the install_packages function. function check_dependencies { # systemd-container is for machinectl - local dependencies=(fuse-overlayfs dbus-user-session uidmap slirp4netns systemd-container at htop curl git sudo vim ssh wget fail2ban) # Declare dependencies as a local array - #> see what to do with name differences between distros if any <# - local missing_dependencies=() # Declare missing_dependencies as a local array - for dependency in "${dependencies[@]}"; do # Loop through the dependencies array - # If the dependency is not installed, add it to the missing_dependencies array - ! command -v "$dependency" &> /dev/null && missing_dependencies+=("$dependency") - done - # If the missing_dependencies array is not empty, install the packages - [[ ${#missing_dependencies[@]} -ne 0 ]] && install_packages "${missing_dependencies[@]}" + local dependencies=(fuse-overlayfs dbus-user-session uidmap slirp4netns systemd-container at htop curl git sudo vim ssh wget fail2ban) # Declare dependencies as a local array + #> see what to do with name differences between distros if any <# + local missing_dependencies=() # Declare missing_dependencies as a local array + for dependency in "${dependencies[@]}"; do # Loop through the dependencies array + # If the dependency is not installed, add it to the missing_dependencies array + ! command -v "$dependency" &> /dev/null && missing_dependencies+=("$dependency") + done + # If the missing_dependencies array is not empty, install the packages + [[ ${#missing_dependencies[@]} -ne 0 ]] && install_packages "${missing_dependencies[@]}" } # Global array of the service names to be restarted @@ -130,95 +129,93 @@ services=() # - Disable agent forwarding to prevent ssh-agent hijacking # Then it will store the sshd service name in the services array. function hardenSSH { - # Check if the sshd_config file exists and is readable - # If it is, then modify it using sed and restart the sshd service - # If it is not, then output an error message and exit with error code 1 - # The -i flag is used to modify the file in place - # We split the sed command into multiple lines for readability purposes - # and to avoid calling it multiple times - if [[ -e /etc/ssh/sshd_config ]] && [[ -r /etc/ssh/sshd_config ]]; then - sudo sed -i \ - -e 's/^#AllowGroups.*/AllowGroups sudo/' \ - -e 's/^#Port.*/Port 22100/' \ - -e 's/^#ClientAliveInterval.*/ClientAliveInterval 300/' \ - -e 's/^#ClientAliveCountMax.*/ClientAliveCountMax 3/' \ - -e 's/^#PermitRootLogin.*/PermitRootLogin no/' \ - -e 's/^#PermitEmptyPasswords.*/PermitEmptyPasswords no/' \ - -e 's/^#Protocol.*/Protocol 2/' \ - -e 's/^#PasswordAuthentication.*/PasswordAuthentication no/' \ - -e 's/^#X11Forwarding.*/X11Forwarding no/' \ - -e 's/^X11Forwarding.*/X11Forwarding no/' \ - -e 's/^#AllowAgentForwarding.*/AllowAgentForwarding no/' \ - /etc/ssh/sshd_config - services+=("sshd") # Add sshd to the services array - else - printf "%s" "File sshd_config not found or not readable" - exit 1 - fi + # Check if the sshd_config file exists and is readable + # If it is, then modify it using sed and restart the sshd service + # If it is not, then output an error message and exit with error code 1 + # The -i flag is used to modify the file in place + # We split the sed command into multiple lines for readability purposes + # and to avoid calling it multiple times + if [[ -e /etc/ssh/sshd_config ]] && [[ -r /etc/ssh/sshd_config ]]; then + sudo sed -i \ + -e 's/^#AllowGroups.*/AllowGroups sudo/' \ + -e 's/^#Port.*/Port 22100/' \ + -e 's/^#ClientAliveInterval.*/ClientAliveInterval 300/' \ + -e 's/^#ClientAliveCountMax.*/ClientAliveCountMax 3/' \ + -e 's/^#PermitRootLogin.*/PermitRootLogin no/' \ + -e 's/^#PermitEmptyPasswords.*/PermitEmptyPasswords no/' \ + -e 's/^#Protocol.*/Protocol 2/' \ + -e 's/^#PasswordAuthentication.*/PasswordAuthentication no/' \ + -e 's/^#X11Forwarding.*/X11Forwarding no/' \ + -e 's/^X11Forwarding.*/X11Forwarding no/' \ + -e 's/^#AllowAgentForwarding.*/AllowAgentForwarding no/' \ + /etc/ssh/sshd_config + services+=("sshd") # Add sshd to the services array + else + printf "%s" "File sshd_config not found or not readable" + exit 1 + fi } function getCorrectFirewall { - local distro # Declare distro as a local variable - distro="$(get_distro)" # Get the distribution name - case "$distro" in # Use case to check for the distribution name - "Ubuntu" | "Debian GNU/Linux") # If the distribution is Ubuntu or Debian + local distro # Declare distro as a local variable + distro="$(get_distro)" # Get the distribution name + case "$distro" in # Use case to check for the distribution name + "Ubuntu" | "Debian GNU/Linux") # If the distribution is Ubuntu or Debian printf "%s" 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections - export DEBIAN_FRONTEND=noninteractive + export DEBIAN_FRONTEND=noninteractive export NEEDRESTART_MODE=a export DEBIAN_PRIORITY=critical sudo -E apt install ufw -y # 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 + ;; + "CentOS Linux" | "Fedora" | "Red Hat Enterprise Linux Server") # If the distribution is CentOS, Fedora or RHEL + sudo dnf install firewalld -y # Install firewalld printf "%s" "firewalld" # Output firewalld - ;; + ;; - "openSUSE Leap") # If the distribution is OpenSUSE - sudo zypper install firewalld -y # Install firewalld + "openSUSE Leap") # If the distribution is OpenSUSE + sudo zypper install firewalld -y # Install firewalld printf "%s" "firewalld" # Output firewalld - ;; - *) - # If the distribution is none of the above, output unsupported distribution - # and exit with error code 1 - printf "%s" "Unsupported distribution" - exit 1 # Exit with error code 1 - ;; - esac - + ;; + *) + # If the distribution is none of the above, output unsupported distribution + # and exit with error code 1 + printf "%s" "Unsupported distribution" + exit 1 # Exit with error code 1 + ;; + esac } function getCorrectKernelSecurityModule { - local distro # Declare distro as a local variable - 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 + local distro # Declare distro as a local variable + 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 printf "%s" "apparmor" # Output apparmor - ;; + ;; "Debian GNU/Linux") # If the distribution is Debian printf "%s" 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections - export DEBIAN_FRONTEND=noninteractive + 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 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 + "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 printf "%s" "selinux" # Output selinux - ;; - - "openSUSE Leap") # If the distribution is OpenSUSE - sudo zypper install -t pattern apparmor -y # Install apparmor + ;; + "openSUSE Leap") # If the distribution is OpenSUSE + sudo zypper install -t pattern apparmor -y # Install apparmor printf "%s" "apparmor" # Output apparmor - ;; - *) - # If the distribution is none of the above, output unsupported distribution - # and exit with error code 1 - printf "%s" "Unsupported distribution" - exit 1 # Exit with error code 1 - ;; + ;; + *) + # If the distribution is none of the above, output unsupported distribution + # and exit with error code 1 + printf "%s" "Unsupported distribution" + exit 1 # Exit with error code 1 + ;; esac } @@ -320,11 +317,13 @@ EOF rm -f -- *.sha512 chmod a+rx runsc containerd-shim-runsc-v1 sudo mv runsc containerd-shim-runsc-v1 /home/secdep/bin + sudo chown secdep:secdep /home/secdep/bin/runsc + sudo chown secdep:secdep /home/secdep/bin/containerd-shim-runsc-v1 ) # Enable gVisor for docker by default while hardening the docker daemon.json file # The no-new-privileges option will prevent the docker daemon from gaining new privileges - # The runsc option --network=host and --ignore-cgroup will help with running runsc - # with rootless docker + # The runsc option --network=host and --ignore-cgroups=true will help with running runsc + # with rootless docker without much hassle sudo runuser - secdep -c 'mkdir -p /home/secdep/.config/docker' # "icc": false to disable inter-container communication, does not work without br_netfilter module loaded # and it is sometimes prohibited by the hosting provider @@ -339,7 +338,9 @@ EOF "path": "/home/secdep/bin/runsc", "runtimeArgs": [ "--network=host", -"--ignore-cgroups" +"--ignore-cgroups=true", +"--overlay2 all:memory", +"--rootless" ] } } @@ -489,7 +490,7 @@ EOF # Then it will output a message to the user and reboot the system in 2 minutes. function main { printf "%s" "$SCRIPT_NAME script started" - check_dependencies || exit 1 # Check dependencies and exit if it fails + check_dependencies || exit 1 # Check dependencies and exit if it fails printf "%s" "Dependencies installed" hardenSSH || exit 1 # Harden ssh and exit if it fails printf "%s" "SSH hardened" @@ -507,8 +508,8 @@ function main { printf "%s" "Services restarted and firewall enabled" 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 + 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 }