I expected something different.
This commit is contained in:
@@ -37,11 +37,14 @@ That's where SecDep comes in 💪. With SecDep, you can manage your virtual mach
|
||||
- [x] Fail2ban installation and configuration
|
||||
- [x] Kernel Security Module installation (AppArmor or SELinux)
|
||||
- [x] Docker Rootless installation
|
||||
- [ ] gVisor installation and integration with Docker Rootless
|
||||
- [x] gVisor installation and integration with Docker Rootless
|
||||
- [x] CronJob to update the system periodically
|
||||
- [x] CronJob to allow or disallow docker ports
|
||||
- [x] Docker deployment during hardening
|
||||
- [x] Single docker-compose file deployment
|
||||
- [x] Pulling of multiple docker images
|
||||
- [x] Automatic portainer deployment
|
||||
- [x] Automatic watchtower deployment
|
||||
|
||||
# Prerequisites 📋
|
||||
|
||||
|
||||
173
harden
173
harden
@@ -383,10 +383,13 @@ EOF
|
||||
# which will be installed and run on port 9443 by default to make it easier to manage docker
|
||||
# url to follow after the installation is complete: https://vps_ip:9443
|
||||
# the https:// part is important as portainer will not work without it
|
||||
# For portainer, we will be using the --runtime=runc option to run it with runc because
|
||||
# For portainer (and watchtower), we will be using the --runtime=runc option to run it with runc because
|
||||
# it doesn't work with runsc as it is not exposing the docker socket to the container
|
||||
# but containers downloaded from it will still use runsc
|
||||
sudo -E runuser - secdep -c 'docker run --runtime=runc -d -p 8000:8000 -p 9443:9443 --name=portainer --restart=always -v /run/user/$UID/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce'
|
||||
# Watchtower is a docker image that will automatically update all the other docker images
|
||||
# that are installed and running so we don't have to do it manually
|
||||
sudo -E runuser - secdep -c 'docker run --runtime=runc -d --name watchtower --restart=always -v /run/user/$UID/docker.sock:/var/run/docker.sock containrrr/watchtower --cleanup --interval 3600'
|
||||
# Check if the dockerImages array is empty and return 0 if it is
|
||||
[[ "${#dockerImages[@]}" -eq 0 ]] && return 0
|
||||
# Loop through the dockerImages array
|
||||
@@ -486,6 +489,168 @@ EOF
|
||||
sudo at now + 1 minute <<< "bash /root/delete_users.sh"
|
||||
}
|
||||
|
||||
function dynamicDockerPortsCronjob {
|
||||
sudo mkdir -p /root/bin
|
||||
cat << 'TOHERE' | sudo tee /root/bin/dynamic_docker_ports_cronjob.sh
|
||||
#!/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")"
|
||||
# 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' ' '"
|
||||
# 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
|
||||
case "$currentFirewall" in
|
||||
ufw)
|
||||
NEW_PORTS="$(comm -23 <(printf "%s" "$CURRENT_DOCKER_PORTS") <(printf "%s" "$CURRENT_FIREWALL_PORTS_UFW_CMD"))"
|
||||
;;
|
||||
firewalld)
|
||||
NEW_PORTS="$(comm -23 <(printf "%s" "$CURRENT_DOCKER_PORTS") <(printf "%s" "$CURRENT_FIREWALL_PORTS_FIREWALLD_CMD"))"
|
||||
;;
|
||||
*)
|
||||
printf "%s" "Unsupported firewall"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
# Loop through the ports in the NEW_PORTS variable if it is not empty
|
||||
if [[ -n "$NEW_PORTS" ]]; then
|
||||
for port in $NEW_PORTS; do
|
||||
# Allow the port in the firewall
|
||||
case "$currentFirewall" in
|
||||
ufw)
|
||||
sudo ufw allow "$port"/tcp
|
||||
;;
|
||||
firewalld)
|
||||
sudo firewall-cmd --permanent --add-port="$port"/tcp
|
||||
;;
|
||||
*)
|
||||
printf "%s" "Unsupported firewall"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
# Find which ports are not used by docker but are allowed by the firewall
|
||||
case "$currentFirewall" in
|
||||
ufw)
|
||||
OLD_PORTS="$(comm -23 <(printf "%s" "$CURRENT_FIREWALL_PORTS_UFW_CMD") <(printf "%s" "$CURRENT_DOCKER_PORTS"))"
|
||||
;;
|
||||
firewalld)
|
||||
OLD_PORTS="$(comm -23 <(printf "%s" "$CURRENT_FIREWALL_PORTS_FIREWALLD_CMD") <(printf "%s" "$CURRENT_DOCKER_PORTS"))"
|
||||
;;
|
||||
*)
|
||||
printf "%s" "Unsupported firewall"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
# Loop through the ports in the OLD_PORTS variable if it is not empty
|
||||
if [[ -n "$OLD_PORTS" ]]; then
|
||||
for port in $OLD_PORTS; do
|
||||
# Deny the port in the firewall
|
||||
case "$currentFirewall" in
|
||||
ufw)
|
||||
sudo ufw deny "$port"/tcp
|
||||
;;
|
||||
firewalld)
|
||||
sudo firewall-cmd --permanent --remove-port="$port"/tcp
|
||||
;;
|
||||
*)
|
||||
printf "%s" "Unsupported firewall"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
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
|
||||
*/30 * * * * /root/bin/dynamic_docker_ports_cronjob.sh
|
||||
TOHERE
|
||||
sudo chmod +x /root/bin/dynamic_docker_ports_cronjob.sh
|
||||
sudo systemctl restart cron
|
||||
}
|
||||
|
||||
function automaticUpdatesCronjob {
|
||||
sudo mkdir -p /root/bin
|
||||
cat << 'TOHERE' | sudo tee /root/bin/automatic_updates_cronjob.sh
|
||||
#!/usr/bin/env bash
|
||||
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 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 {
|
||||
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 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
|
||||
;;
|
||||
"dnf") # If the package manager is dnf
|
||||
sudo dnf upgrade -y # Update the package list
|
||||
sudo dnf install -y
|
||||
;;
|
||||
"zypper") # If the package manager is zypper
|
||||
sudo zypper update -y # Update the package list
|
||||
sudo zypper install -y
|
||||
;;
|
||||
*)
|
||||
# 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
|
||||
}
|
||||
update_system
|
||||
TOHERE
|
||||
cat << TOHERE | sudo tee -a /var/spool/cron/crontabs/root
|
||||
# Every day at 4:00 AM update the system
|
||||
0 4 * * * /root/bin/automatic_updates_cronjob.sh
|
||||
TOHERE
|
||||
sudo chmod +x /root/bin/automatic_updates_cronjob.sh
|
||||
sudo systemctl restart cron
|
||||
}
|
||||
|
||||
# The main function will call the declared functions in order and exit if any of them fails.
|
||||
# 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.
|
||||
@@ -504,9 +669,13 @@ function main {
|
||||
# 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 along with any specified docker images from the command line or a docker-compose.yml file installed"
|
||||
printf "%s" "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"
|
||||
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"
|
||||
automaticUpdatesCronjob || exit 1 # Install a cronjob to update the system periodically
|
||||
printf "%s" "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
|
||||
|
||||
Reference in New Issue
Block a user