Files
SecDep/harden
2023-08-17 03:39:30 +03:00

598 lines
27 KiB
Bash
Executable File

#!/usr/bin/env bash
# Ensure bash path is found
# shellcheck source=/etc/os-release
# use shellcheck to declare which file to source
# Using set to make the script safer
set -e # Exit on error
set -u # Exit on undefined variable
set -x # Print commands for debugging
set -a # Export all variables
set -C # Disable overwriting of files
set -o pipefail # Exit on pipe error
# set -euxaCo pipefail # All options
# Use the built-in trap command to catch error lines and signal numbers
trap 'printf "Error on line %d with signal %s" "$LINENO" "$?"' ERR # Exit on error
# Also use trap to catch interrupt signals and exit cleanly with a message to the user and a return code
trap 'printf "Interrupted on line %d with signal %s" "$LINENO" "$?"' INT SIGHUP SIGINT SIGTERM
# Get script name using parameter expansion to not spawn a new subprocess
##SCRIPT_NAME="${0##*/}"
# We will be using printf instead of echo because it is more standardised.
# Also we will be using the test command's functionality as
# [[ because like this it constitutes a keyword and not a command.
# Functions will be defined as function "name" {body}" to make them
# more clear and () will not be used since using the keyword function renders them redundant
# We are taking for granted that the os-release file is in /etc as
# it has become a standard in most GNU/Linux distributions using systemd.
# We'll be using the -e flag just in case it is actually a symlink to another location.
# 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
}
# 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
}
# 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
echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
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 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 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
}
# 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 {
local dependencies=(fuse-overlayfs dbus-user-session uidmap slirp4netns docker-compose htop curl git sudo vim ssh wget fail2ban) # Declare dependencies as a local array
# local dependencies=(fuse-overlayfs dbus-user-session uidmap slirp4netns docker-compose dnsutils 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
services=()
# The hardenSSH function will use sed to modify the sshd_config file to have the following settings:
# - Allow ssh access to users in the sudo group only
# - Change the port to 22100 if it is available
# - Configure idle timeout to 5 minutes
# - Limit the number of authentication attempts to 3
# - Disable root login
# - Disable empty passwords
# - Disable ssh protocol 1
# - Disable password authentication and only allow public key authentication
# - Disable X11 forwarding for security reasons (X11 forwarding is not needed for ssh)
# - 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
}
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
echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
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
printf "%s" "firewalld" # Output 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
}
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
printf "%s" "apparmor" # Output apparmor
;;
"Debian GNU/Linux") # If the distribution is Debian
echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
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
printf "%s" "selinux" # Output selinux
;;
"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
;;
esac
}
function firewallInit {
getCorrectFirewall # Get the correct firewall installed
# Determine if ufw or firewalld is installed
whereis ufw | grep -q /ufw && currentFirewall="ufw" || currentFirewall="firewalld"
case "$currentFirewall" in
ufw)
sudo ufw default allow outgoing # Allow outgoing connections
sudo ufw default deny incoming # Deny incoming connections
sudo ufw allow 22100/tcp # Allow ssh connections on port 22100
;;
firewalld)
sudo systemctl enable --now firewalld # Enable the firewall on boot and start it
sudo firewall-cmd --permanent --add-port=22100/tcp # Allow ssh connections on port 22100
;;
*)
printf "%s" "Unsupported firewall"
exit 1
;;
esac
}
function kernelSecurityModuleInit {
getCorrectKernelSecurityModule # Get the correct kernel security module installed
# Determine if apparmor or selinux is installed
whereis apparmor | grep -q /apparmor && kernelSecurityModule="apparmor" || kernelSecurityModule="selinux"
case "$kernelSecurityModule" in
apparmor)
sudo systemctl enable --now apparmor # Enable the kernel security module on boot and start it
sudo aa-enforce /etc/apparmor.d/* # Enforce all apparmor profiles
;;
selinux)
sudo systemctl enable --now selinux # Enable the kernel security module on boot and start it
## printf "%s" "{\"selinux-enabled\":true}" | sudo tee /etc/docker/daemon.json # Enable selinux in docker
sudo setenforce 1 # Enforce selinux
sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config # Set selinux to enforcing
## sudo systemctl restart docker # Restart docker
## sudo restorecon -Rv /var/lib/docker # Restore the selinux context of the docker directory
## sudo restorecon -Rv /usr/bin # Restore the selinux context of the docker directory
;;
*)
printf "%s" "Unsupported kernel security module"
exit 1
;;
esac
}
# function getIP {
# RESOLVERS='@resolver4.opendns.com @resolver3.opendns.com @resolver2.opendns.com @resolver1.opendns.com'
# for resolver in $RESOLVERS ; do
# result="$(dig +short myip.opendns.com "$resolver")"
# rc="$?"
# if [ -n "$result" ] ; then
# printf "%s\n" "$result"
# exit "$rc"
# fi
# done
# }
function dockerInit {
# Add user to docker group to avoid using sudo when running docker commands
##sudo usermod -aG docker "$USER"
# Set up rootless docker
# sudo runuser - secdep -c 'curl -fsSL https://get.docker.com/rootless | sh'
# IP="$(getIP)"
# sudo su secdep << 'EOF'
#
# export XDG_RUNTIME_DIR=/run/user/$(id -u secdep)
# export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u secdep)/bus
# curl -fsSL https://get.docker.com/rootless | sh
# export DOCKER_HOST=unix:///run/user/$UID/docker.sock
# export PATH=/home/$USER/bin:$PATH
# printf "%s\n" "export PATH=/home/$USER/bin:$PATH" >> "$HOME/.bashrc"
# printf "%s\n" "export DOCKER_HOST=unix:///run/user/$UID/docker.sock" >> "$HOME/.bashrc"
# source "$HOME/.bashrc" && systemctl --machine=secdep@.host --user enable now docker.service
#
# EOF
# export XDG_RUNTIME_DIR=/run/user/$(id -u secdep)
# export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u secdep)/bus
sudo su secdep << 'EOF'
curl -fsSL https://get.docker.com/rootless | sh
export DOCKER_HOST=unix:///run/user/$UID/docker.sock
export PATH=/home/$USER/bin:$PATH
printf "%s\n" "export PATH=/home/$USER/bin:$PATH" >> "$HOME/.bashrc"
printf "%s\n" "export DOCKER_HOST=unix:///run/user/$UID/docker.sock" >> "$HOME/.bashrc"
EOF
# sudo -u secdep bash -c 'curl -fsSL https://get.docker.com/rootless | sh'
# sudo touch /etc/profile.d/docker.sh
# sudo echo '[[ -S /run/user/${UID}/docker.sock ]] && { export XDG_RUNTIME_DIR=/run/user/${UID} export PATH=/usr/bin:$PATH export DOCKER_HOST=unix:///run/user/${UID}/docker.sock; }' | sudo tee -a /etc/profile.d/docker.sh
sudo runuser - secdep -c 'mkdir -p "/home/secdep/.config/systemd/user"'
sudo runuser - secdep -c 'mkdir -p "/home/secdep/.config/systemd/default.target.wants"'
sudo runuser - secdep -c 'touch "/home/secdep/.config/systemd/user/docker.service"'
# sudo runuser - secdep -c 'cat <<- EOT > "/home/secdep/.config/systemd/user/docker.service"
sudo runuser - secdep -c 'cat << EOF > "/home/secdep/.config/systemd/user/docker.service"
[Unit]
Description=Docker Application Container Engine (Rootless)
Documentation=https://docs.docker.com/go/rootless/
[Service]
Environment=PATH=/home/secdep/bin:/sbin:/usr/sbin:/home/secdep/bin:/home/secdep/bin:/home/secdep/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/secdep/bin/dockerd-rootless.sh
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
Type=notify
NotifyAccess=all
KillMode=mixed
[Install]
WantedBy=default.target
EOF'
sudo runuser - secdep -c 'ln -s "/home/secdep/.config/systemd/user/docker.service" "/home/secdep/.config/systemd/default.target.wants/docker.service"'
# sudo su secdep << 'EOF'
# export XDG_RUNTIME_DIR=/run/user/$(id -u secdep)
# export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u secdep)/bus
# systemctl --machine=secdep@.host --user daemon-reload
# systemctl --machine=secdep@.host --user enable --now docker.service
# EOF
id=$(id -u secdep)
sudo mkdir -p /run/user/"$id"
sudo chown secdep /run/user/"$id"
sudo systemctl start user@"$id"
sudo loginctl enable-linger secdep
sudo setcap cap_net_bind_service=ep /home/secdep/bin/rootlesskit
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/"$id"/bus
export XDG_RUNTIME_DIR=/run/user/"id"
sudo -E su secdep << 'EOF'
systemctl --user daemon-reload
systemctl --user enable --now docker.service
EOF
# sudo su secdep << EOF
# export XDG_RUNTIME_DIR=/run/user/$(id -u secdep)
# export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u secdep)/bus
# systemctl --host secdep@$IP daemon-reload
# systemctl --host secdep@$IP enable --now docker.service
# EOF
# sudo runuser - secdep -c 'mkdir -p "/home/secdep/.docker/run"'
# sudo runuser - secdep -c 'bash /home/secdep/bin/dockerd-rootless-setuptool.sh install'
# sudo runuser - secdep -c 'mkdir -p "/home/secdep/.config/systemd/user"'
# sudo runuser - secdep -c 'cat <<- EOT > "/home/secdep/.config/systemd/user/docker.service"
# [Unit]
# Description=Docker Application Container Engine (Rootless)
# Documentation=https://docs.docker.com/go/rootless/
# [Service]
# Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
# ExecStart=$BIN/dockerd-rootless.sh $DOCKERD_ROOTLESS_SH_FLAGS
# ExecReload=/bin/kill -s HUP \$MAINPID
# TimeoutSec=0
# RestartSec=2
# Restart=always
# StartLimitBurst=3
# StartLimitInterval=60s
# LimitNOFILE=infinity
# LimitNPROC=infinity
# LimitCORE=infinity
# TasksMax=infinity
# Delegate=yes
# Type=notify
# NotifyAccess=all
# KillMode=mixed
# [Install]
# WantedBy=default.target
# EOT
# '
# sudo runuser - secdep -c 'systemctl --user -M secdep@ daemon-reload'
#sudo runuser - secdep -c 'export XDG_RUNTIME_DIR=/run/user/$UID'
# sudo -u secdep bash -c 'export DOCKER_HOST=unix:///run/user/$UID/docker.sock'
# sudo -u secdep bash -c 'export PATH=/home/$USER/bin:$PATH'
# sudo -u secdep bash -c 'printf "%s\n" "export DOCKER_HOST=unix:///run/user/$UID/docker.sock" >> "$HOME/.bashrc"'
# sudo -u secdep bash -c 'printf "%s\n" "export PATH=/home/$USER/bin:$PATH" >> "$HOME/.bashrc"'
# sudo -u secdep bash -c 'source "$HOME/.bashrc" && systemctl --user start docker.service'
# sudo runuser - secdep -c 'systemctl --user -M secdep@ enable --now docker.service'
# sudo loginctl enable-linger secdep
# sudo setcap cap_net_bind_service=ep /home/secdep/bin/rootlesskit
# sudo runuser - secdep -c "systemctl --host secdep@$IP --user restart docker.service"
# sudo runuser - secdep -c "systemctl --machine=secdep@.host --user restart docker.service"
# sudo runuser - secdep -c 'sudo setcap cap_net_bind_service=ep "$(which rootlesskit)"'
# sudo -u secdep bash -c 'systemctl --user restart docker.service'
# Create a new docker network to dissalow communication between containers
##sudo docker network create --driver bridge -o "com.docker.network.bridge.enable_icc"="false" dockerNetworkNoICC
# Get all arguments passed to the function and store them in the dockerImages array
local dockerImages=("$@")
# Check if there is a docker-compose.yml file in the user's home directory
sudo -u secdep bash -c '[[ -f "$HOME/docker-compose.yml" ]] && docker-compose -f "$HOME/docker-compose.yml" up -d' # If there is, run it
# sudo runuser - secdep -c '[[ -f "$HOME/docker-compose.yml" ]] && docker-compose -f "$HOME/docker-compose.yml" up -d' || return 0 # If there is, run it
# Check if the dockerImages array is empty and return 0 if it is
[[ "${#dockerImages[@]}" -eq 0 ]] && return 0
ID=$(id -u secdep)
# Loop through the dockerImages array
# The dockerImages array contains all the docker images to install and run
for dockerImage in "${dockerImages[@]}"; do
# No need to pull the docker image as the run command will do it automatically
# Run the docker image in the background,
# with the restart always option and the name of the docker image
# The --security-opt=no-new-privileges option will prevent the docker image from gaining new privileges
# The --cap-drop all option will drop all capabilities from the docker image
# The --cap-add NET_BIND_SERVICE option will add the NET_BIND_SERVICE capability to the docker image
# The --read-only option will mount the docker image as read-only
# The --tmpfs /opt option will mount the /opt directory as a tmpfs
# The --network dockerNetworkNoICC option will connect the docker image to the dockerNetworkNoICC network
# The -v /:/host option will enable the docker rootless mode
# # The --user secdep option will run the docker image as the secdep user to prevent privilege escalation
sudo -u secdep bash -c 'mkdir -p /home/secdep/opt'
CMD="docker run -d --restart always --name $dockerImage --security-opt=no-new-privileges --cap-drop all --cap-add NET_BIND_SERVICE --read-only --tmpfs /home/secdep/opt -v /run/user/$ID/docker.sock:/home/secdep/.docker/run/docker.sock $dockerImage"
# CMD="docker run -d --restart always --name \"$dockerImage\" --security-opt=no-new-privileges --cap-drop all --cap-add NET_BIND_SERVICE --read-only --tmpfs /home/secdep/opt -v /:/host \"$dockerImage\""
# sudo -u secdep bash -c "$CMD"
sudo runuser - secdep -c "$CMD"
# /home/secdep/bin/docker run -d --restart always --name "$dockerImage" --security-opt=no-new-privileges --cap-drop all --cap-add NET_BIND_SERVICE --read-only --tmpfs /opt -v /:/host "$dockerImage"
##docker run -d --restart always --name "$dockerImage" --security-opt=no-new-privileges --cap-drop all --cap-add NET_BIND_SERVICE --read-only --tmpfs /opt -v /:/host --network dockerNetworkNoICC "$dockerImage"
#docker run -d --restart always --name "$dockerImage" --security-opt=no-new-privileges --cap-drop all --cap-add NET_ADMIN --user secdep "$dockerImage"
done
}
# The apparmorConfig function will set up and configure apparmor with sane defaults.
# function apparmorConfig {
# # Create a new apparmor profile for the docker daemon
# sudo aa-genprof docker
# # Enable the apparmor profile for the docker daemon
# sudo aa-enforce docker
# # Reload the apparmor profiles
# sudo systemctl reload apparmor
# }
# The selinuxConfig function will set up and configure selinux with sane defaults.
# function selinuxConfig {
# # Set the selinux boolean to allow docker to use the network
# sudo setsebool -P docker_connect_any 1
# }
# This function will create a new apparmor profile for every docker image installed on the system.
# function apparmorProfiles {
# # Get all the docker images installed on the system and store them in the dockerImages array
# local dockerImages=("$(docker images --format "{{.Repository}}")")
# # Loop through the dockerImages array
# for dockerImage in "${dockerImages[@]}"; do
# # Create a new apparmor profile for the docker image
# sudo aa-genprof "$dockerImage"
# # Enable the apparmor profile for the docker image
# sudo aa-enforce "$dockerImage"
# done
# # Reload the apparmor profiles
# sudo systemctl reload apparmor
# }
function configureFail2ban {
FAIL2BAN_LOCAL=$(cat <<'EOF'
[Definition]
logtarget = /var/log/fail2ban/fail2ban.log
allowipv6 = auto
EOF
)
printf "%s" "$FAIL2BAN_LOCAL" | sudo tee /etc/fail2ban/fail2ban.local
FAIL2BAN_SSH_JAIL_LOCAL=$(cat <<'EOF'
[sshd]
enabled = true
filter = sshd
banaction = ufw
backend = systemd
maxretry = 3
# 3 failed attempts in 600 seconds = 10 minutes
findtime = 1d
bantime = 1d
ignoreip = 127.0.0.1/8
EOF
)
printf "%s" "$FAIL2BAN_SSH_JAIL_LOCAL" | sudo tee /etc/fail2ban/jail.local/sshd.local
FAIL2BAN_FILTER=$(cat <<'EOF'
[Definition]
failregex = ^.*DROP_.*SRC=<ADDR> DST=.*$
journalmatch = _TRANSPORT=kernel
EOF
)
printf "%s" "$FAIL2BAN_FILTER" | sudo tee /etc/fail2ban/filter.d/fwdrop.local
HARDEN_FAIL2BAN_SERVICE=$(cat <<'EOF'
[Service]
PrivateDevices=yes
PrivateTmp=yes
ProtectHome=read-only
ProtectSystem=strict
ReadWritePaths=-/var/run/fail2ban
ReadWritePaths=-/var/lib/fail2ban
ReadWritePaths=-/var/log/fail2ban
ReadWritePaths=-/var/spool/postfix/maildrop
ReadWritePaths=/run/xtables.lock
CapabilityBoundingSet=CAP_AUDIT_READ CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW
EOF
)
printf "%s" "$HARDEN_FAIL2BAN_SERVICE" | sudo tee /etc/systemd/system/fail2ban.service.d/override.conf
sudo systemctl enable --now fail2ban
printf "%s" "LogLevel VERBOSE" | sudo tee -a /etc/ssh/sshd_config
#sudo systemctl restart sshd
}
function restartServices {
for service in "${services[@]}"; do
sudo systemctl restart "$service"
done
# command -v ufw >/dev/null 2>&1 && currentFirewall="ufw" || currentFirewall="firewalld"
whereis ufw | grep -q /ufw && currentFirewall="ufw" || currentFirewall="firewalld"
# For ufw
# Enable the firewall
# Enable and start the firewall on boot
[[ "$currentFirewall" == "ufw" ]] && sudo ufw enable && sudo systemctl enable --now ufw
# For firewalld
# Reload the firewall
[[ "$currentFirewall" == "firewalld" ]] && sudo firewall-cmd --reload
sudo systemctl disable --now docker.service docker.socket
# sudo systemctl disable --now docker
# Make sure docker is disabled after
# installing docker-compose, to make sure
# only rootless docker is used
}
# The main function will call the check_dependencies function and exit if it fails.
# It will also output a message to the user to let them know that the script has finished.
function main {
check_dependencies || exit 1 # Check dependencies and exit if it fails
hardenSSH || exit 1 # Harden ssh and exit if it fails
firewallInit || exit 1 # Initialize the firewall and exit if it fails
kernelSecurityModuleInit || exit 1 # Initialize the kernel security module and exit if it fails
configureFail2ban || exit 1 # Initialize fail2ban and exit if it fails
## I should probably delete this one dockerInit || exit 1 # Initialize docker and exit if it fails
# apparmorConfig # Configure apparmor
# apparmorProfiles # Create apparmor profiles for all docker images
# selinuxConfig # Configure selinux
# If number of arguments is greater than 0
# Call the dockerInit function with the arguments passed to the script
# Else exit with error code 1
## [[ $# -gt 0 ]] && dockerInit "$@" || exit 1
dockerInit "$@" || exit 1
restartServices || exit 1
printf "%s" "Script finished" # Output message to the user
}
# # The am_i_root function will check if the user is root and exit if they are not.
# function am_i_root {
# if [[ $EUID -ne 0 ]]; then # Check if the user is root
# printf "%s" "Please run as root" # Output message to the user
# exit 1 # Exit with error code 1
# fi
# }
# Call the main function
main "$@"
exit 0 # The right and proper way to exit a script