Now for each ssh group we report last login/account create stats. Add the main user group to output Add unlock user commands for locked users Add CSV and JSON formatted output
271 lines
9.1 KiB
Bash
Executable File
271 lines
9.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Checks for last access of users in sshallow group
|
|
# if user login >30days, remoe user from sshallow group and write log
|
|
|
|
# base folder
|
|
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
|
|
# which groups holds the ssh allowed login users (outside of admin users)
|
|
ssh_groups=('sshforward' 'sshallow' 'sshreject');
|
|
ssh_reject_group='sshreject';
|
|
# date now for compare
|
|
now=$(date +"%s");
|
|
# max age for last login or account create without login
|
|
max_age_login=90;
|
|
max_age_create=30;
|
|
# one day in seconds
|
|
day=86400;
|
|
# delete account strings
|
|
lock_accounts="";
|
|
unlock_flag=0;
|
|
unlock_accounts="";
|
|
# only needed for json output
|
|
first_run=1;
|
|
# log base folder
|
|
LOG="${BASE_FOLDER}/../log";
|
|
# auth log file user;date from collect_login_data script
|
|
AUTH_LOG="${BASE_FOLDER}/../auth-log/user_auth.log";
|
|
|
|
if [ $(whoami) != "root" ]; then
|
|
echo "Script must be run as root user";
|
|
exit;
|
|
fi;
|
|
if [ ! -d "${LOG}" ]; then
|
|
echo "log folder ${LOG} not found";
|
|
exit;
|
|
fi;
|
|
# option 1 in list
|
|
case "${1,,}" in
|
|
text)
|
|
OUTPUT_TARGET="text";
|
|
;;
|
|
json)
|
|
OUTPUT_TARGET="json";
|
|
echo "{";
|
|
;;
|
|
csv)
|
|
OUTPUT_TARGET="csv";
|
|
echo "Hostname,Username,Main Group,SSH Group,Account Created Date,Account Age,Last Login Date,Last Login Age,Never Logged In,Login Source,Status";
|
|
;;
|
|
*)
|
|
OUTPUT_TARGET="text";
|
|
;;
|
|
esac;
|
|
|
|
if [ "${OUTPUT_TARGET}" == "text" ]; then
|
|
LOG="${LOG}/check_ssh_user."$(date +"%F_%H%m%S")".log";
|
|
exec &> >(tee -a "${LOG}");
|
|
echo "[START] =============>";
|
|
echo "Hostname : "$(hostname);
|
|
echo "Run date : "$(date +"%F %T");
|
|
echo "Max age last login: ${max_age_login} days";
|
|
echo "Max age no login : ${max_age_create} days";
|
|
elif [ "${OUTPUT_TARGET}" == "json" ]; then
|
|
echo '"Info": {'
|
|
echo '"Hostname": "'$(hostname)'",';
|
|
echo '"Date": "'$(date +"%F %T")'",';
|
|
echo '"MaxAgeLogin": '${max_age_login}',';
|
|
echo '"MaxAgeCreate": '${max_age_create}'';
|
|
echo '},'
|
|
echo '"Users": ['
|
|
fi;
|
|
for ssh_group in ${ssh_groups[@]}; do
|
|
if [ "${OUTPUT_TARGET}" == "text" ]; then
|
|
echo "--------------------->"
|
|
if [ "${ssh_group}" == "${ssh_reject_group}" ]; then
|
|
echo "Showing current SSH Reject users:";
|
|
unlock_flag=1
|
|
else
|
|
echo "Checking Group : ${ssh_group}";
|
|
fi;
|
|
fi;
|
|
for username in $(cat /etc/group|grep "${ssh_group}:" | cut -d ":" -f 4 | sed -e 's/,/ /g'); do
|
|
# check that user exists in passwd
|
|
if ! id "${username}" &>/dev/null; then
|
|
out_string="[!] User $username does not exists in /etc/passwd file";
|
|
case "${OUTPUT_TARGET}" in
|
|
text)
|
|
echo "${out_string}";
|
|
;;
|
|
json)
|
|
echo "{";
|
|
echo '"Username": "'${username}'",';
|
|
echo '"SshGroup": "'${ssh_group}'",';
|
|
echo '"MainGroup": "",';
|
|
echo '"SubGroups": [],';
|
|
echo '"AccountCreatedDate": "",';
|
|
echo '"AccountAge": "",';
|
|
echo '"LastLoginDate": "",';
|
|
echo '"LastLoginAge": "",';
|
|
echo '"LoginSource": "",';
|
|
echo '"NeverLoggedIn": true,';
|
|
echo '"Status": "'${out_string}'"';
|
|
echo "}";
|
|
;;
|
|
csv)
|
|
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" "$(hostname)" "${username}" "" "${ssh_group}" "" "" "" "" "true" "${out_string}"
|
|
;;
|
|
esac;
|
|
continue;
|
|
fi;
|
|
# for json output, we need , between outputs
|
|
if [ "${OUTPUT_TARGET}" == "json" ] && [ $first_run -eq 0 ]; then
|
|
echo ",";
|
|
fi;
|
|
first_run=0;
|
|
# unlock lis of users
|
|
if [ $unlock_flag -eq 1 ]; then
|
|
unlock_accounts="${unlock_accounts} ${username}"
|
|
fi;
|
|
account_age=0;
|
|
lock_user=0;
|
|
out_string="";
|
|
# get the main group for this user
|
|
main_group=$(id -gn "${username}")
|
|
# get all the sub groups for this user, and remove the main groups
|
|
sub_groups=$(id -Gn "${username}" | sed -e "s/${main_group}//" | sed -e "s/${ssh_group}//")
|
|
#echo "* Checking user ${username}";
|
|
# check user create time, if we have set it in comment
|
|
user_create_date_string=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 5);
|
|
# if empty try last password set time
|
|
if [ -z "${user_create_date_string}" ]; then
|
|
# user L 11/09/2020 0 99999 7 -1
|
|
user_create_date_string=$(passwd -S ${username} | cut -d " " -f 3);
|
|
fi;
|
|
# last try is user home .bash_logout
|
|
if [ -z "${user_create_date_string}" ]; then
|
|
home_dir=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 6)"/.bash_logout";
|
|
user_create_date_string=$(stat -c %Z "${home_dir}");
|
|
fi;
|
|
|
|
# below only works if the user logged in, a lot of them are just file upload
|
|
# users. Use the collect script from systemd-logind or /var/log/secure
|
|
# Username Port From Latest
|
|
# user pts/35 10.110.160.230 Wed Nov 2 09:40:35 +0900 2022
|
|
last_login_string=$(lastlog -u ${username} | sed 1d);
|
|
search="Never logged in";
|
|
never_logged_in="false";
|
|
found="";
|
|
login_source="";
|
|
last_login_date="";
|
|
account_age="";
|
|
last_login="";
|
|
# problem with running rep check in if
|
|
if [ -f "${AUTH_LOG}" ]; then
|
|
found=$(grep "${username};" "${AUTH_LOG}");
|
|
fi;
|
|
# always pre work account dates if they exist, but output only if text
|
|
if [ ! -z "${user_create_date_string}" ]; then
|
|
user_create_date=$(echo "${user_create_date_string}" | date +"%s" -f -);
|
|
# if all empty, we continue with only check if user has last login date
|
|
# else get days since creation
|
|
#account_age=$[ ($(date +"%s")-$(date -d "${user_create_date}" +"%s"))/24 ];
|
|
account_age=$(awk '{printf("%.0f\n",($1-$2)/$3)}' <<<"${now} ${user_create_date} ${day}");
|
|
user_create_date_out=$(echo "${user_create_date_string}" | date +"%F" -f -);
|
|
fi;
|
|
if [ ! -z "${found}" ]; then
|
|
last_login_date_string=$(grep "${username};" "${AUTH_LOG}" | cut -d ";" -f 2);
|
|
last_login_date=$(echo "${last_login_date}" | date +"%s" -f -);
|
|
last_login=$(awk '{printf("%.0f\n",($1-$2)/$3)}' <<<"${now} ${last_login_date} ${day}");
|
|
if [ ${last_login} -gt ${max_age_login} ]; then
|
|
out_string="[!] last ssh log in ${last_login} days ago";
|
|
lock_user=1;
|
|
else
|
|
out_string="OK [ssh]";
|
|
fi;
|
|
login_source="ssh";
|
|
# rewrite to Y-M-D, aka
|
|
last_login_date="${last_login_date_string}"
|
|
elif [ ! -z "${last_login_string##*$search*}" ]; then
|
|
# if we have "** Never logged in**" the user never logged in
|
|
# find \w{3} \w{3} [\s\d]{2} \d{2}:\d{2}:\d{2} \+\d{4} \d{4}
|
|
# awk '{for(i=4;i<=NF;++i)printf $i FS}'
|
|
last_login_date=$(echo "${last_login_string}" | awk '{for(i=4;i<=NF;++i)printf $i FS}' | date +"%s" -f -);
|
|
# date -d "Wed Nov 2 09:40:35 +0900 2022" +%s
|
|
last_login=$(awk '{printf("%.0f\n",($1-$2)/$3)}' <<<"${now} ${last_login_date} ${day}");
|
|
if [ ${last_login} -gt ${max_age_login} ]; then
|
|
out_string="[!] last terminal log in ${last_login} days ago";
|
|
lock_user=1;
|
|
else
|
|
out_string="OK [lastlog]";
|
|
fi;
|
|
login_source="lastlog";
|
|
last_login_date=$(echo "${last_login_string}" | awk '{for(i=4;i<=NF;++i)printf $i FS}' | date +"%F %T" -f -)
|
|
elif [ ! -z "${user_create_date}" ]; then
|
|
if [ ${account_age} -gt ${max_age_create} ]; then
|
|
out_string="[!] Never logged in: account created ${account_age} days ago";
|
|
lock_user=1;
|
|
else
|
|
out_string="OK [Never logged in]";
|
|
fi;
|
|
never_logged_in="true";
|
|
else
|
|
out_string="[!!!] Never logged in and we have no create date";
|
|
never_logged_in="true";
|
|
fi;
|
|
# build delete output
|
|
if [ ${lock_user} = 1 ]; then
|
|
lock_accounts="${lock_accounts} ${username}"
|
|
fi;
|
|
case "${OUTPUT_TARGET}" in
|
|
text)
|
|
printf "* Checking user %-20s (%-20s): %s\n" "${username}" "${main_group}" "${out_string}";
|
|
;;
|
|
json)
|
|
sub_groups_string="["
|
|
sub_group_first=1
|
|
for s_group in $sub_groups; do
|
|
if [ "${sub_group_first}" == 0 ]; then
|
|
sub_groups_string="${sub_groups_string},";
|
|
fi;
|
|
sub_groups_string="${sub_groups_string}\"${s_group}\"";
|
|
sub_group_first=0;
|
|
done;
|
|
sub_groups_string="${sub_groups_string}]";
|
|
echo "{";
|
|
echo '"Username": "'${username}'",';
|
|
echo '"SshGroup": "'${ssh_group}'",';
|
|
echo '"MainGroup": "'${main_group}'",';
|
|
echo '"SubGroups": '${sub_groups_string}',';
|
|
echo '"AccountCreatedDate": "'${user_create_date_out}'",';
|
|
echo '"AccountAge": "'${account_age}'",';
|
|
echo '"LastLoginDate": "'${last_login_date}'",';
|
|
echo '"LastLoginAge": "'${last_login}'",';
|
|
echo '"LoginSource": "'${login_source}'",';
|
|
echo '"NeverLoggedIn": '${never_logged_in}',';
|
|
echo '"Status": "'${out_string}'"';
|
|
echo "}";
|
|
;;
|
|
csv)
|
|
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" "$(hostname)" "${username}" "${main_group}" "${ssh_group}" "${user_create_date_out}" "${account_age}" "${last_login_date}" "${last_login}" "${never_logged_in}" "${login_source}" "${out_string}"
|
|
;;
|
|
esac;
|
|
done;
|
|
done;
|
|
if [ "${OUTPUT_TARGET}" == "text" ]; then
|
|
if [ ! -z "${lock_accounts}" ]; then
|
|
echo "--------------------->"
|
|
echo "% Run script below to move users to reject ssh group";
|
|
echo "";
|
|
echo "bin/lock_user.sh ${lock_accounts}";
|
|
fi;
|
|
if [ ! -z "${unlock_accounts}" ]; then
|
|
echo "--------------------->"
|
|
echo "% Run script below to move users to allow or forward ssh group";
|
|
echo "";
|
|
echo "For ALLOW:"
|
|
echo "bin/unlock_user.sh -s allow ${lock_accounts}";
|
|
echo "";
|
|
echo "For FORWARDONLY:"
|
|
echo "bin/unlock_user.sh -s forward ${lock_accounts}";
|
|
fi;
|
|
echo "[END] ===============>"
|
|
elif [ "${OUTPUT_TARGET}" == "json" ]; then
|
|
# users
|
|
echo "]";
|
|
# overall
|
|
echo "}";
|
|
fi;
|
|
|
|
# __END__
|