diff --git a/firewalld.sh b/firewalld.sh new file mode 100644 index 0000000..434bbc0 --- /dev/null +++ b/firewalld.sh @@ -0,0 +1,271 @@ +#!/bin/bash + +# ========================================== +# INTERACTIVE FIREWALL CONFIGURATOR FOR SAP B1 +# ========================================== + +# Colors for formatting +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# ========================================== +# SERVICE DEFINITIONS +# ========================================== +# Format: "Service Name" "Ports (space separated)" +declare -a SVC_NAMES +declare -a SVC_PORTS + +SVC_NAMES[0]="SAP Web Client" +SVC_PORTS[0]="443" + +SVC_NAMES[1]="SAP HANA Database (System & Company DB)" +SVC_PORTS[1]="30013 30015" + +SVC_NAMES[2]="SAP Business One App Stack (SLD/Auth/SL/Cockpit)" +SVC_PORTS[2]="40000 40020 50000 4300" + +SVC_NAMES[3]="SAP Host Agent" +SVC_PORTS[3]="1128 1129" + +SVC_NAMES[4]="SSH Remote Access" +SVC_PORTS[4]="22" + +# Arrays to store user decisions +declare -a CONFIG_DECISION # "ALL", "IP", "SKIP" +declare -a CONFIG_IPS # Stores the IP string if "IP" is chosen +DO_FLUSH=false + +# ========================================== +# HELPER FUNCTIONS +# ========================================== + +print_header() { + clear + echo -e "${CYAN}==========================================${NC}" + echo -e "${CYAN} SAP B1 Interactive Firewall Setup ${NC}" + echo -e "${CYAN}==========================================${NC}" + echo "" +} + +# ========================================== +# INITIAL SETUP QUESTIONS +# ========================================== +print_header +echo -e "${YELLOW}Existing Configuration:${NC}" +echo "Do you want to FLUSH (remove) all currently active firewall rules before starting?" +echo "This ensures a clean slate. (Only affects Runtime, not Permanent config)" +read -p "Flush all current rules? (y/n): " flush_choice +if [[ "$flush_choice" =~ ^[Yy]$ ]]; then + DO_FLUSH=true + echo -e "-> ${RED}Will flush all rules (Clean Slate).${NC}" +else + echo -e "-> Keeping existing rules (Appending new ones)." +fi +echo "" +sleep 1 + +# ========================================== +# CONFIGURATION LOOP +# ========================================== + +print_header +echo -e "This script will help you configure access rules for each service." +echo -e "${YELLOW}Note: Configuration applies to RUNTIME only.${NC}" +echo "" + +for i in "${!SVC_NAMES[@]}"; do + NAME="${SVC_NAMES[$i]}" + PORTS="${SVC_PORTS[$i]}" + + echo -e "--------------------------------------------------" + echo -e "Configuring Service: ${GREEN}$NAME${NC}" + echo -e "Ports: ${YELLOW}$PORTS${NC}" + echo "--------------------------------------------------" + echo "1) Allow from ANYWHERE (Public)" + echo "2) Restrict to SPECIFIC IPs" + echo "3) Skip / Block (Do not open)" + + while true; do + read -p "Select option (1-3): " choice + case $choice in + 1) + CONFIG_DECISION[$i]="ALL" + CONFIG_IPS[$i]="" + echo -e "-> Selected: ${RED}Public Access${NC}" + break + ;; + 2) + CONFIG_DECISION[$i]="IP" + echo "" + echo -e "Enter IPs or Subnets separated by spaces or commas." + echo -e "Example: ${CYAN}192.168.1.10, 192.168.1.20${NC}" + read -p "IPs: " ip_input + # Replace commas with spaces to sanitize + CONFIG_IPS[$i]="${ip_input//,/ }" + echo -e "-> Selected: ${GREEN}Restricted to ${CONFIG_IPS[$i]}${NC}" + break + ;; + 3) + CONFIG_DECISION[$i]="SKIP" + CONFIG_IPS[$i]="" + echo -e "-> Selected: ${YELLOW}Skipping${NC}" + break + ;; + *) + echo "Invalid option." + ;; + esac + done + echo "" +done + +# ========================================== +# SUMMARY & CONFIRMATION +# ========================================== + +print_header +echo -e "${YELLOW}SUMMARY OF PENDING CHANGES:${NC}" +echo "" +printf "%-25s | %-15s | %-30s\n" "Service" "Action" "Details" +echo "-------------------------------------------------------------------------------" + +for i in "${!SVC_NAMES[@]}"; do + NAME="${SVC_NAMES[$i]}" + ACTION="${CONFIG_DECISION[$i]}" + DETAILS="${CONFIG_IPS[$i]}" + + # Shorten name for table + SHORT_NAME=${NAME:0:24} + + if [ "$ACTION" == "ALL" ]; then + printf "%-25s | ${RED}%-15s${NC} | %-30s\n" "$SHORT_NAME" "Open Public" "0.0.0.0/0" + elif [ "$ACTION" == "IP" ]; then + printf "%-25s | ${GREEN}%-15s${NC} | %-30s\n" "$SHORT_NAME" "Restricted" "$DETAILS" + else + printf "%-25s | ${YELLOW}%-15s${NC} | %-30s\n" "$SHORT_NAME" "Blocked/Skip" "-" + fi +done + +echo "" +echo -e "${CYAN}Global Actions:${NC}" +if [ "$DO_FLUSH" = true ]; then + echo "1. FLUSH ALL current rules (Clean Slate)." +else + echo "1. Remove specific insecure rules (0-65535) and standard SSH service." +fi +echo "" + +read -p "Do you want to apply these changes now? (y/n): " confirm +if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Aborted." + exit 0 +fi + +# ========================================== +# EXECUTION +# ========================================== +echo "" +echo "Applying configurations (RUNTIME ONLY)..." + +# 1. Flush or Safety Cleanup +if [ "$DO_FLUSH" = true ]; then + echo "-> Flushing active rules..." + # Flush Services + for service in $(firewall-cmd --list-services); do + firewall-cmd --remove-service="$service" >/dev/null 2>&1 + done + # Flush Ports + for port in $(firewall-cmd --list-ports); do + firewall-cmd --remove-port="$port" >/dev/null 2>&1 + done + # Flush Rich Rules + # Reading line by line to handle spaces within rules + firewall-cmd --list-rich-rules | while read -r rule; do + if [ -n "$rule" ]; then + firewall-cmd --remove-rich-rule="$rule" >/dev/null 2>&1 + fi + done +else + # Only remove specific conflicting rules if not flushing everything + echo "-> Cleaning up insecure rules..." + firewall-cmd --remove-port=0-65535/tcp >/dev/null 2>&1 + # Remove standard SSH service so we can apply precise rules + firewall-cmd --remove-service=ssh >/dev/null 2>&1 + firewall-cmd --remove-port=22/tcp >/dev/null 2>&1 +fi + +# 2. Loop and Apply +for i in "${!SVC_NAMES[@]}"; do + PORTS="${SVC_PORTS[$i]}" + DECISION="${CONFIG_DECISION[$i]}" + + # Convert space-separated ports to array for inner loop + read -ra PORT_ARR <<< "$PORTS" + + if [ "$DECISION" == "ALL" ]; then + # Open ports globally + for port in "${PORT_ARR[@]}"; do + echo " Opening $port globally..." + firewall-cmd --add-port=${port}/tcp >/dev/null + done + + elif [ "$DECISION" == "IP" ]; then + # Add rich rules for specific IPs + read -ra IP_ARR <<< "${CONFIG_IPS[$i]}" + + for ip in "${IP_ARR[@]}"; do + # Sanity check for empty strings + if [[ -z "$ip" ]]; then continue; fi + + for port in "${PORT_ARR[@]}"; do + echo " Allowing $ip access to port $port..." + firewall-cmd --add-rich-rule="rule family='ipv4' source address='$ip' port port='$port' protocol='tcp' accept" >/dev/null + done + done + fi +done + +echo "" +echo -e "${YELLOW}==========================================${NC}" +echo -e "${YELLOW} TESTING CONNECTIVITY ${NC}" +echo -e "${YELLOW}==========================================${NC}" +echo "The new rules are active. If you are locked out, DO NOTHING." +echo "The firewall will automatically REVERT in 15 seconds." +echo "" +echo -e "${GREEN}If you can read this and your connection works:${NC}" +echo -e "Press ${CYAN}ENTER${NC} now to CONFIRM and KEEP the changes." +echo "OR press Ctrl+C to keep changes without saving (script exits)." +echo "" + +if read -t 15 -p "Waiting for confirmation... "; then + # User pressed Enter (Connection is good) + echo "" + echo -e "${GREEN}Connection confirmed!${NC}" + echo "" + read -p "Do you want to save these rules PERMANENTLY now? (y/n): " save_choice + if [[ "$save_choice" =~ ^[Yy]$ ]]; then + echo "Saving to permanent configuration..." + firewall-cmd --runtime-to-permanent + echo -e "${GREEN}Configuration Saved.${NC}" + else + echo "Rules kept in RUNTIME only. They will be lost on reboot." + fi +else + # Timeout occurred (User likely locked out) + echo "" + echo -e "${RED}Timeout reached! Reverting changes...${NC}" + + # Revert Logic + echo "1. Reloading permanent configuration..." + firewall-cmd --reload >/dev/null 2>&1 + + echo "2. Ensuring SSH is accessible (Failsafe)..." + firewall-cmd --add-service=ssh >/dev/null 2>&1 + + echo -e "${YELLOW}Firewall reverted to previous state (plus global SSH allow).${NC}" +fi + +exit 0 \ No newline at end of file