From 65885a41c6b8db8e906261ffcf623b050dae60d9 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 10:15:40 -0700 Subject: [PATCH 01/28] fix: target ssh if sshd.service can't be found - Made additional improvements to 'clean_exit' function. --- hardening/SSHD Hardening/harden-sshd.bash | 37 +++++++++++------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/hardening/SSHD Hardening/harden-sshd.bash b/hardening/SSHD Hardening/harden-sshd.bash index 52fcdbb..6694377 100755 --- a/hardening/SSHD Hardening/harden-sshd.bash +++ b/hardening/SSHD Hardening/harden-sshd.bash @@ -20,18 +20,16 @@ readonly C_CONFIG_FILE_BAK="/etc/ssh/sshd_config.bak" readonly C_CONFIG_FILE="/etc/ssh/sshd_config" -## Used to colorize output. C_YELLOW="$(printf '\033[1;33m')" C_GREEN="$(printf '\033[0;32m')" C_BLUE="$(printf '\033[0;34m')" C_CYAN="$(printf '\033[0;36m')" C_RED="$(printf '\033[1;31m')" C_NC="$(printf '\033[0m')" -readonly C_GREEN C_CYAN C_RED C_NC +readonly C_YELLOW C_GREEN C_BLUE C_CYAN C_RED C_NC -## Short-hand colorized messages. -readonly C_SUCCESS="${C_GREEN}==>${C_NC} " readonly C_WARNING="${C_YELLOW}==>${C_NC} " +readonly C_SUCCESS="${C_GREEN}==>${C_NC} " readonly C_ERROR="${C_RED}ERROR:${C_NC} " readonly C_INFO="${C_BLUE}==>${C_NC} " readonly C_NOTE="${C_CYAN}==>${C_NC} " @@ -89,16 +87,12 @@ readonly C_SSHD_CONFIG clean_exit() { local exit_code="$1" - # Unset the EXIT trap to prevent re-entry. - trap - EXIT - case "$exit_code" in - 0) ;; - 1) echo "" ;; - 129) echo -e "\n${C_WARNING}Hangup signal detected (SIGHUP)" ;; - 130) echo -e "\n${C_WARNING}User interrupt detected (SIGINT)" ;; - 143) echo -e "\n${C_WARNING}Termination signal detected (SIGTERM)" ;; - *) echo -e "\n${C_WARNING}Exiting with code: $exit_code" ;; + 0|1) echo "" ;; + 129) echo -e "\n\n${C_WARNING}Hangup signal detected (SIGHUP)" ;; + 130) echo -e "\n\n${C_WARNING}User interrupt detected (SIGINT)" ;; + 143) echo -e "\n\n${C_WARNING}Termination signal detected (SIGTERM)" ;; + *) echo -e "\n\n${C_WARNING}Exiting with code: $exit_code" ;; esac echo "Exiting..." @@ -112,14 +106,13 @@ clean_exit() { trap 'clean_exit 129' SIGHUP trap 'clean_exit 130' SIGINT trap 'clean_exit 143' SIGTERM -trap 'clean_exit $?' EXIT ####[ Prepping ]######################################################################## ## Check if the script was executed with root privilege. -if [[ $EUID != 0 ]]; then +if (( EUID != 0 )); then echo "${C_ERROR}This script requires root privilege" >&2 exit 1 fi @@ -204,15 +197,19 @@ done ### [ Finalizing ] ### -echo -e "\n${C_INFO}Restarting sshd..." -systemctl restart sshd || { - echo "${C_ERROR}Failed to restart sshd" >&2 +echo -e "\n${C_INFO}Restarting SSH service..." +if systemctl restart sshd 2>/dev/null; then + echo "${C_SUCCESS}SSH service (sshd) restarted successfully" +elif systemctl restart ssh 2>/dev/null; then + echo "${C_SUCCESS}SSH service (ssh) restarted successfully" +else + echo "${C_ERROR}Failed to restart SSH service (tried both 'sshd' and 'ssh')" >&2 + echo "${C_NOTE}You may need to restart the SSH service manually" exit 1 -} +fi echo -e "\n${C_SUCCESS}Finished hardening sshd" echo -e "${C_NOTE}It is highly recommended to manually:" echo -e "${C_NOTE} 1) Change the default sshd port (22)" echo -e "${C_NOTE} 2) Disable PasswordAuthentication in favor of PubkeyAuthentication" echo -e "${C_NOTE} 3) Add 'AllowUsers [your username]' to the bottom of 'sshd_config'" - From 2b166ac833d081466923592ac1d0a4ed7d74f6f2 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 11:37:07 -0700 Subject: [PATCH 02/28] feat(harden-sshd): restore original config file if an error occurs --- hardening/SSHD Hardening/harden-sshd.bash | 68 +++++++++++++++++------ 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/hardening/SSHD Hardening/harden-sshd.bash b/hardening/SSHD Hardening/harden-sshd.bash index 6694377..c0b4b12 100755 --- a/hardening/SSHD Hardening/harden-sshd.bash +++ b/hardening/SSHD Hardening/harden-sshd.bash @@ -1,22 +1,24 @@ #!/bin/bash # -# This script hardens the ssh server by modifying its configuration file, 'sshd_config'. +# Harden the ssh server by modifying its configuration file with the recommended settings +# outlined by the security auditing tool known as Lynis (https://github.com/CISOfy/lynis). # # NOTE: -# These configurations align with the recommendations of the security auditing tool -# known as Lynis (https://github.com/CISOfy/lynis). +# - Two types of backups are created: +# - Permanent backup (.bak): For manual user restoration and reference. +# - Session backup (.session_backup): For automatic script restoration during +# interruptions. # -# TODO: -# - Impliment functionality to revert changes if the script fails. -# -# Version: v2.0.2 +# Version: v2.1.0 # License: MIT License -# Copyright (c) 2020-2024 Hunter T. (StrangeRanger) +# Copyright (c) 2020-2025 Hunter T. (StrangeRanger) # ######################################################################################## ####[ Global Variables ]################################################################ +C_TMP_DIR=$(mktemp -d); readonly C_TMP_DIR +readonly C_SESSION_BACKUP="$C_TMP_DIR/sshd_config.session_backup" readonly C_CONFIG_FILE_BAK="/etc/ssh/sshd_config.bak" readonly C_CONFIG_FILE="/etc/ssh/sshd_config" @@ -75,12 +77,15 @@ declare -A C_SSHD_CONFIG=( ) readonly C_SSHD_CONFIG +modifications_in_progress=false + ####[ Functions ]####################################################################### #### -# Exit the script and display a message based on the exit code. +# Cleanly exit the script by removing temporary files, restoring backups if needed, and +# displaying a message based on the exit code. # # PARAMETERS: # - $1: exit_code (Required) @@ -95,7 +100,26 @@ clean_exit() { *) echo -e "\n\n${C_WARNING}Exiting with code: $exit_code" ;; esac - echo "Exiting..." + # Check if we need to restore (modifications were in progress). + if [[ $modifications_in_progress == true ]] && [[ -f "$C_SESSION_BACKUP" ]]; then + echo "${C_WARNING}Script was interrupted during configuration changes" + echo "${C_INFO}Restoring original 'sshd_config'..." + if cp "$C_SESSION_BACKUP" "$C_CONFIG_FILE"; then + echo "${C_SUCCESS}Successfully restored original configuration" + echo "${C_INFO}Cleaning up..." + [[ -d "$C_TMP_DIR" ]] && rm -rf "$C_TMP_DIR" + else + echo "${C_ERROR}Failed to restore 'sshd_config'" >&2 + echo "${C_NOTE}Session backup is available at: $C_SESSION_BACKUP" + echo "${C_NOTE}Permanent backup is available at: $C_CONFIG_FILE_BAK" + echo "${C_NOTE}Temp directory preserved for manual recovery: $C_TMP_DIR" + fi + else + echo "${C_INFO}Cleaning up..." + [[ -d "$C_TMP_DIR" ]] && rm -rf "$C_TMP_DIR" + fi + + echo "${C_INFO}Exiting..." exit "$exit_code" } @@ -137,14 +161,12 @@ read -rp "${C_NOTE}We will now harden sshd. Press [Enter] to continue." if [[ -f $C_CONFIG_FILE_BAK ]]; then printf "%sA backup of 'sshd_config' already exists. " "$C_NOTE" read -rp "Do you want to overwrite it? [y/N] " choice - choice="${choice,,}" + choice="${choice,,}" case "$choice" in y*) echo "${C_INFO}Overwriting backup of 'sshd_config'..." - { - rm $C_CONFIG_FILE_BAK && cp $C_CONFIG_FILE $C_CONFIG_FILE_BAK - } || { + cp $C_CONFIG_FILE $C_CONFIG_FILE_BAK || { echo "${C_ERROR}Failed to overwrite backup of 'sshd_config'" >&2 exit 1 } @@ -157,18 +179,25 @@ if [[ -f $C_CONFIG_FILE_BAK ]]; then unset choice else echo "${C_INFO}Backing up 'sshd_config'..." - cp $C_CONFIG_FILE $C_CONFIG_FILE_BAK || { + cp "$C_CONFIG_FILE" "$C_CONFIG_FILE_BAK" || { echo "${C_ERROR}Failed to back up sshd_config" >&2 - echo "${C_NOTE}Please create a backup of the original 'sshd_config' before" \ - "continuing" + echo "${C_NOTE}Create a backup of the original 'sshd_config' file before continuing" exit 1 } fi +echo "${C_INFO}Creating session backup for safe restoration..." +cp "$C_CONFIG_FILE" "$C_SESSION_BACKUP" || { + echo "${C_ERROR}Failed to create session backup" >&2 + clean_exit 1 +} + ### ### [ Harden 'sshd_config' ] ### +modifications_in_progress=true + for key in "${!C_SSHD_CONFIG[@]}"; do # Skip processing Regex keys directly. if [[ "$key" =~ Regex$ ]]; then @@ -197,6 +226,8 @@ done ### [ Finalizing ] ### +modifications_in_progress=false + echo -e "\n${C_INFO}Restarting SSH service..." if systemctl restart sshd 2>/dev/null; then echo "${C_SUCCESS}SSH service (sshd) restarted successfully" @@ -205,7 +236,6 @@ elif systemctl restart ssh 2>/dev/null; then else echo "${C_ERROR}Failed to restart SSH service (tried both 'sshd' and 'ssh')" >&2 echo "${C_NOTE}You may need to restart the SSH service manually" - exit 1 fi echo -e "\n${C_SUCCESS}Finished hardening sshd" @@ -213,3 +243,5 @@ echo -e "${C_NOTE}It is highly recommended to manually:" echo -e "${C_NOTE} 1) Change the default sshd port (22)" echo -e "${C_NOTE} 2) Disable PasswordAuthentication in favor of PubkeyAuthentication" echo -e "${C_NOTE} 3) Add 'AllowUsers [your username]' to the bottom of 'sshd_config'" + +clean_exit 0 From 87c9cad19dffd08a6e1c6369a968505b3259120c Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 11:42:22 -0700 Subject: [PATCH 03/28] style: use note color for 'already set' SSH config messages --- hardening/SSHD Hardening/harden-sshd.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardening/SSHD Hardening/harden-sshd.bash b/hardening/SSHD Hardening/harden-sshd.bash index c0b4b12..ca608ff 100755 --- a/hardening/SSHD Hardening/harden-sshd.bash +++ b/hardening/SSHD Hardening/harden-sshd.bash @@ -210,7 +210,7 @@ for key in "${!C_SSHD_CONFIG[@]}"; do ## Check if the key is already set to the desired value. if grep -Eq "^${key} ${C_SSHD_CONFIG[$key]}$" "$C_CONFIG_FILE"; then - echo "${C_SUCCESS}${key} already set to '${C_SSHD_CONFIG[$key]}'" + echo "${C_NOTE}${key} already set to '${C_SSHD_CONFIG[$key]}'" ## Check if the configurations are present in the file. elif grep -Eq "${C_SSHD_CONFIG[$regex_key]}" "$C_CONFIG_FILE"; then echo "${C_INFO}Setting '${key} ${C_SSHD_CONFIG[$key]}'..." From cef2e281ee6a7c6ffa4fcb952c908283850681ef Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 11:54:33 -0700 Subject: [PATCH 04/28] docs(CHANGELOG): update CHANGELOG with v2.1.0 changes --- hardening/SSHD Hardening/CHANGELOG.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/hardening/SSHD Hardening/CHANGELOG.md b/hardening/SSHD Hardening/CHANGELOG.md index 9ec38e4..6e5f5e7 100644 --- a/hardening/SSHD Hardening/CHANGELOG.md +++ b/hardening/SSHD Hardening/CHANGELOG.md @@ -2,7 +2,22 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## v2.1.0 - 2025-08-09 + +### Added + +- **Session backup system**: Automatic restoration during script interruptions with temporary backup preservation for manual recovery +- **Cross-platform SSH service restart**: Automatically detects and restarts either `sshd` or `ssh` service based on distribution +- **Enhanced signal handling**: Proper restoration and cleanup on script interruption (SIGHUP, SIGINT, SIGTERM) + +### Changed + +- **Backup strategy**: Dual backup system with permanent `.bak` file for user reference and session backup for auto-restoration +- **Exit handling**: Strategic use of `clean_exit` function only when cleanup or restoration is needed +- **User messaging**: Enhanced feedback throughout backup, restoration, and cleanup processes +- **Output colors**: "Already set" messages now use note (cyan) instead of success (green) for better semantic clarity ## v2.0.2 - 2024-12-20 From b9eae0b71f926c1436476a1d0eaffa427ba06c76 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 12:07:00 -0700 Subject: [PATCH 05/28] docs(README): improve format and content of README --- README.md | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 129 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a5a8770..ea5d5df 100644 --- a/README.md +++ b/README.md @@ -4,26 +4,111 @@ [![Style Guide](https://img.shields.io/badge/code%20style-Style%20Guide-blueviolet)](https://github.com/StrangeRanger/bash-style-guide) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/598c2083cd6f432a910a315fd10aaa66)](https://www.codacy.com/gh/StrangeRanger/linux-security-scripts/dashboard?utm_source=github.com&utm_medium=referral&utm_content=StrangeRanger/linux-security-scripts&utm_campaign=Badge_Grade) -This repository is a collection of scripts designed to secure/harden Linux based Distributions. +This repository is a collection of scripts designed to secure/harden Linux-based distributions. + +
+Table of Contents + +- [Linux Security Scripts](#linux-security-scripts) + - [Tools and Scripts](#tools-and-scripts) + - [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Download and Setup](#download-and-setup) + - [Usage](#usage) + - [Quick Start](#quick-start) + - [Individual Script Usage](#individual-script-usage) + - [Post-Installation](#post-installation) + - [Tested On](#tested-on) + - [Troubleshooting](#troubleshooting) + - [Common Issues](#common-issues) + - [Other Resources](#other-resources) + - [Security Auditing Tools](#security-auditing-tools) + - [Additional Hardening Resources](#additional-hardening-resources) + - [System Monitoring](#system-monitoring) + - [Support and Issues](#support-and-issues) + - [License](#license) + +
+ +## Tools and Scripts + +Below is a list of tools included in this repository. + +| Tool Name | Description | Category | Requirements | Notes | +|-----------|-------------|----------|--------------|-------| +| **[Lynis Installer](auditing/Lynis%20Installer/lynis-installer.bash)** | Download (clone) Lynis, a security auditing tool for Unix-like systems. | Auditing | Git, Internet connection | No root required | +| **[Root Locker](hardening/Root%20Locker/root-locker.bash)** | Locks the root account to prevent direct logins. | Hardening | Root privileges | Preserves sudo access | +| **[SSHD Hardening](hardening/SSHD%20Hardening/harden-sshd.bash)** | Harden OpenSSH server (sshd) per Lynis recommendations. | Hardening | Root privileges | Creates backups; restarts sshd | +| **[UFW Cloudflare](hardening/UFW%20Cloudflare/ufw-cloudflare.bash)** | Configure UFW to only allow HTTP/HTTPS from Cloudflare IP ranges. | Hardening | Root privileges, UFW, Internet connection | **Beta status** | +## Getting Started - +### Prerequisites -## Getting Started +- **Bash**: Version 4.0 or higher +- **Operating System**: Linux-based distribution +- **File Permissions**: Ability to make scripts executable (`chmod +x`) -### Downloading +> [!NOTE] +> Individual scripts may have additional requirements listed in the table above. + +### Download and Setup All you need to do is download this repository to your local machine: -`git clone https://github.com/StrangeRanger/linux-security-scripts` +```bash +git clone https://github.com/StrangeRanger/linux-security-scripts +cd linux-security-scripts +``` + +> [!NOTE] +> If you're downloading individual scripts, you may need to make them executable with `chmod +x `. ## Usage -> [!NOTE] -> Some of the scripts in this repository require root privileges to run. You can run the scripts with the `sudo` command to give them the necessary permissions. +### Quick Start + +For users who want to get started immediately: + +1. **Audit your system first**: Run the Lynis installer to download the auditing tool. + ```bash + ./auditing/Lynis\ Installer/lynis-installer.bash + ``` + +2. **Run a security audit**: Use Lynis to identify security issues. + ```bash + cd ~/lynis && sudo ./lynis audit system + ``` + +3. **Apply hardening**: Based on the audit results, run the appropriate hardening scripts. + +### Individual Script Usage + +You can run any script individually using one of the following methods: + +```bash +./[script-name] +``` + +**or** + +```bash +bash [script-name] +``` + +> [!IMPORTANT] +> Scripts that require root privileges will prompt you or exit with an error if not run with appropriate permissions. -You can run the scripts in this repository by using the following command: +## Post-Installation -`./[script name]` OR `bash [script name]` +After running the hardening scripts: + +1. **Verify SSH access**: Before logging out, test SSH connectivity in a new terminal session. +2. **Review firewall rules**: Check UFW status with `sudo ufw status verbose` if you used the UFW Cloudflare script. +3. **Run Lynis again**: Re-audit your system to see security improvements. +4. **Backup configurations**: Keep copies of any modified configuration files. + +> [!WARNING] +> The SSHD hardening script modifies SSH configuration. Ensure you have alternative access to your system before applying changes in production environments. ## Tested On @@ -34,8 +119,42 @@ All of the scripts should work on most, if not all Linux Distributions. With tha | Ubuntu | 24.04, 22.04, 20.04 | | Debian | 11, 10, 9 | +> [!NOTE] +> Scripts should work on most Linux distributions with Bash 4.0+. The above list represents officially tested distributions. + +## Troubleshooting + +### Common Issues + +- **Permission denied**: Ensure you're running scripts with appropriate permissions (sudo for hardening scripts). +- **Git not found**: Install git with your package manager (`apt install git`, `yum install git`, etc.). +- **SSH connection lost**: The SSHD hardening script creates a backup at `/etc/ssh/sshd_config.bak` - you can restore it if needed. +- **UFW conflicts**: If you have existing UFW rules, review them before running the Cloudflare script. + ## Other Resources While this repository has scripts that can help secure Linux, it's not nearly enough to secure the system as much as it needs to be. Below is a list of other resources that you can/should use to help make your system as secure as possible. -- [SSH Audit](https://github.com/jtesta/ssh-audit) - SSH server & client auditing (banner, key exchange, encryption, mac, compression, compatibility, security, etc). +### Security Auditing Tools + +- [SSH Audit](https://github.com/jtesta/ssh-audit) - SSH server & client auditing (banner, key exchange, encryption, mac, compression, compatibility, security, etc) + +### Additional Hardening Resources + +- [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks) - Industry-standard security configuration guidelines +- [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework) - Comprehensive cybersecurity guidance +- [OpenSCAP](https://www.open-scap.org/) - Security compliance and vulnerability management + +### System Monitoring + +- [AIDE](https://aide.github.io/) - Advanced Intrusion Detection Environment +- [Fail2Ban](https://github.com/fail2ban/fail2ban) - Intrusion prevention software +- [rkhunter](http://rkhunter.sourceforge.net/) - Rootkit detection tool + +## Support and Issues + +Please use [GitHub Issues](https://github.com/StrangeRanger/linux-security-scripts/issues) for bug reports and feature requests. + +## License + +Licensing may vary by tool; see individual file headers. From eac3187685236fc45a3a0c3cd7a6cc4e8e699ba6 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 12:10:02 -0700 Subject: [PATCH 06/28] style: update comment style --- hardening/SSHD Hardening/harden-sshd.bash | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hardening/SSHD Hardening/harden-sshd.bash b/hardening/SSHD Hardening/harden-sshd.bash index ca608ff..3450dd2 100755 --- a/hardening/SSHD Hardening/harden-sshd.bash +++ b/hardening/SSHD Hardening/harden-sshd.bash @@ -13,8 +13,8 @@ # License: MIT License # Copyright (c) 2020-2025 Hunter T. (StrangeRanger) # -######################################################################################## -####[ Global Variables ]################################################################ +############################################################################################ +####[ Global Variables ]#################################################################### C_TMP_DIR=$(mktemp -d); readonly C_TMP_DIR @@ -80,7 +80,7 @@ readonly C_SSHD_CONFIG modifications_in_progress=false -####[ Functions ]####################################################################### +####[ Functions ]########################################################################### #### @@ -124,7 +124,7 @@ clean_exit() { } -####[ Trapping Logic ]################################################################## +####[ Trapping Logic ]###################################################################### trap 'clean_exit 129' SIGHUP @@ -132,7 +132,7 @@ trap 'clean_exit 130' SIGINT trap 'clean_exit 143' SIGTERM -####[ Prepping ]######################################################################## +####[ Prepping ]############################################################################ ## Check if the script was executed with root privilege. @@ -149,7 +149,7 @@ if [[ ! -f $C_CONFIG_FILE ]]; then fi -####[ Main ]############################################################################ +####[ Main ]################################################################################ read -rp "${C_NOTE}We will now harden sshd. Press [Enter] to continue." From b1715a6dd0a21f36776238c6211b4f1d81f38d5e Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 12:12:16 -0700 Subject: [PATCH 07/28] style: update comment style --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 21 +++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index f63248a..ae40e1b 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -1,13 +1,13 @@ #!/bin/bash # -# Sets up UFW to only allow HTTP and HTTPS traffic from Cloudflare's IP ranges. +# Set up UFW to only allow HTTP and HTTPS traffic from Cloudflare's IP ranges. # -# Version: v1.0.0-beta.2 +# Version: v1.0.0-alpha.2 # License: MIT License -# Copyright (c) 2024 Hunter T. (StrangeRanger) +# Copyright (c) 2024-2025 Hunter T. (StrangeRanger) # -######################################################################################## -####[ Global Variables ]################################################################ +############################################################################################ +####[ Global Variables ]#################################################################### ## URL for retrieving the current Cloudflare IP ranges. @@ -20,7 +20,7 @@ new_cloudflare_ip_ranges=() stage=0 -####[ Function ]######################################################################## +####[ Function ]############################################################################ #### @@ -28,9 +28,7 @@ stage=0 # # PARAMETERS: # - $1: ip (Required) -# - The IP address to check. # - $2: port (Required) -# - The port to check. # # RETURN: # - 0: The rule exists. @@ -43,7 +41,7 @@ ufw_rule_exists() { } #### -# Retrieves the rule number of all Cloudflare IP rules currently set in UFW, then +# Retrieve the rule number of all Cloudflare IP rules currently set in UFW, then # stores them in an array. # # PARAMETERS: @@ -139,7 +137,7 @@ cleanup() { } -####[ Trapping Logic ]################################################################## +####[ Trapping Logic ]###################################################################### trap 'clean_exit 130' SIGINT @@ -149,7 +147,7 @@ trap 'clean_exit 131' SIGQUIT trap 'clean_exit $?' EXIT -####[ Main ]############################################################################ +####[ Main ]################################################################################ ### @@ -209,4 +207,3 @@ ufw delete allow from any to any port 80,443 proto tcp sleep 1 # Wait for the rule to take effect. echo "Done." - From d688d161fc34836c69a1c2592893e5f7ab759625 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 12:23:59 -0700 Subject: [PATCH 08/28] func: restrict execution to root --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index ae40e1b..1a4ef69 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -147,6 +147,16 @@ trap 'clean_exit 131' SIGQUIT trap 'clean_exit $?' EXIT +####[ Prepping ]############################################################################ + + +## Check if the script was executed with root privilege. +if (( EUID != 0 )); then + echo "${C_ERROR}This script requires root privilege" >&2 + exit 1 +fi + + ####[ Main ]################################################################################ From 9ef38c3640f95ddb67ddce831522ec389166b631 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 13:41:15 -0700 Subject: [PATCH 09/28] refactor(ufw-cloudflare): inline rule-number extraction and simplify flow - Replace get_set_* helpers with inline logic - Robustly parse bracketed numbers ([ 9] and [9]) and trim whitespace - delete_set_cloudflare_rules accepts optional arg with default - Clarify logs/section headings; keep behavior intact --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 94 ++++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 1a4ef69..4dd7e30 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -40,44 +40,6 @@ ufw_rule_exists() { ufw status | grep -qE "^${port}.*ALLOW.*${ip}.*$" } -#### -# Retrieve the rule number of all Cloudflare IP rules currently set in UFW, then -# stores them in an array. -# -# PARAMETERS: -# - $1: string_to_grep (Required) -# - The string to grep for in the UFW status output. -# - Acceptable values: -# - 0: "Cloudflare IP" -# - 1: "Temporary rule" -get_set_cloudflare_rule_numbers() { - if (( $1 == 0 )); then - local string_to_grep="Cloudflare IP" - elif (( $1 == 1 )); then - local string_to_grep="Temporary rule" - else - echo "Invalid argument: $1" - exit 1 - fi - - mapfile -t current_cloudflare_rule_numbers < <( - ufw status numbered \ - | grep "$string_to_grep" \ - | awk -F'[][]' '{print $2}' \ - | sort -rn - ) -} - -#### -# Retrieves the IP addresses of all Cloudflare IP rules currently set in UFW, then -# stores them in an array. -get_set_cloudflare_ip_ranges() { - while IFS= read -r line; do - ip=$(echo "$line" | awk '{print $3}') # Extract the IP address. - current_cloudflare_ip_ranges+=("$ip") - done < <(sudo ufw status | grep "Cloudflare IP") -} - #### # Set the new Cloudflare IP ranges in UFW, retrieved from the Cloudflare website. set_new_cloudflare_ip_ranges() { @@ -98,8 +60,40 @@ restore_current_cloudflare_ip_ranges() { #### # Deletes all Cloudflare IP rules currently set in UFW. +# +# PARAMETERS: +# - $1: grep_string (Optional, Default: 0) +# - The string to look for in the UFW status output. Using an integer for the value +# helps eliminate accidental misspellings when passing arguments. +# - Acceptable values: +# - 0: "Cloudflare IP" +# - 1: "Temporary rule" delete_set_cloudflare_rules() { - get_set_cloudflare_rule_numbers "0" + local grep_string="${1:-0}" + local current_cloudflare_rule_numbers + + if (( $1 == 0 )); then + grep_string="Cloudflare IP" + elif (( $1 == 1 )); then + grep_string="Temporary rule" + else + echo "INTERNAL ERROR: Invalid argument: $1" + exit 2 + fi + + mapfile -t current_cloudflare_rule_numbers < <( + ufw status numbered \ + | grep -E "^\[ *[0-9]+\].*$grep_string" \ + | while IFS= read -r line; do + ## Extract number between brackets (handles both [1] and [ 1] formats). + temp="${line#*[}" + temp="${temp%%]*}" + ## Remove any leading/trailing whitespace. + temp="${temp#"${temp%%[![:space:]]*}"}" + temp="${temp%"${temp##*[![:space:]]}"}" + echo "$temp" + done + ) for rule_num in "${current_cloudflare_rule_numbers[@]}"; do # TODO: Add configuration option to confirm deletion. @@ -166,15 +160,21 @@ fi stage=1 -get_set_cloudflare_ip_ranges -mapfile -t new_cloudflare_ip_ranges < <(curl -s "$C_CLOUDFLARE_IPV4_RANGES_URL") -mapfile -t new_cloudflare_ipv6_ranges < <(curl -s "$C_CLOUDFLARE_IPV6_RANGES_URL") +echo "Retrieving current Cloudflare IP rules from UFW..." +while IFS= read -r line; do + read -ra fields <<< "$line" + current_cloudflare_ip_ranges+=("${fields[2]}") +done < <(sudo ufw status | grep "Cloudflare IP") +unset fields -new_cloudflare_ip_ranges+=("${new_cloudflare_ipv6_ranges[@]}") -unset new_cloudflare_ipv6_ranges +echo "Retrieving new Cloudflare IP ranges..." +mapfile -t new_cloudflare_ip_ranges < <( + curl -s "$C_CLOUDFLARE_IPV4_RANGES_URL" + curl -s "$C_CLOUDFLARE_IPV6_RANGES_URL" +) ### -### [ Opening ports 80 and 443 from any IP address ] +### Temporary rule to prevent traffic disruption. ### stage=2 @@ -184,7 +184,7 @@ ufw allow from any to any port 80,443 proto tcp comment "Temporary rule" sleep 1 # Wait for the rule to take effect. ### -### [ Removing the existing Cloudflare IP ranges ] +### Remove the existing Cloudflare IP ranges to allow new ones. ### stage=3 @@ -197,7 +197,7 @@ fi sleep 1 # Wait for the rule to take effect. ### -### [ Adding the new Cloudflare IP ranges ] +### Add the new Cloudflare IP ranges. ### stage=4 From 5e54364e750776d7a7cf1b7a17c7a698005db68d Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 15:07:57 -0700 Subject: [PATCH 10/28] func(ufw-cloudflare): add transactional rollback and signal-safe updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create temp archive backup of /etc/ufw and restore on error/interrupt (stages 2–4) - Add clean_exit with traps for SIGHUP/SIGINT/SIGTERM; finalize with clean_exit 0 - Add temporary 80/443 allow rule to prevent disruption during updates - Parse bracketed rule numbers ([ 1] and [1]) and delete matching rules - Use ufw_rule_exists to avoid duplicate additions - Introduce constants (Cloudflare comment, tmp/backup paths) and clearer logs --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 152 ++++++++----------- 1 file changed, 63 insertions(+), 89 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 4dd7e30..61165f8 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -10,6 +10,11 @@ ####[ Global Variables ]#################################################################### +C_TMP_DIR=$(mktemp -d) +C_UFW_BACKUP_ARCHIVE="$C_TMP_DIR/ufw-backup-$(date +%F).tar.gz" +readonly C_TMP_DIR C_UFW_BACKUP_ARCHIVE +readonly C_CLOUDFLARE_UFW_COMMENT="Cloudflare IP" + ## URL for retrieving the current Cloudflare IP ranges. readonly C_CLOUDFLARE_IPV4_RANGES_URL="https://www.cloudflare.com/ips-v4/" readonly C_CLOUDFLARE_IPV6_RANGES_URL="https://www.cloudflare.com/ips-v6/" @@ -41,91 +46,35 @@ ufw_rule_exists() { } #### -# Set the new Cloudflare IP ranges in UFW, retrieved from the Cloudflare website. -set_new_cloudflare_ip_ranges() { - for ip in "${new_cloudflare_ip_ranges[@]}"; do - ufw_rule_exists "$ip" "80,443" \ - || ufw allow from "$ip" to any port 80,443 proto tcp comment "Cloudflare IP" - done -} - -#### -# Restores the previous (non-new) Cloudflare IP ranges in UFW. -restore_current_cloudflare_ip_ranges() { - for ip in "${current_cloudflare_ip_ranges[@]}"; do - ufw_rule_exists "$ip" "80,443" \ - || ufw allow from "$ip" to any port 80,443 proto tcp comment "Cloudflare IP" - done -} - -#### -# Deletes all Cloudflare IP rules currently set in UFW. +# Cleanly exit the script by removing temporary files, restoring backups if needed, and +# displaying a message based on the exit code. # # PARAMETERS: -# - $1: grep_string (Optional, Default: 0) -# - The string to look for in the UFW status output. Using an integer for the value -# helps eliminate accidental misspellings when passing arguments. -# - Acceptable values: -# - 0: "Cloudflare IP" -# - 1: "Temporary rule" -delete_set_cloudflare_rules() { - local grep_string="${1:-0}" - local current_cloudflare_rule_numbers - - if (( $1 == 0 )); then - grep_string="Cloudflare IP" - elif (( $1 == 1 )); then - grep_string="Temporary rule" - else - echo "INTERNAL ERROR: Invalid argument: $1" - exit 2 - fi - - mapfile -t current_cloudflare_rule_numbers < <( - ufw status numbered \ - | grep -E "^\[ *[0-9]+\].*$grep_string" \ - | while IFS= read -r line; do - ## Extract number between brackets (handles both [1] and [ 1] formats). - temp="${line#*[}" - temp="${temp%%]*}" - ## Remove any leading/trailing whitespace. - temp="${temp#"${temp%%[![:space:]]*}"}" - temp="${temp%"${temp##*[![:space:]]}"}" - echo "$temp" - done - ) - - for rule_num in "${current_cloudflare_rule_numbers[@]}"; do - # TODO: Add configuration option to confirm deletion. - yes | ufw delete "$rule_num" - done -} +# - $1: exit_code (Required) +clean_exit() { + local exit_code="$1" + + case "$exit_code" in + 0|1) echo "" ;; + 129) echo -e "\n\nHangup signal detected (SIGHUP)" ;; + 130) echo -e "\n\nUser interrupt detected (SIGINT)" ;; + 143) echo -e "\n\nTermination signal detected (SIGTERM)" ;; + *) echo -e "\n\nExiting with code: $exit_code" ;; + esac -#### -# Cleanup function to close ports 80 and 443 from any IP address. -cleanup() { case $stage in - 2) - delete_set_cloudflare_rules "1" - ;; - 3) - echo "Potential error or interruption detected." - echo "Restoring the previous Cloudflare IP ranges..." - restore_current_cloudflare_ip_ranges - delete_set_cloudflare_rules "1" - ;; - 4) - echo "Potential error or interruption detected." - echo "Restoring the previous Cloudflare IP ranges..." - delete_new_cloudflare_ip_ranges - restore_current_cloudflare_ip_ranges - delete_set_cloudflare_rules "1" - ;; - 5) - # Continue, as we are too far along to realistically undo anything - ;; - *) - echo "Invalid stage: $stage" + 2|3|4) + echo "Interrupt occurred during stage '$stage', resulting in incomplete changes" + echo "Temporarily disabling UFW..." + ufw disable + echo "Restoring previous UFW rules..." + sudo tar -C /etc -xf "$C_UFW_BACKUP_ARCHIVE" + echo "Re-enabling UFW..." + ufw enable + echo "Displaying current UFW status..." + echo "---" + ufw status verbose + echo "---" ;; esac } @@ -134,11 +83,9 @@ cleanup() { ####[ Trapping Logic ]###################################################################### +trap 'clean_exit 129' SIGHUP trap 'clean_exit 130' SIGINT trap 'clean_exit 143' SIGTERM -trap 'clean_exit 129' SIGHUP -trap 'clean_exit 131' SIGQUIT -trap 'clean_exit $?' EXIT ####[ Prepping ]############################################################################ @@ -173,6 +120,9 @@ mapfile -t new_cloudflare_ip_ranges < <( curl -s "$C_CLOUDFLARE_IPV6_RANGES_URL" ) +echo "Creating UFW backup archive at: $C_UFW_BACKUP_ARCHIVE" +tar -C /etc -cf "$C_UFW_BACKUP_ARCHIVE" ufw + ### ### Temporary rule to prevent traffic disruption. ### @@ -191,10 +141,29 @@ stage=3 if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then echo "Removing the existing Cloudflare IP ranges..." - delete_set_cloudflare_rules + + mapfile -t current_cloudflare_rule_numbers < <( + ufw status numbered \ + | grep -E "^\[ *[0-9]+\].*$C_CLOUDFLARE_UFW_COMMENT" \ + | while IFS= read -r line; do + ## Extract number between brackets (handles both [1] and [ 1] formats). + temp="${line#*[}" + temp="${temp%%]*}" + ## Remove any leading/trailing whitespace. + temp="${temp#"${temp%%[![:space:]]*}"}" + temp="${temp%"${temp##*[![:space:]]}"}" + echo "$temp" + done + ) + + for rule_num in "${current_cloudflare_rule_numbers[@]}"; do + # TODO: Add configuration option to confirm deletion. + yes | ufw delete "$rule_num" + done fi -sleep 1 # Wait for the rule to take effect. +unset current_cloudflare_rule_numbers +sleep 1 # Wait for the changes to take effect. ### ### Add the new Cloudflare IP ranges. @@ -203,8 +172,12 @@ sleep 1 # Wait for the rule to take effect. stage=4 echo "Adding the new Cloudflare IPv4 and IPv6 ranges..." -set_new_cloudflare_ip_ranges -sleep 1 # Wait for the rule to take effect. +for ip in "${new_cloudflare_ip_ranges[@]}"; do + ufw_rule_exists "$ip" "80,443" \ + || ufw allow from "$ip" to any port 80,443 proto tcp comment "Cloudflare IP" +done + +sleep 1 # Wait for the changes to take effect. ### ### [ Finalizing ] @@ -214,6 +187,7 @@ stage=5 echo "Removing temporary rules..." ufw delete allow from any to any port 80,443 proto tcp -sleep 1 # Wait for the rule to take effect. +sleep 1 # Wait for the changes to take effect. echo "Done." +clean_exit 0 From fd761f04e22b8fa3c60a7aa17270456bcf97bb09 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 15:29:07 -0700 Subject: [PATCH 11/28] feat(ufw-cloudflare): colorize output messages --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 60 ++++++++++++-------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 61165f8..2c8c055 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -19,6 +19,18 @@ readonly C_CLOUDFLARE_UFW_COMMENT="Cloudflare IP" readonly C_CLOUDFLARE_IPV4_RANGES_URL="https://www.cloudflare.com/ips-v4/" readonly C_CLOUDFLARE_IPV6_RANGES_URL="https://www.cloudflare.com/ips-v6/" +C_YELLOW="$(printf '\033[1;33m')" +C_GREEN="$(printf '\033[0;32m')" +C_BLUE="$(printf '\033[0;34m')" +C_RED="$(printf '\033[1;31m')" +C_NC="$(printf '\033[0m')" +readonly C_YELLOW C_GREEN C_BLUE C_RED C_NC + +readonly C_SUCCESS="${C_GREEN}==>${C_NC} " +readonly C_WARNING="${C_YELLOW}==>${C_NC} " +readonly C_ERROR="${C_RED}ERROR:${C_NC} " +readonly C_INFO="${C_BLUE}==>${C_NC} " + current_cloudflare_rule_numbers=() current_cloudflare_ip_ranges=() new_cloudflare_ip_ranges=() @@ -56,27 +68,30 @@ clean_exit() { case "$exit_code" in 0|1) echo "" ;; - 129) echo -e "\n\nHangup signal detected (SIGHUP)" ;; - 130) echo -e "\n\nUser interrupt detected (SIGINT)" ;; - 143) echo -e "\n\nTermination signal detected (SIGTERM)" ;; - *) echo -e "\n\nExiting with code: $exit_code" ;; + 129) echo -e "\n\n${C_WARNING}Hangup signal detected (SIGHUP)" ;; + 130) echo -e "\n\n${C_WARNING}User interrupt detected (SIGINT)" ;; + 143) echo -e "\n\n${C_WARNING}Termination signal detected (SIGTERM)" ;; + *) echo -e "\n\n${C_WARNING}Exiting with code: $exit_code" ;; esac case $stage in 2|3|4) - echo "Interrupt occurred during stage '$stage', resulting in incomplete changes" - echo "Temporarily disabling UFW..." + echo "${C_WARNING}Interrupt occurred during stage '$stage'; incomplete changes" + echo "${C_INFO}Temporarily disabling UFW..." ufw disable - echo "Restoring previous UFW rules..." + echo "${C_INFO}Restoring previous UFW rules..." sudo tar -C /etc -xf "$C_UFW_BACKUP_ARCHIVE" - echo "Re-enabling UFW..." + echo "${C_INFO}Re-enabling UFW..." ufw enable - echo "Displaying current UFW status..." + echo "${C_INFO}Displaying current UFW status..." echo "---" ufw status verbose echo "---" ;; esac + + echo "${C_INFO}Exiting..." + exit "$exit_code" } @@ -107,20 +122,20 @@ fi stage=1 -echo "Retrieving current Cloudflare IP rules from UFW..." +echo "${C_INFO}Retrieving current Cloudflare IP rules from UFW..." while IFS= read -r line; do read -ra fields <<< "$line" current_cloudflare_ip_ranges+=("${fields[2]}") done < <(sudo ufw status | grep "Cloudflare IP") unset fields -echo "Retrieving new Cloudflare IP ranges..." +echo "${C_INFO}Retrieving new Cloudflare IP ranges..." mapfile -t new_cloudflare_ip_ranges < <( curl -s "$C_CLOUDFLARE_IPV4_RANGES_URL" curl -s "$C_CLOUDFLARE_IPV6_RANGES_URL" ) -echo "Creating UFW backup archive at: $C_UFW_BACKUP_ARCHIVE" +echo "${C_INFO}Creating UFW backup archive at: $C_UFW_BACKUP_ARCHIVE" tar -C /etc -cf "$C_UFW_BACKUP_ARCHIVE" ufw ### @@ -129,18 +144,18 @@ tar -C /etc -cf "$C_UFW_BACKUP_ARCHIVE" ufw stage=2 -echo "Temporarily opening ports 80 and 443 from any IP address..." +echo "${C_INFO}Temporarily opening ports 80 and 443 from any IP address..." ufw allow from any to any port 80,443 proto tcp comment "Temporary rule" -sleep 1 # Wait for the rule to take effect. ### ### Remove the existing Cloudflare IP ranges to allow new ones. ### stage=3 +sleep 1 if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then - echo "Removing the existing Cloudflare IP ranges..." + echo "${C_INFO}Removing the existing Cloudflare IP ranges..." mapfile -t current_cloudflare_rule_numbers < <( ufw status numbered \ @@ -163,31 +178,30 @@ if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then fi unset current_cloudflare_rule_numbers -sleep 1 # Wait for the changes to take effect. ### ### Add the new Cloudflare IP ranges. ### stage=4 +sleep 1 -echo "Adding the new Cloudflare IPv4 and IPv6 ranges..." +echo "${C_INFO}Adding the new Cloudflare IPv4 and IPv6 ranges..." for ip in "${new_cloudflare_ip_ranges[@]}"; do ufw_rule_exists "$ip" "80,443" \ || ufw allow from "$ip" to any port 80,443 proto tcp comment "Cloudflare IP" done -sleep 1 # Wait for the changes to take effect. - ### -### [ Finalizing ] +### Perform the last modifications to UFW. ### stage=5 +sleep 1 -echo "Removing temporary rules..." +echo "${C_INFO}Removing temporary rules..." ufw delete allow from any to any port 80,443 proto tcp -sleep 1 # Wait for the changes to take effect. -echo "Done." +sleep 1 +echo "${C_SUCCESS}Finished setting up UFW with Cloudflare IP ranges" clean_exit 0 From c9ddf5d008872dc83c38642828d15d5353888310 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 15:29:46 -0700 Subject: [PATCH 12/28] fix(ufw-cloudfalre): sort rule numbers in reverse order --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 2c8c055..8ab35a8 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -168,7 +168,8 @@ if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then temp="${temp#"${temp%%[![:space:]]*}"}" temp="${temp%"${temp##*[![:space:]]}"}" echo "$temp" - done + done \ + | sort -rn ) for rule_num in "${current_cloudflare_rule_numbers[@]}"; do From ca8d8caf3f8d4552cad8c2616fb1ea6b4385bf51 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 15:43:22 -0700 Subject: [PATCH 13/28] fix(ufw-cloudfalre): fix last IPv4 and first IPv6 from merging in array --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 1 + 1 file changed, 1 insertion(+) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 8ab35a8..34ba99a 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -132,6 +132,7 @@ unset fields echo "${C_INFO}Retrieving new Cloudflare IP ranges..." mapfile -t new_cloudflare_ip_ranges < <( curl -s "$C_CLOUDFLARE_IPV4_RANGES_URL" + echo "" # Will prevent the last IPv4 and first IPv6 address from being merged. curl -s "$C_CLOUDFLARE_IPV6_RANGES_URL" ) From 489dcd205775e545c10546bea42e801f6d85f6b4 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 16:38:26 -0700 Subject: [PATCH 14/28] feat(ufw-cloudflare): add note-level waits, per-step error handling, and per-IP logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduce C_NOTE and C_SLEEP_TIME; show “Waiting …” with configurable delay - Guard temporary rule add/remove with error checks; include comment on delete - Print “Adding rule for …” and surface ufw failures; suppress noisy output - Tidy section heading wording --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 54 +++++++++----------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 34ba99a..70fe5af 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -14,22 +14,24 @@ C_TMP_DIR=$(mktemp -d) C_UFW_BACKUP_ARCHIVE="$C_TMP_DIR/ufw-backup-$(date +%F).tar.gz" readonly C_TMP_DIR C_UFW_BACKUP_ARCHIVE readonly C_CLOUDFLARE_UFW_COMMENT="Cloudflare IP" +readonly C_SLEEP_TIME=1 -## URL for retrieving the current Cloudflare IP ranges. readonly C_CLOUDFLARE_IPV4_RANGES_URL="https://www.cloudflare.com/ips-v4/" readonly C_CLOUDFLARE_IPV6_RANGES_URL="https://www.cloudflare.com/ips-v6/" C_YELLOW="$(printf '\033[1;33m')" C_GREEN="$(printf '\033[0;32m')" C_BLUE="$(printf '\033[0;34m')" +C_CYAN="$(printf '\033[0;36m')" C_RED="$(printf '\033[1;31m')" C_NC="$(printf '\033[0m')" -readonly C_YELLOW C_GREEN C_BLUE C_RED C_NC +readonly C_YELLOW C_GREEN C_BLUE C_CYAN C_RED C_NC readonly C_SUCCESS="${C_GREEN}==>${C_NC} " readonly C_WARNING="${C_YELLOW}==>${C_NC} " readonly C_ERROR="${C_RED}ERROR:${C_NC} " readonly C_INFO="${C_BLUE}==>${C_NC} " +readonly C_NOTE="${C_CYAN}==>${C_NC} " current_cloudflare_rule_numbers=() current_cloudflare_ip_ranges=() @@ -40,23 +42,6 @@ stage=0 ####[ Function ]############################################################################ -#### -# Check if a UFW rule exists for a specific IP address and port. -# -# PARAMETERS: -# - $1: ip (Required) -# - $2: port (Required) -# -# RETURN: -# - 0: The rule exists. -# - ?: The rule does not exist. -ufw_rule_exists() { - local ip="$1" - local port="$2" - - ufw status | grep -qE "^${port}.*ALLOW.*${ip}.*$" -} - #### # Cleanly exit the script by removing temporary files, restoring backups if needed, and # displaying a message based on the exit code. @@ -140,20 +125,24 @@ echo "${C_INFO}Creating UFW backup archive at: $C_UFW_BACKUP_ARCHIVE" tar -C /etc -cf "$C_UFW_BACKUP_ARCHIVE" ufw ### -### Temporary rule to prevent traffic disruption. +### Add temporary rule to prevent traffic disruption. ### stage=2 echo "${C_INFO}Temporarily opening ports 80 and 443 from any IP address..." -ufw allow from any to any port 80,443 proto tcp comment "Temporary rule" +if ! ufw allow from any to any port 80,443 proto tcp comment "Temporary rule"; then + echo "${C_ERROR}Failed to add temporary rule" >&2 + clean_exit 1 +fi ### ### Remove the existing Cloudflare IP ranges to allow new ones. ### stage=3 -sleep 1 +echo "${C_NOTE}Waiting '$C_SLEEP_TIME' second for changes to take effect..." +sleep "$C_SLEEP_TIME" if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then echo "${C_INFO}Removing the existing Cloudflare IP ranges..." @@ -174,7 +163,6 @@ if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then ) for rule_num in "${current_cloudflare_rule_numbers[@]}"; do - # TODO: Add configuration option to confirm deletion. yes | ufw delete "$rule_num" done fi @@ -186,12 +174,15 @@ unset current_cloudflare_rule_numbers ### stage=4 -sleep 1 +echo "${C_NOTE}Waiting '$C_SLEEP_TIME' second for changes to take effect..." +sleep "$C_SLEEP_TIME" echo "${C_INFO}Adding the new Cloudflare IPv4 and IPv6 ranges..." for ip in "${new_cloudflare_ip_ranges[@]}"; do - ufw_rule_exists "$ip" "80,443" \ - || ufw allow from "$ip" to any port 80,443 proto tcp comment "Cloudflare IP" + echo "${C_INFO} Adding rule for '$ip'..." + if ! ufw allow from "$ip" to any port 80,443 proto tcp comment "$C_CLOUDFLARE_UFW_COMMENT" >/dev/null; then + echo "${C_ERROR}Failed to add rule for '$ip'" >&2 + fi done ### @@ -199,11 +190,16 @@ done ### stage=5 -sleep 1 +echo "${C_NOTE}Waiting '$C_SLEEP_TIME' second for changes to take effect..." +sleep "$C_SLEEP_TIME" echo "${C_INFO}Removing temporary rules..." -ufw delete allow from any to any port 80,443 proto tcp +if ! ufw delete allow from any to any port 80,443 proto tcp comment "Temporary rule"; then + echo "${C_ERROR}Failed to remove temporary rule" >&2 + echo "${C_NOTE}Please check your UFW configuration and remove it manually" +fi -sleep 1 +sleep "$C_SLEEP_TIME" +echo "${C_NOTE}Waiting '$C_SLEEP_TIME' second for changes to take effect..." echo "${C_SUCCESS}Finished setting up UFW with Cloudflare IP ranges" clean_exit 0 From 2f3eede991acf5f61250fcfef44230370ec276f9 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 16:40:08 -0700 Subject: [PATCH 15/28] docs(CHANGELOG): production release --- hardening/UFW Cloudflare/CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hardening/UFW Cloudflare/CHANGELOG.md b/hardening/UFW Cloudflare/CHANGELOG.md index e69de29..2c368ac 100644 --- a/hardening/UFW Cloudflare/CHANGELOG.md +++ b/hardening/UFW Cloudflare/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## v1.0.0 - 2025-08-09 + +- Full production-ready release tool. From 598e87e2d0a7d54f95425808ccbfc53bf6698b66 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 17:07:10 -0700 Subject: [PATCH 16/28] docs: update version number --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 70fe5af..f563663 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -2,7 +2,7 @@ # # Set up UFW to only allow HTTP and HTTPS traffic from Cloudflare's IP ranges. # -# Version: v1.0.0-alpha.2 +# Version: v1.0.0 # License: MIT License # Copyright (c) 2024-2025 Hunter T. (StrangeRanger) # @@ -180,7 +180,9 @@ sleep "$C_SLEEP_TIME" echo "${C_INFO}Adding the new Cloudflare IPv4 and IPv6 ranges..." for ip in "${new_cloudflare_ip_ranges[@]}"; do echo "${C_INFO} Adding rule for '$ip'..." - if ! ufw allow from "$ip" to any port 80,443 proto tcp comment "$C_CLOUDFLARE_UFW_COMMENT" >/dev/null; then + if ! ufw allow from "$ip" to any port 80,443 proto tcp comment \ + "$C_CLOUDFLARE_UFW_COMMENT" >/dev/null + then echo "${C_ERROR}Failed to add rule for '$ip'" >&2 fi done From 2e459115f452d71243cfa75dc134185a2bd19825 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sat, 9 Aug 2025 17:10:08 -0700 Subject: [PATCH 17/28] refactor: remove 'Exiting...' output --- hardening/Root Locker/CHANGELOG.md | 6 ++++++ hardening/Root Locker/root-locker.bash | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hardening/Root Locker/CHANGELOG.md b/hardening/Root Locker/CHANGELOG.md index a5d5905..aa4fec4 100644 --- a/hardening/Root Locker/CHANGELOG.md +++ b/hardening/Root Locker/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v1.0.9 - 2025-08-09 + +## Changed + +- Removed "Exiting..." message from output. + ## v1.0.8 - 2024-12-20 ### Changed diff --git a/hardening/Root Locker/root-locker.bash b/hardening/Root Locker/root-locker.bash index 02e0583..698906a 100755 --- a/hardening/Root Locker/root-locker.bash +++ b/hardening/Root Locker/root-locker.bash @@ -6,7 +6,7 @@ # Locking the root account doesn't prevent users from using something like `sudo su` # to gain root access. # -# Version: v1.0.8 +# Version: v1.0.9 # License: MIT License # Copyright (c) 2020-2024 Hunter T. (StrangeRanger) # @@ -27,7 +27,6 @@ C_NOTE="${C_CYAN}==>${C_NC} " ## Check if this script was executed with root privilege. if [[ $EUID != 0 ]]; then echo "${C_ERROR}Please run this script as or with root privilege" >&2 - echo -e "\n${C_INFO}Exiting..." exit 1 fi @@ -37,7 +36,6 @@ read -rp "${C_NOTE}We will now disable the root account. Press [Enter] to contin echo "${C_INFO}Disabling root account..." usermod -L root || { echo -e "${C_ERROR}Failed to lock the root account" >&2 - echo -e "\n${C_INFO}Exiting..." exit 1 } From da68418657cac4a6be5955a822a52da900916e06 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:05:07 -0700 Subject: [PATCH 18/28] fix(clean_exit): remove temp files on exit to avoid leftovers --- hardening/UFW Cloudflare/CHANGELOG.md | 8 +++++++- hardening/UFW Cloudflare/ufw-cloudflare.bash | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hardening/UFW Cloudflare/CHANGELOG.md b/hardening/UFW Cloudflare/CHANGELOG.md index 2c368ac..d5aa6c4 100644 --- a/hardening/UFW Cloudflare/CHANGELOG.md +++ b/hardening/UFW Cloudflare/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v1.0.1 - 2025-08-10 + +### Fixed + +- Remove temp files on exit to avoid leftovers + ## v1.0.0 - 2025-08-09 -- Full production-ready release tool. +- Full production-ready release diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index f563663..0b2c5a3 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -75,6 +75,11 @@ clean_exit() { ;; esac + if [[ -d "$C_TMP_DIR" ]]; then + echo "${C_INFO}Cleaning up..." + rm -rf "$C_TMP_DIR" + fi + echo "${C_INFO}Exiting..." exit "$exit_code" } From 902dbcd393caf43d387b428bb926c9686f8038cb Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:05:53 -0700 Subject: [PATCH 19/28] chore: update version number --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 0b2c5a3..5f9c72c 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -2,7 +2,7 @@ # # Set up UFW to only allow HTTP and HTTPS traffic from Cloudflare's IP ranges. # -# Version: v1.0.0 +# Version: v1.0.1 # License: MIT License # Copyright (c) 2024-2025 Hunter T. (StrangeRanger) # From e95bfe2727f2dd52f5645bccd68301ebab256d92 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:09:29 -0700 Subject: [PATCH 20/28] chore: clean up comments --- hardening/UFW Cloudflare/ufw-cloudflare.bash | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hardening/UFW Cloudflare/ufw-cloudflare.bash b/hardening/UFW Cloudflare/ufw-cloudflare.bash index 5f9c72c..cb3d3c2 100755 --- a/hardening/UFW Cloudflare/ufw-cloudflare.bash +++ b/hardening/UFW Cloudflare/ufw-cloudflare.bash @@ -96,7 +96,6 @@ trap 'clean_exit 143' SIGTERM ####[ Prepping ]############################################################################ -## Check if the script was executed with root privilege. if (( EUID != 0 )); then echo "${C_ERROR}This script requires root privilege" >&2 exit 1 @@ -156,7 +155,7 @@ if (( ${#current_cloudflare_ip_ranges[@]} != 0 )); then ufw status numbered \ | grep -E "^\[ *[0-9]+\].*$C_CLOUDFLARE_UFW_COMMENT" \ | while IFS= read -r line; do - ## Extract number between brackets (handles both [1] and [ 1] formats). + ## Extract the number between brackets (handles both [1] and [ 1] formats). temp="${line#*[}" temp="${temp%%]*}" ## Remove any leading/trailing whitespace. From 2425da8aa3ebdda5e155c8ad10d8898237c17f31 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:18:06 -0700 Subject: [PATCH 21/28] chore: clean up comments and echo format --- hardening/SSHD Hardening/harden-sshd.bash | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hardening/SSHD Hardening/harden-sshd.bash b/hardening/SSHD Hardening/harden-sshd.bash index 3450dd2..dd7e65d 100755 --- a/hardening/SSHD Hardening/harden-sshd.bash +++ b/hardening/SSHD Hardening/harden-sshd.bash @@ -100,12 +100,12 @@ clean_exit() { *) echo -e "\n\n${C_WARNING}Exiting with code: $exit_code" ;; esac - # Check if we need to restore (modifications were in progress). + # Check if we need to restore the original configurations. if [[ $modifications_in_progress == true ]] && [[ -f "$C_SESSION_BACKUP" ]]; then echo "${C_WARNING}Script was interrupted during configuration changes" echo "${C_INFO}Restoring original 'sshd_config'..." if cp "$C_SESSION_BACKUP" "$C_CONFIG_FILE"; then - echo "${C_SUCCESS}Successfully restored original configuration" + echo "${C_SUCCESS}Successfully restored original configurations" echo "${C_INFO}Cleaning up..." [[ -d "$C_TMP_DIR" ]] && rm -rf "$C_TMP_DIR" else @@ -238,10 +238,11 @@ else echo "${C_NOTE}You may need to restart the SSH service manually" fi -echo -e "\n${C_SUCCESS}Finished hardening sshd" -echo -e "${C_NOTE}It is highly recommended to manually:" -echo -e "${C_NOTE} 1) Change the default sshd port (22)" -echo -e "${C_NOTE} 2) Disable PasswordAuthentication in favor of PubkeyAuthentication" -echo -e "${C_NOTE} 3) Add 'AllowUsers [your username]' to the bottom of 'sshd_config'" +echo "" +echo "${C_SUCCESS}Finished hardening sshd" +echo "${C_NOTE}It is highly recommended to manually:" +echo "${C_NOTE} 1) Change the default sshd port (22)" +echo "${C_NOTE} 2) Disable PasswordAuthentication in favor of PubkeyAuthentication" +echo "${C_NOTE} 3) Add 'AllowUsers [your username]' to the bottom of 'sshd_config'" clean_exit 0 From 0eb295473944bea7374817543f474f69894afd35 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:21:11 -0700 Subject: [PATCH 22/28] refactor(root-locker): replace [[ ]] with (( )) and remove redundant comment --- hardening/Root Locker/root-locker.bash | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hardening/Root Locker/root-locker.bash b/hardening/Root Locker/root-locker.bash index 698906a..bd57608 100755 --- a/hardening/Root Locker/root-locker.bash +++ b/hardening/Root Locker/root-locker.bash @@ -6,9 +6,9 @@ # Locking the root account doesn't prevent users from using something like `sudo su` # to gain root access. # -# Version: v1.0.9 +# Version: v1.0.10 # License: MIT License -# Copyright (c) 2020-2024 Hunter T. (StrangeRanger) +# Copyright (c) 2020-2025 Hunter T. (StrangeRanger) # ######################################################################################## @@ -24,8 +24,7 @@ C_INFO="${C_BLUE}==>${C_NC} " C_NOTE="${C_CYAN}==>${C_NC} " -## Check if this script was executed with root privilege. -if [[ $EUID != 0 ]]; then +if (( EUID != 0 )); then echo "${C_ERROR}Please run this script as or with root privilege" >&2 exit 1 fi From 1f36387ff502e17c47763d4b9371317b6c938676 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:21:26 -0700 Subject: [PATCH 23/28] docs: update CHANGELOG.md --- hardening/Root Locker/CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hardening/Root Locker/CHANGELOG.md b/hardening/Root Locker/CHANGELOG.md index aa4fec4..42d36bc 100644 --- a/hardening/Root Locker/CHANGELOG.md +++ b/hardening/Root Locker/CHANGELOG.md @@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v1.0.10 - 2025-08-10 + +### Changed + +- Replace `[[ ]]` with `(( ))`. +- Remove redundant comments. + ## v1.0.9 - 2025-08-09 -## Changed +### Changed - Removed "Exiting..." message from output. From 1fcb8733f62c13dc307363b45cbfcb9acda9e2a3 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:23:55 -0700 Subject: [PATCH 24/28] refactor(lynis-installer): remove pointless -e flag in echo --- auditing/Lynis Installer/lynis-installer.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/auditing/Lynis Installer/lynis-installer.bash b/auditing/Lynis Installer/lynis-installer.bash index 75fe317..a5c1c5a 100755 --- a/auditing/Lynis Installer/lynis-installer.bash +++ b/auditing/Lynis Installer/lynis-installer.bash @@ -5,9 +5,9 @@ # it. Unless an error is encountered, Lynis will always be downloaded to the current # user's root directory (`/home/USERNAME/`). # -# Version: v1.0.8 +# Version: v1.0.9 # License: MIT License -# Copyright (c) 2020-2024 Hunter T. (StrangeRanger) +# Copyright (c) 2020-2025 Hunter T. (StrangeRanger) # ######################################################################################## @@ -48,5 +48,5 @@ git clone https://github.com/CISOfy/lynis || { } echo -e "\n${C_SUCCESS}Lynis has been downloaded to your system" -echo -e "${C_NOTE}To perform a system scan with lynis, execute the following command" \ +echo "${C_NOTE}To perform a system scan with lynis, execute the following command" \ "in the lynis root directory: sudo ./lynis audit system" From 49e9e1bb64db2e6e5cc60aded640eeae052b3bfe Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:25:02 -0700 Subject: [PATCH 25/28] docs: update CHANGELOG.md --- auditing/Lynis Installer/CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/auditing/Lynis Installer/CHANGELOG.md b/auditing/Lynis Installer/CHANGELOG.md index 4e023ef..5342886 100644 --- a/auditing/Lynis Installer/CHANGELOG.md +++ b/auditing/Lynis Installer/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v1.0.9 - 2025-08-10 + +### Removed + +- Remove pointless `-e` flag in `echo`. + ## v1.0.8 - 2024-12-20 ### Changed @@ -17,7 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - No longer requires root permission to run the script. - Won't download lynis if is already present on the system. - Improved syntax of the script. -- Rename script to `lynis-installer.bash`. +- Rename script to `lynis-installer.bash`. ## v1.0.6 - 2024-04-13 From 4185dd6a83834245a6dffe8c4840596542a37caa Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:45:32 -0700 Subject: [PATCH 26/28] docs(README): improve and reformat README --- README.md | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index ea5d5df..26b18f8 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,6 @@ This repository is a collection of scripts designed to secure/harden Linux-based - [Individual Script Usage](#individual-script-usage) - [Post-Installation](#post-installation) - [Tested On](#tested-on) - - [Troubleshooting](#troubleshooting) - - [Common Issues](#common-issues) - [Other Resources](#other-resources) - [Security Auditing Tools](#security-auditing-tools) - [Additional Hardening Resources](#additional-hardening-resources) @@ -38,15 +36,20 @@ Below is a list of tools included in this repository. |-----------|-------------|----------|--------------|-------| | **[Lynis Installer](auditing/Lynis%20Installer/lynis-installer.bash)** | Download (clone) Lynis, a security auditing tool for Unix-like systems. | Auditing | Git, Internet connection | No root required | | **[Root Locker](hardening/Root%20Locker/root-locker.bash)** | Locks the root account to prevent direct logins. | Hardening | Root privileges | Preserves sudo access | -| **[SSHD Hardening](hardening/SSHD%20Hardening/harden-sshd.bash)** | Harden OpenSSH server (sshd) per Lynis recommendations. | Hardening | Root privileges | Creates backups; restarts sshd | -| **[UFW Cloudflare](hardening/UFW%20Cloudflare/ufw-cloudflare.bash)** | Configure UFW to only allow HTTP/HTTPS from Cloudflare IP ranges. | Hardening | Root privileges, UFW, Internet connection | **Beta status** | +| **[SSHD Hardening](hardening/SSHD%20Hardening/harden-sshd.bash)** | Harden OpenSSH server (sshd) per Lynis recommendations. | Hardening | Root privileges | Creates backups | +| **[UFW Cloudflare](hardening/UFW%20Cloudflare/ufw-cloudflare.bash)** | Configure UFW to only allow HTTP/HTTPS from Cloudflare IP ranges. | Hardening | Root privileges, UFW, Internet connection | Creates backups | + +> [!NOTE] +> All scripts include version information in their headers. Check individual CHANGELOG.md files in each tool's directory for version history and updates. + ## Getting Started ### Prerequisites +The following requirements extend to every tool in this repository: + - **Bash**: Version 4.0 or higher - **Operating System**: Linux-based distribution -- **File Permissions**: Ability to make scripts executable (`chmod +x`) > [!NOTE] > Individual scripts may have additional requirements listed in the table above. @@ -60,9 +63,6 @@ git clone https://github.com/StrangeRanger/linux-security-scripts cd linux-security-scripts ``` -> [!NOTE] -> If you're downloading individual scripts, you may need to make them executable with `chmod +x `. - ## Usage ### Quick Start @@ -79,7 +79,10 @@ For users who want to get started immediately: cd ~/lynis && sudo ./lynis audit system ``` -3. **Apply hardening**: Based on the audit results, run the appropriate hardening scripts. +3. **Apply hardening**: Based on the audit results, run the appropriate hardening scripts with root privileges. + +> [!CAUTION] +> **Production Environment Warning**: Always test scripts in a non-production environment first. Some scripts modify critical system configurations and may affect system accessibility. ### Individual Script Usage @@ -95,9 +98,6 @@ You can run any script individually using one of the following methods: bash [script-name] ``` -> [!IMPORTANT] -> Scripts that require root privileges will prompt you or exit with an error if not run with appropriate permissions. - ## Post-Installation After running the hardening scripts: @@ -112,28 +112,16 @@ After running the hardening scripts: ## Tested On -All of the scripts should work on most, if not all Linux Distributions. With that said, below is a list of Linux Distributions that the scripts have been officially tested and are confirmed to work on. +All of the scripts should work on most, if not all, Linux distributions with Bash v4.0+ installed. With that said, below is a list of Linux distributions that the scripts have been officially tested and are confirmed to work on. | Distributions | Distro Versions | | ------------- | ---------------------- | | Ubuntu | 24.04, 22.04, 20.04 | | Debian | 11, 10, 9 | -> [!NOTE] -> Scripts should work on most Linux distributions with Bash 4.0+. The above list represents officially tested distributions. - -## Troubleshooting - -### Common Issues - -- **Permission denied**: Ensure you're running scripts with appropriate permissions (sudo for hardening scripts). -- **Git not found**: Install git with your package manager (`apt install git`, `yum install git`, etc.). -- **SSH connection lost**: The SSHD hardening script creates a backup at `/etc/ssh/sshd_config.bak` - you can restore it if needed. -- **UFW conflicts**: If you have existing UFW rules, review them before running the Cloudflare script. - ## Other Resources -While this repository has scripts that can help secure Linux, it's not nearly enough to secure the system as much as it needs to be. Below is a list of other resources that you can/should use to help make your system as secure as possible. +Below is a list of additional resources that you can/should use to help make your system as secure as possible. ### Security Auditing Tools From 0b03ecbb361a5b2e7a845cecc3a5e17a0151506f Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:46:46 -0700 Subject: [PATCH 27/28] docs(README): update badge links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 26b18f8..9d2d089 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Linux Security Scripts -[![Project Tracker](https://img.shields.io/badge/repo%20status-Project%20Tracker-lightgrey)](https://wiki.hthompson.dev/en/project-tracker) -[![Style Guide](https://img.shields.io/badge/code%20style-Style%20Guide-blueviolet)](https://github.com/StrangeRanger/bash-style-guide) +[![Project Tracker](https://img.shields.io/badge/repo%20status-Project%20Tracker-lightgrey)](https://hthompson.dev/project-tracker#project-293920085) +[![Style Guide](https://img.shields.io/badge/code%20style-Style%20Guide-blueviolet)](https://bsg.hthompson.dev/) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/598c2083cd6f432a910a315fd10aaa66)](https://www.codacy.com/gh/StrangeRanger/linux-security-scripts/dashboard?utm_source=github.com&utm_medium=referral&utm_content=StrangeRanger/linux-security-scripts&utm_campaign=Badge_Grade) This repository is a collection of scripts designed to secure/harden Linux-based distributions. From 714e9b2d6b7df0fec09646be86a5fbf62bc9c178 Mon Sep 17 00:00:00 2001 From: "Hunter T." Date: Sun, 10 Aug 2025 12:53:08 -0700 Subject: [PATCH 28/28] docs(README): update README.md Signed-off-by: Hunter T. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d2d089..6d44c78 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ After running the hardening scripts: 4. **Backup configurations**: Keep copies of any modified configuration files. > [!WARNING] -> The SSHD hardening script modifies SSH configuration. Ensure you have alternative access to your system before applying changes in production environments. +> The SSHD hardening script modifies SSH configurations. Ensure you have alternative access to your system before applying changes in production environments. ## Tested On