Skip to content

Instantly share code, notes, and snippets.

@Coopeh
Last active December 22, 2021 19:41
Show Gist options
  • Save Coopeh/4ab987e5b8210e4222a82c2581aed861 to your computer and use it in GitHub Desktop.
Save Coopeh/4ab987e5b8210e4222a82c2581aed861 to your computer and use it in GitHub Desktop.
SSH Idle Session Kicker
#!/usr/bin/env bash
###
#
# SSH Inactive Session Killer
#
###
# Set idle time in hours - default is 12
idle_time="12"
# Where to store session file for logging - default is /var/ssh-session
session_directory="/var/ssh-session"
#############
# If idle_time is left empty, set to default of 12 hours
if [[ -z $idle_time ]]; then
idle_time="12"
fi
# If session directory is left empty, set to default of /var/ssh-session
if [[ -z $session_directory ]]; then
session_directory="/var/ssh-session"
fi
# Exit on script error - https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -uo pipefail
# Warning and disconnect timing variables in hours
warning_time=$( date -d "$((idle_time - 1)) hours ago" +%s )
disconnect_time=$(date -d "$idle_time hours ago" +%s)
# Create the sessions directory
if [ ! -d "$session_directory" ]; then
mkdir -p "$session_directory"
fi
# Create arrays from new lines
IFS=$'\n';
# Function to create array of user session info
user_info() {
who -s | awk '{ print $2 }' | (cd /dev && xargs stat -c '%n %U %X') | awk '{print $1" "$2" "$3}' | grep -v "root|grep" | sort -k 3,3
}
user_sessions=$(user_info)
# Remove non-idle session files
for f in "$session_directory"/*; do
# Check that this is definitely a file
test -f "$f" || continue
# Create reusable variables for checking session and idle time for arithmetic later
session_check=$(echo "${user_sessions[*]}" | grep "pts/${f##*/}")
session_idle_time=$(echo "${user_sessions[*]}" | grep "pts/${f##*/}" | awk '{print $3}')
# Check if the file exists but there's no longer a session
if [[ -z $session_check ]]; then
rm "$f"
echo "pts/${f##*/} no longer connected, removing session file"
continue
# Check if the file exists, but is no longer an inactive session
elif [[ ! -z $session_check ]] && [[ $session_idle_time > $warning_time ]]; then
rm "$f"
echo "pts/${f##*/} no longer an inactive session, removing session file"
continue
fi
done
# Loop through the current connected users
for i in ${user_sessions[*]}; do
# Create pts, user and session variables from the connected user data
pts=$(echo "$i" | awk '{print $1}' | cut -d '/' -f2)
user=$(echo "$i" | awk '{print $2}')
session=$(echo "$i" | awk '{print $3}')
# If the session is idle for over the idle cut off time
if [[ $session < $warning_time ]]; then
# If the session file doesn't exist, create it and warn the user that they will be disconnected
if [[ ! -f "$session_directory/$pts" ]]; then
touch "$session_directory/$pts"
echo "Hi $user. Your SSH session has been inactive for $((idle_time - 1)) hours, it will be closed in 1 hour at $(date -d '1 hour') if no activity is detected." | write "$user" "pts/$pts"
continue
# If the session file exists, check it hasn't been there for the idle cut off time
# Kill the session if over idle cut off time
elif [[ -f "$session_directory/$pts" && $session < $disconnect_time ]]; then
pkill -9 -t "pts/$pts"
rm "$session_directory/$pts"
fi
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment