Compare commits

...

12 Commits

Author SHA1 Message Date
Clemens Schwaighofer
66213dfd65 Text fixes for check last login 2023-12-21 16:06:53 +09:00
Clemens Schwaighofer
39da44b546 Wrong unlock account var used for unlock users 2023-12-21 16:01:35 +09:00
Clemens Schwaighofer
d4bb06e3e1 Fix lock user flow to only lock if the user is not in the reject group 2023-12-21 15:58:28 +09:00
Clemens Schwaighofer
cc647de495 Readme update 2023-12-21 15:14:57 +09:00
Clemens Schwaighofer
68b450baaf Add warning message for logins 2023-12-21 13:46:58 +09:00
Clemens Schwaighofer
8452a1b8c0 Fix pre check for ssh login checks 2023-12-21 13:35:50 +09:00
Clemens Schwaighofer
3fcb74ac47 Update check last login script with better reporting and csv/json output
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
2023-12-21 13:23:35 +09:00
Clemens Schwaighofer
70212da3cb systemd logs end with dot and we split, so we missed user names with . inside 2023-12-20 17:51:35 +09:00
Clemens Schwaighofer
168cf9db15 Create user output was using wrong var for SSH access type 2023-08-21 09:41:23 +09:00
Clemens Schwaighofer
92ef3f0f2e The GO flag for create_user was default 1 instead of 0
Script must be run with -g flag but for that the GO flag must be default
0.
2023-08-21 09:38:00 +09:00
Clemens Schwaighofer
f181ee74e3 Bug fix: missing ;; in case in create_user script 2023-08-21 09:36:42 +09:00
Clemens Schwaighofer
93224e3768 Update create/delete scripts, add rename script
rename user script added: renames user, home dir and connected files.

delete script fix with remove of not needed options (-g)

Update all scripts to exit only after all errors are shown, unless it
is a critical run error.
2023-08-08 10:50:08 +09:00
6 changed files with 501 additions and 73 deletions

View File

@@ -256,3 +256,77 @@ The script can be put into the crontab and run once a month, it prints to STDOUT
```crontab
0 2 1 * * root /root/users/bin/check_last_login.sh | mail -s "User Account check: $(hostname)"
```
For processable output there is a "csv" and "json" option to output the data in CSV or JSON format
Example csv
```csv
Hostname,Username,Main Group,SSH Group,Account Created Date,Account Age,Last Login Date,Last Login Age,Login Source,Never Logged In,Status
some.host,name_a,staff,sshallow,2021-11-18,764,,,,true,[!] Never logged in: account created 764 days ago
some.host,name_b,staff,sshallow,2021-11-15,767,2023-12-20 22:18:36,1,ssh,false,OK [ssh]
...
```
```json
{
"Info": {
"Hostname": "host.name",
"Date": "2023-12-21 13:11:45",
"MaxAgeLogin": 90,
"MaxAgeCreate": 30
},
"Users": [
{
"Username": "name_a",
"SshGroup": "sshallow",
"MainGroup": "staff",
"SubGroups": [],
"AccountCreatedDate": "2021-11-18",
"AccountAge": "764",
"LastLoginDate": "",
"LastLoginAge": "",
"LoginSource": "",
"NeverLoggedIn": true,
"Status": "[!] Never logged in: account created 764 days ago"
},
{
"Username": "name_b",
"SshGroup": "sshallow",
"MainGroup": "staff",
"SubGroups": [
"sudo",
"users",
"group_a",
"group_b",
],
"AccountCreatedDate": "2021-11-15",
"AccountAge": "767",
"LastLoginDate": "2023-12-20 22:18:36",
"LastLoginAge": "1",
"LoginSource": "ssh",
"NeverLoggedIn": false,
"Status": "OK [ssh]"
},
]
}
```
## Delete users
`bin/delete_user.sh -t -b <user 1> <user 2> ...`
Deletes one or more users
- `-t` test, no action done
- `-b` do not create a backup
Unless `-b` is set the home folder and public key in /etc/ssh will be backed up.
Flags user with #DELETED-YYYYMMDD_HHmmss:id;... in the user_list.txt file
## Rename user
`bin/rename_user.sh -t -o <current user name> -n <new user name>`
Renames a user including the home directory, public key files and any other connected data.
Also updates the user_list.txt

View File

@@ -6,17 +6,22 @@
# base folder
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
# which groups holds the ssh allowed login users (outside of admin users)
ssh_groups=('sshforward' 'sshallow');
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=60;
max_age_login=90;
warn_age_login=80;
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
@@ -30,37 +35,110 @@ if [ ! -d "${LOG}" ]; then
echo "log folder ${LOG} not found";
exit;
fi;
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";
# 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 "Warn age last login: ${warn_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 '"WarnAgeLogin": '${warn_age_login}',';
echo '"MaxAgeCreate": '${max_age_create}'';
echo '},'
echo '"Users": ['
fi;
for ssh_group in ${ssh_groups[@]}; do
echo "--------------------->"
echo "Checking Group : ${ssh_group}";
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
echo "[!] User $username does not exists in /etc/passwd file";
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=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 5);
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}" ]; then
if [ -z "${user_create_date_string}" ]; then
# user L 11/09/2020 0 99999 7 -1
user_create_date=$(passwd -S ${username} | cut -d " " -f 3);
user_create_date_string=$(passwd -S ${username} | cut -d " " -f 3);
fi;
# last try is user home .bash_logout
if [ -z "${user_create_date}" ]; then
if [ -z "${user_create_date_string}" ]; then
home_dir=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 6)"/.bash_logout";
user_create_date=$(stat -c %Z "${home_dir}");
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
@@ -69,20 +147,42 @@ echo "Checking Group : ${ssh_group}";
# 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 "${found}" ] && [ ! -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=$(grep "${username};" "${AUTH_LOG}" | cut -d ";" -f 2 | date +"%s" -f -);
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;
if [ "${ssh_group}" != "${ssh_reject_group}" ]; then
lock_user=1;
fi;
elif [ ${last_login} -gt ${warn_age_login} ]; then
out_string="OK [last ssh login ${last_login} days ago]";
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}
@@ -92,43 +192,92 @@ echo "Checking Group : ${ssh_group}";
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;
if [ "${ssh_group}" != "${ssh_reject_group}" ]; then
lock_user=1;
fi;
elif [ ${last_login} -gt ${warn_age_login} ]; then
out_string="OK [last terminal login ${last_login} days ago]";
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
user_create_date=$(echo "${user_create_date}" | 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}");
if [ ${account_age} -gt ${max_age_create} ]; then
out_string="[!] Never logged in, account created ${account_age} days ago";
lock_user=1;
out_string="[!] Never logged in: account created ${account_age} days ago";
if [ "${ssh_group}" != "${ssh_reject_group}" ]; then
lock_user=1;
fi;
else
out_string="OK [first login]";
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
if [ ${lock_user} -eq 1 ]; then
lock_accounts="${lock_accounts} ${username}"
fi;
printf "* Checking user %-20s: %s\n" "${username}" "${out_string}";
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;
echo "--------------------->"
echo "Showing current SSH Reject users:"
for user in $(cat /etc/group|grep "${ssh_reject_group}:" | cut -d ":" -f 4 | sed -e 's/,/ /g'); do
echo "${user}";
done;
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}";
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 ${unlock_accounts}";
echo "";
echo "For FORWARDONLY:"
echo "bin/unlock_user.sh -s forward ${unlock_accounts}";
fi;
echo "[END] ===============>"
elif [ "${OUTPUT_TARGET}" = "json" ]; then
# users
echo "]";
# overall
echo "}";
fi;
echo "[END] ===============>"
# __END__

View File

