@@ -233,7 +233,6 @@ ENDSSH
233233# Main harden command
234234cmd_harden () {
235235 load_config
236- ensure_gum_for_ui
237236
238237 info " ShipNode Security Hardening"
239238 info " This wizard will guide you through basic server hardening."
@@ -249,7 +248,8 @@ cmd_harden() {
249248 echo " "
250249
251250 # Check SSH service status
252- local ssh_status=$( check_ssh_service)
251+ local ssh_status
252+ ssh_status=$( check_ssh_service)
253253 if [[ " $ssh_status " == * " NOT_FOUND" * ]]; then
254254 warn " SSH service not detected on remote server"
255255 elif [[ " $ssh_status " == * " INACTIVE" * ]]; then
@@ -259,275 +259,205 @@ cmd_harden() {
259259
260260 local changes_made=0
261261 local backup_path=" "
262+ local ssh_changes=0
263+ local summary=()
262264
263265 # ==================== SSH Hardening ====================
264266 info " === SSH Configuration Hardening ==="
265267 echo " "
266268
267- # Show current SSH settings
268- local current_port=$( get_ssh_config " Port" )
269- local current_permit_root=$( get_ssh_config " PermitRootLogin" )
270- local current_password_auth=$( get_ssh_config " PasswordAuthentication" )
269+ local current_port current_permit_root current_password_auth
270+ current_port=$( get_ssh_config " Port" )
271+ current_permit_root=$( get_ssh_config " PermitRootLogin" )
272+ current_password_auth=$( get_ssh_config " PasswordAuthentication" )
271273
272274 echo " Current SSH Configuration:"
273- echo " Port: ${current_port:- 22} (default if not set) "
274- echo " PermitRootLogin: ${current_permit_root:- yes} (default if not set) "
275- echo " PasswordAuthentication: ${current_password_auth:- yes} (default if not set) "
275+ echo " Port: ${current_port:- 22 (default)} "
276+ echo " PermitRootLogin: ${current_permit_root:- yes (default)} "
277+ echo " PasswordAuthentication: ${current_password_auth:- yes (default)} "
276278 echo " "
277279
278- # Ask if user wants to harden SSH
279- echo " "
280- if gum_confirm " Would you like to configure SSH hardening?" " n" ; then
280+ if prompt_yes_no " Configure SSH hardening?" " n" ; then
281281 backup_path=$( backup_ssh_config)
282282 info " SSH config backed up to: $backup_path "
283283 echo " "
284284
285285 # Change SSH port
286- if gum_confirm " Change SSH port from default (22) ?" " n" ; then
286+ if prompt_yes_no " Change SSH port from ${current_port :- 22} ?" " n" ; then
287287 echo " "
288- info " Available ports:"
289- echo " 1) 2222 (commonly used alternative)"
288+ echo " 1) 2222 (common alternative)"
290289 echo " 2) 1022 (registered alternative)"
291290 echo " 3) Custom port"
292291 echo " "
293-
294- local port_choice=$( gum_choose " Select new SSH port:" " 2222" " 1022" " Custom port" )
292+ read -rp " Select option [1-3]: " port_choice
295293
296294 local new_port=" "
297295 case " $port_choice " in
298- " 2222" )
299- new_port=" 2222"
300- ;;
301- " 1022" )
302- new_port=" 1022"
303- ;;
304- " Custom port" )
305- new_port=$( gum_input " Enter custom SSH port (1024-65535):" " " )
296+ 1) new_port=" 2222" ;;
297+ 2) new_port=" 1022" ;;
298+ 3)
299+ read -rp " Enter port (1024-65535): " new_port
306300 if [[ ! " $new_port " =~ ^[0-9]+$ ]] || [ " $new_port " -lt 1024 ] || [ " $new_port " -gt 65535 ]; then
307- warn " Invalid port number . Skipping port change ."
301+ warn " Invalid port. Skipping."
308302 new_port=" "
309303 fi
310304 ;;
305+ * ) warn " Invalid choice. Skipping port change." ;;
311306 esac
312307
313308 if [ -n " $new_port " ]; then
314- # Check if port is already in use on the remote server
315- local port_in_use=$( remote_exec " ss -tlnp 2>/dev/null | grep -c ':${new_port} ' || true" )
309+ local port_in_use
310+ port_in_use=$( remote_exec " ss -tlnp 2>/dev/null | grep -c ':${new_port} ' || true" )
316311 if [ " ${port_in_use:- 0} " -gt 0 ]; then
317- warn " Port $new_port is already in use on the remote server . Skipping port change ."
312+ warn " Port $new_port already in use. Skipping."
318313 new_port=" "
319314 fi
320315 fi
321316
322317 if [ -n " $new_port " ]; then
323318 echo " "
324- warn " Changing SSH port to $new_port "
319+ warn " After this change connect with: ssh -p $new_port $SSH_USER @$SSH_HOST "
320+ echo " Rollback: set 'Port $new_port ' back to 'Port 22' in /etc/ssh/sshd_config"
325321 echo " "
326- echo " ⚠ IMPORTANT: Make sure to update your firewall and SSH client configuration!"
327- echo " After this change, connect using: ssh -p $new_port $SSH_USER @$SSH_HOST "
328- echo " "
329- echo " Rollback: Edit /etc/ssh/sshd_config and change 'Port $new_port ' to 'Port 22'"
330- echo " "
331-
332- if gum_confirm " Proceed with changing SSH port to $new_port ?" " n" ; then
322+ if prompt_yes_no " Proceed with port change to $new_port ?" " n" ; then
333323 apply_ssh_config " Port" " $new_port "
334324 SSH_PORT=" $new_port "
335- # Persist SSH_PORT to shipnode.conf on the server
336325 sed -i " s/^SSH_PORT=.*/SSH_PORT=${new_port} /" shipnode.conf 2> /dev/null || true
337- (( changes_made++ ))
338- success " SSH port configured: $new_port "
339- echo " "
340- else
341- info " SSH port change skipped."
342- echo " "
326+ (( ssh_changes++ ))
327+ summary+=(" SSH port changed to $new_port " )
343328 fi
344329 fi
345330 fi
346331
347332 # Disable root login
348- if gum_confirm " Disable root login via SSH?" " n" ; then
349- echo " "
350- warn " This will prevent direct root SSH access."
351- echo " Rollback: Edit /etc/ssh/sshd_config and change 'PermitRootLogin no' to 'PermitRootLogin yes'"
352- echo " "
353-
354- if gum_confirm " Proceed with disabling root login?" " n" ; then
333+ if prompt_yes_no " Disable root login via SSH?" " n" ; then
334+ echo " Rollback: set 'PermitRootLogin no' back to 'yes' in /etc/ssh/sshd_config"
335+ if prompt_yes_no " Proceed?" " n" ; then
355336 apply_ssh_config " PermitRootLogin" " no"
356- (( changes_made++ ))
357- success " Root login disabled via SSH"
358- echo " "
359- else
360- info " Root login change skipped."
361- echo " "
337+ (( ssh_changes++ ))
338+ summary+=(" Root login disabled" )
362339 fi
363340 fi
364341
365342 # Disable password authentication
366- if gum_confirm " Disable password authentication (key-based auth only)?" " n" ; then
367- echo " "
368- warn " This will disable password authentication."
369- echo " ⚠ WARNING: Make sure you have SSH key access configured before proceeding!"
370- echo " "
371- echo " Rollback: Edit /etc/ssh/sshd_config and change 'PasswordAuthentication no' to 'PasswordAuthentication yes'"
372- echo " "
373-
374- if gum_confirm " Are you sure? You must have SSH key access!" " n" ; then
343+ if prompt_yes_no " Disable password authentication (key-based only)?" " n" ; then
344+ warn " Ensure SSH key access is configured before proceeding!"
345+ echo " Rollback: set 'PasswordAuthentication no' back to 'yes' in /etc/ssh/sshd_config"
346+ if prompt_yes_no " Proceed? (you must have SSH key access)" " n" ; then
375347 apply_ssh_config " PasswordAuthentication" " no"
376- (( changes_made++ ))
377- success " Password authentication disabled"
378- echo " "
379- else
380- info " Password authentication change skipped."
381- echo " "
348+ (( ssh_changes++ ))
349+ summary+=(" Password authentication disabled" )
382350 fi
383351 fi
384352
385- # Restart SSH if changes were made
386- if [ $changes_made -gt 0 ]; then
353+ if [ " $ssh_changes " -gt 0 ]; then
387354 echo " "
388- info " Restarting SSH service to apply changes ..."
355+ info " Restarting SSH service..."
389356 restart_ssh_service
390357 success " SSH service restarted"
391- echo " "
358+ (( changes_made += ssh_changes ))
392359 fi
393- else
394- info " SSH hardening skipped."
395- echo " "
396360 fi
361+ echo " "
397362
398363 # ==================== Firewall Configuration ====================
399364 info " === Firewall Configuration (UFW) ==="
400365 echo " "
401366
402- local ufw_status=$( check_ufw)
367+ local ufw_status
368+ ufw_status=$( check_ufw)
403369 if [[ " $ufw_status " == " UFW_NOT_INSTALLED" ]]; then
404- info " UFW (Uncomplicated Firewall) is not installed."
405- if gum_confirm " Install and configure UFW firewall?" " y" ; then
406- echo " "
370+ info " UFW is not installed."
371+ if prompt_yes_no " Install UFW?" " y" ; then
407372 info " Installing UFW..."
408373 install_ufw
409374 success " UFW installed"
410- echo " "
411- else
412- warn " Firewall configuration skipped."
413- echo " "
375+ summary+=(" UFW installed" )
414376 fi
415377 else
416378 echo " Current UFW status:"
417379 echo " $ufw_status "
418- echo " "
419380 fi
381+ echo " "
420382
421- # Check UFW again after potential install
422383 ufw_status=$( check_ufw)
423384 if [[ " $ufw_status " != " UFW_NOT_INSTALLED" ]]; then
424- if gum_confirm " Configure UFW firewall rules (SSH, HTTP, HTTPS)?" " y" ; then
425- echo " "
426- echo " Firewall rules to be applied:"
427- echo " ✓ Allow SSH (port ${SSH_PORT:- 22} )"
428- echo " ✓ Allow HTTP (port 80)"
429- echo " ✓ Allow HTTPS (port 443)"
430- echo " ✗ Deny all other incoming traffic"
431- echo " "
432- echo " Rollback: Run 'sudo ufw disable' or 'sudo ufw reset'"
433- echo " "
434-
435- if gum_confirm " Proceed with firewall configuration?" " y" ; then
436- apply_firewall_rules " ${SSH_PORT:- 22} "
437- (( changes_made++ ))
438- success " Firewall configured successfully"
439- echo " "
440- info " Current status:"
441- check_ufw
442- echo " "
443- else
444- info " Firewall configuration skipped."
445- echo " "
446- fi
447- else
448- info " Firewall configuration skipped."
385+ echo " Rules to apply: SSH (${SSH_PORT:- 22} ), HTTP (80), HTTPS (443) — deny everything else"
386+ echo " Rollback: sudo ufw disable"
387+ if prompt_yes_no " Configure UFW rules?" " y" ; then
388+ apply_firewall_rules " ${SSH_PORT:- 22} "
389+ (( changes_made++ ))
390+ summary+=(" UFW configured: SSH/HTTP/HTTPS allowed, all else denied" )
391+ success " Firewall configured"
449392 echo " "
393+ check_ufw
450394 fi
451395 fi
396+ echo " "
452397
453398 # ==================== Fail2ban Configuration ====================
454399 info " === Fail2ban (Intrusion Prevention) ==="
455400 echo " "
456401
457- local fail2ban_status=$( check_fail2ban)
402+ local fail2ban_status
403+ fail2ban_status=$( check_fail2ban)
458404 case " $fail2ban_status " in
459405 " ACTIVE" )
460- info " Fail2ban is already installed and active"
461- echo " "
406+ success " Fail2ban already installed and active"
462407 ;;
463408 " INSTALLED_INACTIVE" )
464- warn " Fail2ban is installed but not running"
465- if gum_confirm " Start and enable fail2ban?" " y" ; then
409+ warn " Fail2ban installed but not running"
410+ if prompt_yes_no " Start and enable fail2ban?" " y" ; then
466411 remote_exec " sudo systemctl start fail2ban && sudo systemctl enable fail2ban"
467412 success " Fail2ban started and enabled"
468413 (( changes_made++ ))
414+ summary+=(" Fail2ban started and enabled" )
469415 fi
470- echo " "
471416 ;;
472417 " NOT_INSTALLED" )
473- info " Fail2ban is not installed."
474- echo " Fail2ban monitors log files and bans IPs that show malicious signs (e.g., multiple failed SSH attempts)."
475- echo " "
476-
477- if gum_confirm " Install and configure fail2ban?" " n" ; then
478- echo " "
418+ info " Fail2ban not installed."
419+ echo " Monitors logs and bans IPs after repeated failed SSH attempts."
420+ echo " Config: 5 retries / 10 min window / 1 hour ban"
421+ echo " Rollback: sudo systemctl stop fail2ban && sudo systemctl disable fail2ban"
422+ if prompt_yes_no " Install and configure fail2ban?" " n" ; then
479423 info " Installing fail2ban..."
480424 install_configure_fail2ban
481425 success " Fail2ban installed and configured"
482- echo " "
483- echo " Configuration:"
484- echo " - Max retry: 5 attempts"
485- echo " - Find time: 10 minutes"
486- echo " - Ban time: 1 hour"
487- echo " "
488- echo " Rollback: sudo systemctl stop fail2ban && sudo systemctl disable fail2ban"
489- echo " Then remove the package using your system's package manager"
490- echo " "
491426 (( changes_made++ ))
492- else
493- info " Fail2ban installation skipped."
494- echo " "
427+ summary+=(" Fail2ban installed (5 retries / 10 min / 1 hr ban)" )
495428 fi
496429 ;;
497430 esac
431+ echo " "
498432
499433 # ==================== Summary ====================
500- echo " "
501434 info " === Security Hardening Summary ==="
502435 echo " "
503436
504- if [ $changes_made -eq 0 ]; then
505- warn " No security changes were made."
506- info " Server configuration remains unchanged."
437+ if [ ${# summary[@]} -eq 0 ]; then
438+ warn " No changes made. Server configuration unchanged."
507439 else
508- success " Security hardening completed!"
509- info " Total changes applied: $changes_made "
440+ success " Changes applied: ${# summary[@]} "
441+ echo " "
442+ for item in " ${summary[@]} " ; do
443+ echo " ✓ $item "
444+ done
510445 echo " "
511446
512- if [ -n " $backup_path " ]; then
513- info " SSH configuration backup: $backup_path "
514- fi
447+ [ -n " $backup_path " ] && info " SSH config backup: $backup_path "
515448
516449 echo " "
517- echo " Important reminders:"
518- echo " - Test your SSH connection before closing this session"
519- echo " - If you changed the SSH port, update your SSH client config"
520- echo " - Review firewall rules with: sudo ufw status"
521- echo " - Check fail2ban status with: sudo fail2ban-client status"
450+ echo " Reminders:"
451+ echo " - Test SSH connection before closing this session"
452+ echo " - Review firewall: sudo ufw status"
453+ echo " - Check fail2ban: sudo fail2ban-client status"
522454 echo " "
523455
524- # Test SSH connection
525456 info " Testing SSH connection..."
526457 if remote_exec " exit" & > /dev/null; then
527458 success " SSH connection verified"
528459 else
529- warn " SSH connection test failed!"
530- warn " Please verify your connection settings before disconnecting."
460+ warn " SSH connection test failed — verify settings before disconnecting!"
531461 fi
532462 fi
533463
0 commit comments