Script Purpose
A comprehensive Bash script designed to completely remove CrowdSec components from a Linux system, providing flexible uninstallation options.
Key Functionalities
Prerequisite Checks
- Root privilege validation
- Detection of package management system (apt/rpm)
- Service and package discovery mechanisms
Removal Options
- Disable CrowdSec services
- Remove CrowdSec packages
- Complete removal (services, packages, configurations, repositories)
Detailed Component Removal Process
Service Handling
- Identifies CrowdSec-related systemd services
- Stops and disables active services
- Uses
systemctlfor service management
Package Removal
- Supports multiple package managers:
- Debian/Ubuntu: Uses
apt remove --purge - Red Hat/CentOS: Uses
yum remove
- Debian/Ubuntu: Uses
- Performs automatic dependency cleanup
Configuration Cleanup
- Removes configuration directories:
/etc/crowdsec/var/lib/crowdsec
Repository Management
- Strips CrowdSec-related entries from APT sources
- Runs
apt updateto refresh repository cache
Usage Modes
Interactive Mode
- Provides user-driven removal process
- Offers granular control over removal steps
Nuke Mode (-n flag)
- Performs complete, non-interactive removal
- Removes all CrowdSec components automatically
Safety Considerations
- Requires root privileges
- Provides color-coded console output for clarity
- Implements error handling and validation checks
Compatibility
- Supports Cloudpanel, Debian/Ubuntu and Red Hat-based distributions
- Requires systemd and modern package management tools
Recommended Usage
# Interactive mode
sudo ./crowdsec_removal.sh
# Non-interactive complete removal
sudo ./crowdsec_removal.sh -n
Potential Risks
- Completely removes CrowdSec security components
- May impact existing security configurations
- Recommended to backup system before execution
Version 2.0(2024)
I’ve significantly enhanced the script with several improvements:
-
Enhanced Error Handling:
- Added comprehensive error trapping
- Implemented detailed error logging
- Added cleanup functions for temporary files
- Improved exit code handling
-
Logging System:
- Added detailed logging to
/var/log/crowdsec_removal_[timestamp].log - Implemented structured log messages with timestamps
- Added different log levels (INFO, WARNING, ERROR, SUCCESS)
- Added detailed logging to
-
Backup Functionality:
- Added
-b/--backupoption to create backups before removal - Backs up configuration files and service definitions
- Creates timestamped backup directories
- Added
-
Better System Compatibility:
- Added support for multiple package managers (apt, yum, dnf)
- Used
tputinstead of ANSI codes for better terminal compatibility - Added system requirements checking
- Improved repository handling
-
Command Line Options:
- Added proper command-line argument parsing
- Added
-h/--helpoption for usage information - Added
-v/--versionoption - Maintained
-n/--nukeoption for non-interactive mode
-
Improved Configuration Removal:
- Added more configuration directories to clean up
- Better handling of service files
- More thorough package dependency cleanup
-
Code Organization:
- Better function organization
- Added version tracking
- Improved variable naming and scope
- Added meaningful comments
To use the improved script:
- Basic interactive mode:
sudo ./crowdsec_removal.sh
- Non-interactive complete removal with backup:
sudo ./crowdsec_removal.sh -n -b
- Show help:
./crowdsec_removal.sh -h
The script now provides:
- Better safety with backups
- Comprehensive logging
- More robust error handling
- Better system compatibility
- More thorough cleanup
- Better user interface
- Better maintainability
#!/bin/bash
# Script version
VERSION="2.0.0"
# Color definitions using tput for better compatibility
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
BLUE=$(tput setaf 4)
NC=$(tput sgr0)
# Logging setup
LOGFILE="/var/log/crowdsec_removal_$(date +%Y%m%d_%H%M%S).log"
BACKUP_DIR="/var/backup/crowdsec_$(date +%Y%m%d_%H%M%S)"
# Trap errors and interrupts
trap 'error_handler $? $LINENO' ERR
trap 'cleanup' EXIT
trap 'interrupt_handler' INT TERM
# Function to handle errors
error_handler() {
local exit_code=$1
local line_number=$2
log_message "ERROR" "Error $exit_code occurred on line $line_number"
cleanup
exit "$exit_code"
}
# Function to handle interrupts
interrupt_handler() {
log_message "WARNING" "Script interrupted by user"
cleanup
exit 130
}
# Cleanup function
cleanup() {
# Remove temporary files if they exist
[ -f "/tmp/crowdsec_services.tmp" ] && rm -f "/tmp/crowdsec_services.tmp"
[ -f "/tmp/crowdsec_packages.tmp" ] && rm -f "/tmp/crowdsec_packages.tmp"
}
# Enhanced logging function
log_message() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> "$LOGFILE"
case $level in
"INFO") print_color "$BLUE" "$message" ;;
"WARNING") print_color "$YELLOW" "$message" ;;
"ERROR") print_color "$RED" "$message" ;;
"SUCCESS") print_color "$GREEN" "$message" ;;
esac
}
# Function to print colored output
print_color() {
printf "%s%s%s\n" "${1}" "${2}" "${NC}"
}
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to check system requirements
check_system_requirements() {
local missing_deps=()
# Check for required commands
for cmd in systemctl grep awk sed; do
if ! command_exists "$cmd"; then
missing_deps+=("$cmd")
fi
done
if [ ${#missing_deps[@]} -ne 0 ]; then
log_message "ERROR" "Missing required dependencies: ${missing_deps[*]}"
exit 1
fi
}
# Function to check if running as root
check_root() {
if [ "$(id -u)" -ne 0 ]; then
log_message "ERROR" "Please run as root"
exit 1
fi
}
# Function to create backup
create_backup() {
log_message "INFO" "Creating backup of CrowdSec configurations..."
mkdir -p "$BACKUP_DIR"
# Backup configuration files
if [ -d "/etc/crowdsec" ]; then
cp -r "/etc/crowdsec" "$BACKUP_DIR/"
fi
if [ -d "/var/lib/crowdsec" ]; then
cp -r "/var/lib/crowdsec" "$BACKUP_DIR/"
fi
# Backup service files
if [ -d "/etc/systemd/system" ]; then
find "/etc/systemd/system" -name "*crowdsec*" -exec cp {} "$BACKUP_DIR/" \;
fi
log_message "SUCCESS" "Backup created at $BACKUP_DIR"
}
# Enhanced service check function
check_services() {
log_message "INFO" "Checking for CrowdSec services..."
systemctl list-units --type=service --all | grep -i crowdsec | awk '{print $1}' > /tmp/crowdsec_services.tmp
if [ ! -s /tmp/crowdsec_services.tmp ]; then
log_message "SUCCESS" "No CrowdSec services found."
services=""
else
services=$(cat /tmp/crowdsec_services.tmp)
log_message "WARNING" "Found CrowdSec services:"
echo "$services" | while read -r service; do
log_message "INFO" "Found service: $service"
done
fi
}
# Enhanced package check function
check_packages() {
log_message "INFO" "Checking for CrowdSec packages..."
if command_exists dpkg; then
dpkg -l | grep -i crowdsec | awk '{print $2}' > /tmp/crowdsec_packages.tmp
elif command_exists rpm; then
rpm -qa | grep -i crowdsec > /tmp/crowdsec_packages.tmp
else
log_message "ERROR" "Unable to determine package manager."
return 1
fi
if [ ! -s /tmp/crowdsec_packages.tmp ]; then
log_message "SUCCESS" "No CrowdSec packages found."
packages=""
else
packages=$(cat /tmp/crowdsec_packages.tmp)
log_message "WARNING" "Found CrowdSec packages:"
echo "$packages" | while read -r package; do
log_message "INFO" "Found package: $package"
done
fi
}
# Enhanced service disable function
disable_services() {
log_message "INFO" "Disabling CrowdSec services..."
if [ -z "$services" ]; then
log_message "WARNING" "No CrowdSec services to disable."
else
echo "$services" | while read -r service; do
systemctl stop "$service" 2>/dev/null
if [ $? -eq 0 ]; then
systemctl disable "$service" 2>/dev/null
log_message "SUCCESS" "Disabled $service"
else
log_message "ERROR" "Failed to stop $service"
fi
done
fi
}
# Enhanced package removal function
remove_packages() {
log_message "INFO" "Removing CrowdSec packages..."
if [ -z "$packages" ]; then
log_message "WARNING" "No CrowdSec packages to remove."
return
fi
local remove_cmd=""
if command_exists apt-get; then
remove_cmd="apt-get remove --purge -y"
cleanup_cmd="apt-get autoremove -y"
elif command_exists yum; then
remove_cmd="yum remove -y"
cleanup_cmd="yum autoremove -y"
elif command_exists dnf; then
remove_cmd="dnf remove -y"
cleanup_cmd="dnf autoremove -y"
else
log_message "ERROR" "No supported package manager found."
return 1
fi
echo "$packages" | while read -r package; do
if $remove_cmd "$package"; then
log_message "SUCCESS" "Removed package: $package"
else
log_message "ERROR" "Failed to remove package: $package"
fi
done
if $cleanup_cmd; then
log_message "SUCCESS" "Cleaned up dependencies"
fi
}
# Enhanced repository removal function
remove_apt_repos() {
log_message "INFO" "Removing CrowdSec repository entries..."
if ! command_exists apt-get; then
log_message "INFO" "System is not Debian/Ubuntu based, skipping repo removal"
return
fi
local repo_files=("/etc/apt/sources.list" "/etc/apt/sources.list.d/"*)
for file in "${repo_files[@]}"; do
if [ -f "$file" ] && grep -q "crowdsec" "$file"; then
if sed -i '/crowdsec/d' "$file"; then
log_message "SUCCESS" "Removed CrowdSec entry from $file"
else
log_message "ERROR" "Failed to remove CrowdSec entry from $file"
fi
fi
done
if apt-get update >/dev/null 2>&1; then
log_message "SUCCESS" "APT repositories updated"
else
log_message "ERROR" "Failed to update APT repositories"
fi
}
# Enhanced configuration removal function
remove_config() {
log_message "INFO" "Removing CrowdSec configuration files..."
local config_dirs=(
"/etc/crowdsec"
"/var/lib/crowdsec"
"/usr/local/lib/crowdsec"
"/usr/share/crowdsec"
)
for dir in "${config_dirs[@]}"; do
if [ -d "$dir" ]; then
if rm -rf "$dir" 2>/dev/null; then
log_message "SUCCESS" "Removed directory: $dir"
else
log_message "ERROR" "Failed to remove directory: $dir"
fi
fi
done
}
# Function to display script version
show_version() {
echo "CrowdSec Removal Script v${VERSION}"
exit 0
}
# Function to display help
show_help() {
cat << EOF
CrowdSec Removal Script v${VERSION}
Usage: $0 [OPTIONS]
Options:
-n, --nuke Remove all CrowdSec components without prompting
-b, --backup Create backup before removal
-v, --version Show script version
-h, --help Show this help message
The script can run in interactive mode (no options) or automatic mode (-n).
EOF
exit 0
}
# Enhanced main function
main() {
local NUKE=0
local BACKUP=0
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--nuke) NUKE=1 ;;
-b|--backup) BACKUP=1 ;;
-v|--version) show_version ;;
-h|--help) show_help ;;
*) log_message "ERROR" "Unknown option: $1"; exit 1 ;;
esac
shift
done
# Check requirements
check_root
check_system_requirements
# Initialize log file
touch "$LOGFILE" || { echo "Cannot create log file"; exit 1; }
log_message "INFO" "Starting CrowdSec removal script v${VERSION}"
# Create backup if requested
if [ "$BACKUP" -eq 1 ]; then
create_backup
fi
# Check current state
check_services
check_packages
if [ "$NUKE" -eq 1 ]; then
log_message "WARNING" "Performing complete removal of CrowdSec..."
disable_services
remove_packages
remove_apt_repos
remove_config
log_message "SUCCESS" "CrowdSec has been completely removed from your system."
exit 0
fi
if [ -z "$services" ] && [ -z "$packages" ]; then
log_message "SUCCESS" "No CrowdSec components found on your system."
exit 0
fi
# Interactive menu
log_message "INFO" "What would you like to do?"
echo "1) Disable CrowdSec services"
echo "2) Remove CrowdSec packages"
echo "3) Remove everything (services, packages, configuration, and repositories)"
echo "4) Exit without changes"
read -r -p "Enter your choice (1-4): " choice
case $choice in
1) disable_services ;;
2) remove_packages ;;
3)
disable_services
remove_packages
remove_apt_repos
remove_config
;;
4) log_message "INFO" "Exiting without changes."; exit 0 ;;
*) log_message "ERROR" "Invalid choice."; exit 1 ;;
esac
log_message "SUCCESS" "Operations completed successfully."
echo "Log file available at: $LOGFILE"
}
main "$@"