@@ -61,7 +61,8 @@ function parseLog()
if [ "${logger}" = "systemd" ]; then
# 2022-11-18T20:04:08+0900
auth_date=$(echo "${line}" | cut -d " " -f 1);
auth_user=$(echo "${line}" | cut -d "]" -f 2 | cut -d " " -f 7 | cut -d "." -f 1);
# Note, instead of cut with dot, remove last dot in line
auth_user=$(echo "${line}" | cut -d "]" -f 2 | cut -d " " -f 7 | sed -e "s/\.$//");
else
auth_date=$(echo "${line}" | cut -c 1-6)" ${start_year} "$(echo "${line}" | cut -c 8-15);
auth_user=$(echo "${line}" | cut -d ")" -f 2 | cut -d " " -f 6 | cut -d "(" -f 1);

View File

@@ -27,11 +27,12 @@
# SET TO 1 to TEST [will not create user/group/folder]
TEST=0; # no actions will be run
INFO=0; # no creation of anything, just print info strings
GO=1; # without this flag the script will exit with an info box
while getopts ":tih:" opt; do
GO=0; # without this flag the script will exit with an info box
while getopts ":gtih:" opt; do
case "${opt}" in
g|go)
GO=1;
;;
t|test)
TEST=1;
;;
@@ -50,6 +51,7 @@ while getopts ":tih:" opt; do
;;
esac;
done;
error=0;
# hostname for output file only
host=$(hostname);
timestamp=$(date +%Y%m%d-%H%M%S)
@@ -71,18 +73,22 @@ if [ ! -z "${HOME_LOCATION}" ]; then
# must start with / as it has to be from root
if [ "${HOME_LOCATION##/*}" ]; then
echo "Home location folder must start with a slash (/): ${HOME_LOCATION}";
exit;
error=1;
fi;
# must be valid folder
if [ ! -d "${HOME_LOCATION}" ]; then
echo "Folder for home location does not exists: ${HOME_LOCATION}";
exit;
error=1;
fi;
fi;
# the new location for home, if override is set will be created in this folder
HOME_FOLDER="${HOME_LOCATION}${HOME_BASE}"
if [ ! -d "${HOME_FOLDER}" ]; then
echo "Home folder location not found: ${HOME_FOLDER}";
error=1;
fi;
# home dir error abort
if [ $error -eq 1 ]; then
exit;
fi;
ROOT_FOLDER="${BASE_FOLDER}../";
@@ -123,18 +129,18 @@ fi;
# if [ ! command -v pwgen &> /dev/null ]; then
if [ -z $(command -v pwgen) ]; then
echo "Missing pwgen application, aborting";
exit;
error=1;
fi;
# check for zip
# if [ ! command -v zip &> /dev/null ]; then
if [ -z $(command -v zip) ]; then
echo "Missing zip application, aborting";
exit;
error=1;
fi;
# check if sshallow or sshfoward group exists
if [ -z $(cat /etc/group | grep "sshallow:") ]; then
echo "Missing ssh access group: sshallow";
exit;
error=1;
fi;
# flag if we can set ssh forward
if [ ! -z $(cat /etc/group | grep "sshforward:") ]; then
@@ -143,7 +149,7 @@ fi;
# check if user list file exists
if [ ! -f "${ROOT_FOLDER}${input_file}" ]; then
echo "Missing ${ROOT_FOLDER}${input_file}";
exit;
error=1;
fi;
# make sure my own folder is owned by root and 600 (except for testing)
if [ $(stat -c %a .) != "600" ]; then
@@ -152,7 +158,7 @@ fi;
if [ $(whoami) != "root" ]; then
if [ ${TEST} -eq 0 ] && [ ${INFO} -eq 0 ]; then
echo "Script must be run as root user";
exit;
error=1;
else
echo "!!!! Script must be run as root user !!!!";
fi;
@@ -162,6 +168,10 @@ fi;
if [ $GO -eq 0 ]; then
echo "Script has to be run with -g option for actual user creation.";
echo "It is recommended to run -t for testing prior to user creation.";
error=1;
fi;
if [ $error -eq 1 ]; then
exit;
fi;
@@ -338,7 +348,7 @@ while read i; do
else
create_output_file="${ROOT_FOLDER}${output_file}.TEST";
fi;
echo $(date +"%F %T")";"${host}";"${_hostname}";"${username}";"${password}";"${ssh_allow_type} >> ${create_output_file};
echo $(date +"%F %T")";"${host}";"${_hostname}";"${username}";"${password}";"${ssh_access_type} >> ${create_output_file};
# create folder only if we do not have central
# create the SSH foler and authorized access file with correct permissions
if [ -z "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then

View File

@@ -12,13 +12,9 @@
# This will permaently remove the user
TEST=0; # do not run any actions
GO=1; # without this flag the script will exit with an info box
BACKUP=1;
while getopts ":tih:" opt; do
while getopts ":tb" opt; do
case "${opt}" in
g|go)
GO=1;
;;
t|test)
TEST=1;
;;
@@ -53,7 +49,7 @@ fi;
# check tar, bzip2 is installed if backup = 1
host=$(hostname);
timestamp=$(date +%Y%m%d-%H%M%S)
timestamp=$(date +%Y%m%d-%H%M%S);
# character to set getween info blocks
separator="#";
# base folder for all data
@@ -92,6 +88,7 @@ fi;
# $1 ... $n
for username in "$@"; do
error=0;
# skip if there is an option hidden
if [[ ${_arg:0:1} = "-" ]]; then
continue;
@@ -108,18 +105,18 @@ for username in "$@"; do
if ! id "${username}" &>/dev/null; then
# not in passwd
echo "[!!!] User ${username} does not exist in /etc/passwd";
if [ ${TEST} -eq 0 ]; then
break;
fi;
error=1;
fi;
user_list_entry=$(grep "${username}" "${user_list_file}");
if [ -z "${user_list_entry}" ]; then
echo "[!!!] User ${username} does not exist in user_list.txt file";
if [ ${TEST} -eq 0 ]; then
break;
fi;
error=1;
elif [[ "${user_list_entry}" =~ ^#DELETED ]]; then
echo "[!!!] User ${username} is flagged as deleted in user_list.txt file";
error=1;
fi;
if [ $error -eq 1 ]; then
if [ ${TEST} -eq 0 ]; then
break;
fi;

View File

@@ -4,22 +4,32 @@
# - rename user name
# - rename home folder + owner
# - rename public key file in /etc/ssh/
# - rename in user_list.txt
# - rename created public key file
TEST=0; # do not run any actions
GO=1; # without this flag the script will exit with an info box
BACKUP=1;
while getopts ":tih:" opt; do
OLD_USERNAME="";
NEW_USERNAME="";
while getopts ":to:n:" opt; do
case "${opt}" in
g|go)
GO=1;
;;
t|test)
TEST=1;
;;
o|old-user)
if [ -z "${OLD_USERNAME}" ]; then
OLD_USERNAME="${OPTARG}";
fi;
;;
n|new-user)
if [ -z "${NEW_USERNAME}" ]; then
NEW_USERNAME="${OPTARG}";
fi;
;;
\?)
echo -e "\n Option does not exist: ${OPTARG}\n";
echo "Use -t for test";
echo "Use -g for actually creation run";
echo "-o: Current user";
echo "-n: New username";
exit 1;
;;
esac;
@@ -35,9 +45,196 @@ if [ $(whoami) != "root" ]; then
fi;
fi;
if [ $# -eq 0 ]; then
echo "Must give at least one user name";
error=0;
host=$(hostname);
timestamp=$(date +%Y%m%d-%H%M%S);
# character to set getween info blocks
separator="#";
# base folder for all data
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
root_folder="${BASE_FOLDER}../";
SSH_KEYGEN_FOLDER_CREATED_PUB='ssh-keygen-created-pub/';
input_file='user_list.txt';
user_list_file="${root_folder}${input_file}";
default_ssh_keytype='ed25519';
ssh_keytype='';
# log file
LOG="${BASE_FOLDER}/../log/rename_user."$(date +"%F_%H%m%S");
if [ ${TEST} -eq 0 ]; then
LOG="${LOG}.log";
else
LOG="${LOG}.test.log";
fi;
# ignore users (root and admin users)
ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
# detect ssh authorized_keys setting
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER='';
SSH_AUTHORIZED_FILE='';
for cf in $(grep "^AuthorizedKeysFile" /etc/ssh/sshd_config | grep "%u"); do
if [ ! -z $(echo "${cf}" | grep "%u") ]; then
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER=$(echo "${cf}" | sed -e 's/%u//');
if [ ! -d "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then
echo "ssh central authorized_file folder could not be found: ${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}";
error=1;
fi;
fi;
done;
if [ ! -f "${user_list_file}" ]; then
echo "${input_file} is missing";
error=1;
fi;
if [ -z "${OLD_USERNAME}" ] || [ -z "${NEW_USERNAME}" ]; then
echo "[!!!] Current and new username must be provided";
error=1;
fi;
if [ "${OLD_USERNAME}" = "${NEW_USERNAME}" ]; then
echo "[!!!] Current and new username cannot be the same";
error=1;
fi;
if ! [[ "${NEW_USERNAME}" =~ ^[a-z0-9]+([.a-z0-9_-]+[a-z0-9])?$ ]]; then
echo "User name can only be a-z 0-9 - _ . and cannot start or end with - . or _: ${NEW_USERNAME}";
error=1;
fi;
# skip ignore users, note that if a user is not in the sshallow list anyway
# we skip them too, this is just in case check
if [[ " ${ignore_users[*]} " =~ " ${OLD_USERNAME} " ]]; then
echo "[!] User ${OLD_USERNAME} is in the ignore user list";
error=1;
fi;
if [[ " ${ignore_users[*]} " =~ " ${NEW_USERNAME} " ]]; then
echo "[!] User ${NEW_USERNAME} is in the ignore user list";
error=1;
fi;
# user must exist in user_list.txt and /etc/passwd
# if missing in or another do not continue
if ! id "${OLD_USERNAME}" &>/dev/null; then
# not in passwd
echo "[!!!] User ${OLD_USERNAME} does not exist in /etc/passwd";
error=1;
fi;
if id "${NEW_USERNAME}" &>/dev/null; then
# not in passwd
echo "[!!!] User ${NEW_USERNAME} exists in /etc/passwd";
error=1;
fi;
if [ -f "${user_list_file}" ]; then
user_list_entry=$(grep "${OLD_USERNAME}" "${user_list_file}");
if [ -z "${user_list_entry}" ]; then
echo "[!!!] User ${OLD_USERNAME} does not exist in user_list.txt file";
error=1;
fi;
# if the old user exists but as DELETED -> no go
if [ ! -z $(echo "${user_list_entry}" | grep "#DELETED-") ]; then
echo "[!!!] User ${OLD_USERNAME} has been flagged as deleted";
error=1;
fi;
# if new user name already exists in user list file for whatever reason
if [ $(grep "${NEW_USERNAME}" "${user_list_file}") ]; then
echo "[!!!] User ${NEW_USERNAME} exists in user_list.txt file";
error=1;
fi;
fi;
# exit on any error
if [ $error -eq 1 ]; then
exit;
fi;
# parse user list entry for group/hostname/ssh type key to build ssh key list
# POS 3: groups
_group=$(echo "${user_list_entry}" | cut -d ";" -f 3 | tr A-Z a-z | tr -d ' ');
group=$(echo "${_group}" | cut -d "," -f 1);
# POS 6: override host name, lowercase and spaces removed
_hostname=$(echo "${user_list_entry}" | cut -d ";" -f 6 | tr A-Z a-z | tr -d ' ');
if [ -z "${_hostname}" ]; then
hostname=${host};
else
hostname=${_hostname};
fi;
# POS 7: ssh keytype override
_ssh_keytype=$(echo "${user_list_entry}" | cut -d ";" -f 7 | tr A-Z a-z | tr -d ' ');
if [ "${_ssh_keytype}" = "rsa" ]; then
ssh_keytype="${_ssh_keytype}";
else
ssh_keytype=${default_ssh_keytype};
fi;
echo "* Rename ${OLD_USERNAME} to ${NEW_USERNAME}";
old_home_dir=$(getent passwd "${OLD_USERNAME}" | cut -d: -f6);
new_home_dir=$(echo "${old_home_dir}" | sed -e "s/\/${OLD_USERNAME}$/\/${NEW_USERNAME}/");
# rename user
if [ $TEST -eq 0 ]; then
echo "usermod with ${new_home_dir}";
usermod -l ${NEW_USERNAME} -m -d "${new_home_dir}" ${OLD_USERNAME};
else
echo "$> usermod -l ${NEW_USERNAME} -m -d \"${new_home_dir}\" ${OLD_USERNAME};";
fi
# check that home folder is renamed and owned by new user
# check if spool exists
if [ -f "/var/spool/mail/${OLD_USERNAME}" ]; then
if [ $TEST -eq 0 ]; then
echo "rename to /var/spool/mail/${NEW_USERNAME}";
mv "/var/spool/mail/${OLD_USERNAME}" "/var/spool/mail/${NEW_USERNAME}";
else
echo "$> mv \"/var/spool/mail/${OLD_USERNAME}\" \"/var/spool/mail/${NEW_USERNAME}\";";
fi
fi;
# check if crontab exists
if [ -f "/var/spool/cron/crontabs/${OLD_USERNAME}" ]; then
if [ $TEST -eq 0 ]; then
echo "rename to /var/spool/cron/crontabs/${NEW_USERNAME}";
mv "/var/spool/cron/crontabs/${OLD_USERNAME}" "/var/spool/cron/crontabs/${NEW_USERNAME}";
else
echo "$> mv \"/var/spool/cron/crontabs/${OLD_USERNAME}\" \"/var/spool/cron/crontabs/${NEW_USERNAME}\";";
fi
fi;
# public key files user must be renamed
OLD_SSH_AUTHORIZED_FILE="${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}${OLD_USERNAME}";
NEW_SSH_AUTHORIZED_FILE="${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}${NEW_USERNAME}";
if [ -f "${OLD_SSH_AUTHORIZED_FILE}" ]; then
if [ $TEST -eq 0 ]; then
echo "rename to ${NEW_SSH_AUTHORIZED_FILE}";
chattr -i "${OLD_SSH_AUTHORIZED_FILE}";
mv "${OLD_SSH_AUTHORIZED_FILE}" "${NEW_SSH_AUTHORIZED_FILE}";
chattr +i "${NEW_SSH_AUTHORIZED_FILE}";
else
echo "$> chattr -i \"${OLD_SSH_AUTHORIZED_FILE}\";";
echo "$> mv \"${OLD_SSH_AUTHORIZED_FILE}\" \"${NEW_SSH_AUTHORIZED_FILE}\";";
echo "$> chattr +i \"${NEW_SSH_AUTHORIZED_FILE}\";";
fi;
else
echo "[?] ${OLD_SSH_AUTHORIZED_FILE} is missing";
fi;
# rename keygen public file
OLD_ssh_keygen_pub="${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}${hostname}${separator}${group}${separator}${OLD_USERNAME}${separator}${ssh_keytype}.pem.pub";
NEW_ssh_keygen_pub="${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}${hostname}${separator}${group}${separator}${NEW_USERNAME}${separator}${ssh_keytype}.pem.pub";
if [ -f "${OLD_ssh_keygen_pub}" ]; then
if [ $TEST -eq 0 ]; then
echo "rename to ${NEW_ssh_keygen_pub}";
mv "${OLD_ssh_keygen_pub}" "${NEW_ssh_keygen_pub}";
else
echo "$> mv \"${OLD_ssh_keygen_pub}\" \"${NEW_ssh_keygen_pub}\";";
fi;
else
echo "[?] ${OLD_ssh_keygen_pub} is missing";
fi;
# rename entry in user list txt file
if [ $TEST -eq 0 ]; then
echo "update ${user_list_file}";
sed -i -e "s/^\([A-Za-z0-9]\{1,\}\);${OLD_USERNAME};/\1;${NEW_USERNAME};/" "${user_list_file}";
else
echo "$> sed -i -e \"s/^\([A-Za-z0-9]\{1,\}\);${OLD_USERNAME};/\1;${NEW_USERNAME};/\" \"${user_list_file}\";";
fi;
# __END__