fix that damn sign!!!
This commit is contained in:
170
harden
170
harden
@@ -19,7 +19,7 @@ trap 'printf "Error on line %d with signal %s" "$LINENO" "$?"' ERR # Exit on err
|
||||
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##*/}"
|
||||
##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
|
||||
@@ -74,8 +74,12 @@ function install_packages {
|
||||
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
|
||||
sudo apt update # Update the package list
|
||||
sudo apt install -y "$@" # Install the packages passed as arguments
|
||||
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 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
|
||||
@@ -98,7 +102,7 @@ function install_packages {
|
||||
# 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=(curl git sudo vim ssh docker-ce docker.io docker docker-compose wget fail2ban) # Declare dependencies as a local array
|
||||
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
|
||||
#> 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
|
||||
@@ -132,7 +136,7 @@ function hardenSSH {
|
||||
# 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
|
||||
sed -i \
|
||||
sudo sed -i \
|
||||
-e 's/^#AllowGroups.*/AllowGroups sudo/' \
|
||||
-e 's/^#Port.*/Port 22100/' \
|
||||
-e 's/^#ClientAliveInterval.*/ClientAliveInterval 300/' \
|
||||
@@ -142,6 +146,7 @@ function hardenSSH {
|
||||
-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
|
||||
@@ -156,16 +161,20 @@ function getCorrectFirewall {
|
||||
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
|
||||
apt install ufw -y # Install ufw
|
||||
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
|
||||
dnf install firewalld -y # Install firewalld
|
||||
sudo dnf install firewalld -y # Install firewalld
|
||||
printf "%s" "firewalld" # Output firewalld
|
||||
;;
|
||||
|
||||
"openSUSE Leap") # If the distribution is OpenSUSE
|
||||
zypper install firewalld -y # Install firewalld
|
||||
sudo zypper install firewalld -y # Install firewalld
|
||||
printf "%s" "firewalld" # Output firewalld
|
||||
;;
|
||||
*)
|
||||
@@ -183,20 +192,24 @@ 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
|
||||
apt install apparmor-profiles apparmor-utils apparmor-profiles-extra -y # Install apparmor
|
||||
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
|
||||
apt install apparmor apparmor-utils auditd python3-apparmor -y # Install apparmor
|
||||
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
|
||||
dnf install selinux container-selinux -y # Install selinux
|
||||
sudo dnf install selinux container-selinux -y # Install selinux
|
||||
printf "%s" "selinux" # Output selinux
|
||||
;;
|
||||
|
||||
"openSUSE Leap") # If the distribution is OpenSUSE
|
||||
zypper install -t pattern apparmor -y # Install apparmor
|
||||
sudo zypper install -t pattern apparmor -y # Install apparmor
|
||||
printf "%s" "apparmor" # Output apparmor
|
||||
;;
|
||||
*)
|
||||
@@ -209,20 +222,18 @@ function getCorrectKernelSecurityModule {
|
||||
}
|
||||
|
||||
function firewallInit {
|
||||
local firewall
|
||||
firewall="$(getCorrectFirewall)" # Get the correct firewall
|
||||
case "$firewall" in
|
||||
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
|
||||
sudo ufw enable # Enable the firewall
|
||||
sudo systemctl enable --now ufw # Enable and start the firewall on boot
|
||||
;;
|
||||
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
|
||||
sudo firewall-cmd --reload # Reload the firewall
|
||||
;;
|
||||
*)
|
||||
printf "%s" "Unsupported firewall"
|
||||
@@ -232,8 +243,9 @@ function firewallInit {
|
||||
}
|
||||
|
||||
function kernelSecurityModuleInit {
|
||||
local kernelSecurityModule
|
||||
kernelSecurityModule="$(getCorrectKernelSecurityModule)" # Get the correct kernel security module
|
||||
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
|
||||
@@ -241,11 +253,12 @@ function kernelSecurityModuleInit {
|
||||
;;
|
||||
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
|
||||
## printf "%s" "{\"selinux-enabled\":true}" | sudo tee /etc/docker/daemon.json # Enable selinux in docker
|
||||
sudo setenforce 1 # Enforce selinux
|
||||
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
|
||||
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"
|
||||
@@ -256,13 +269,23 @@ function kernelSecurityModuleInit {
|
||||
|
||||
function dockerInit {
|
||||
# Add user to docker group to avoid using sudo when running docker commands
|
||||
sudo usermod -aG docker "$USER"
|
||||
##sudo usermod -aG docker "$USER"
|
||||
# Set up rootless docker
|
||||
sudo runuser - secdep -c 'curl -fsSL https://get.docker.com/rootless | sh'
|
||||
sudo runuser - secdep -c 'export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock'
|
||||
sudo runuser - secdep -c 'export PATH=/home/$USER/bin:$PATH'
|
||||
sudo runuser - secdep -c 'printf "%s\n" "export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock" >> "$HOME/.bashrc"'
|
||||
sudo runuser - secdep -c 'printf "%s\n" "export PATH=/home/$USER/bin:$PATH" >> "$HOME/.bashrc"'
|
||||
sudo runuser - secdep -c 'systemctl --user enable --now docker.service'
|
||||
sudo runuser - secdep -c 'sudo setcap cap_net_bind_service=ep "$(which rootlesskit)"'
|
||||
sudo runuser - secdep -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
|
||||
##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
|
||||
[[ -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' # 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
|
||||
# Loop through the dockerImages array
|
||||
@@ -270,49 +293,53 @@ function dockerInit {
|
||||
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 restar always option and the name of the docker image
|
||||
# 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_ADMIN option will add the NET_ADMIN capability to 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
|
||||
docker run -d --restart always --name "$dockerImage" --security-opt=no-new-privileges --cap-drop all --cap-add NET_ADMIN --read-only --tmpfs /opt --network dockerNetworkNoICC "$dockerImage"
|
||||
/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
|
||||
}
|
||||
# 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
|
||||
}
|
||||
# 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 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'
|
||||
@@ -360,7 +387,26 @@ 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
|
||||
#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
|
||||
# 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.
|
||||
@@ -371,14 +417,16 @@ function main {
|
||||
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
|
||||
dockerInit || exit 1 # Initialize docker and exit if it fails
|
||||
apparmorConfig # Configure apparmor
|
||||
apparmorProfiles # Create apparmor profiles for all docker images
|
||||
selinuxConfig # Configure selinux
|
||||
## 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
|
||||
## [[ $# -gt 0 ]] && dockerInit "$@" || exit 1
|
||||
dockerInit "$@" || exit 1
|
||||
restartServices || exit 1
|
||||
printf "%s" "Script finished" # Output message to the user
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user