fix that damn sign!!!

This commit is contained in:
2023-08-09 15:52:44 +03:00
parent 7cbae4d58f
commit 6be027cf68
2 changed files with 126 additions and 66 deletions

170
harden
View File

@@ -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
}

View File

@@ -1127,6 +1127,9 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi
sudo chown secdep:secdep /home/secdep -R
sudo chmod 700 /home/secdep /home/secdep/.ssh
sudo chmod 600 /home/secdep/.ssh/authorized_keys'''
## Last two lines don't work
## sudo printf "%s\n" "secdep ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/secdepRules"
## sudo chmod 0440 "/etc/sudoers.d/secdepRules"'''
deploy = ScriptDeployment(script=SCRIPT, name="initialization.sh", delete=True)
if args.deploy:
actualDeployScript = ScriptFileDeployment(script_file=SECDEP_DEPLOY_SCRIPT, args=args.deploy, name="harden", delete=True)
@@ -1268,6 +1271,9 @@ def create_node(provider, name=None, location=None, size=None, image=None, confi
sudo chown secdep:secdep /home/secdep -R
sudo chmod 700 /home/secdep /home/secdep/.ssh
sudo chmod 600 /home/secdep/.ssh/authorized_keys'''
## Last two lines don't work
## sudo printf "%s\n" "secdep ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/secdepRules"
## sudo chmod 0440 "/etc/sudoers.d/secdepRules"'''
deploy = ScriptDeployment(script=SCRIPT, name="initialization.sh", delete=True)
if args.deploy:
actualDeployScript = ScriptFileDeployment(script_file=SECDEP_DEPLOY_SCRIPT, args=args.deploy, name="harden", delete=True)
@@ -1324,7 +1330,10 @@ def list_all_nodes(provider, filterIn=None, awsRegion=None):
if len(azureNodes) > 0:
for node in azureNodes:
nodes.append(node)
console.print("[bold white]Loading %s%%...[/bold white]" % (int((2/providers_quantity)*100)))
if providers_quantity < 3:
console.print("[bold white]Loading %s%%...[/bold white]" % (int(((2/providers_quantity)/2)*100)))
else:
console.print("[bold white]Loading %s%%...[/bold white]" % (int((2/providers_quantity)*100)))
else:
console.print("Skipping azure", style="bold red")
if SECDEP_AWS_ACCESS_KEY != "":
@@ -1338,7 +1347,10 @@ def list_all_nodes(provider, filterIn=None, awsRegion=None):
if len(awsNodes) > 0:
for node in awsNodes:
nodes.append(node)
console.print("[bold white]Loading %s%%...[/bold white]" % (int((3/providers_quantity)*100)))
if providers_quantity < 3:
console.print("[bold white]Loading %s%%...[/bold white]" % (int((providers_quantity/providers_quantity)*100)))
else:
console.print("[bold white]Loading %s%%...[/bold white]" % (int((3/providers_quantity)*100)))
else:
console.print("Skipping aws", style="bold red")
status.stop()
@@ -1350,7 +1362,7 @@ def list_all_nodes(provider, filterIn=None, awsRegion=None):
if len(gceNodes) > 0:
for node in gceNodes:
nodes.append(node)
console.print("[bold white]Loading %s%%...[/bold white]" % (int((1/providers_quantity)*100)))
console.print("[bold white]Loading 100%...[/bold white]")
else:
console.print("Skipping gce", style="bold red")
status.stop()
@@ -1362,7 +1374,7 @@ def list_all_nodes(provider, filterIn=None, awsRegion=None):
if len(azureNodes) > 0:
for node in azureNodes:
nodes.append(node)
console.print("[bold white]Loading %s%%...[/bold white]" % (int((2/providers_quantity)*100)))
console.print("[bold white]Loading 100%...[/bold white]")
else:
console.print("Skipping azure", style="bold red")
status.stop()
@@ -1390,7 +1402,7 @@ def list_all_nodes(provider, filterIn=None, awsRegion=None):
if len(awsNodes) > 0:
for node in awsNodes:
nodes.append(node)
console.print("[bold white]Loading %s%%...[/bold white]" % (int((3/providers_quantity)*100)))
console.print("[bold white]Loading 100%...[/bold white]")
else:
console.print("Skipping aws", style="bold red")
status.stop()