Compare commits

..

16 Commits

Author SHA1 Message Date
Clemens Schwaighofer
694f04313c Add Account, Region and Instance info for each report
So we can easy match up user reports to other information we collect
2023-12-22 11:54:34 +09:00
Clemens Schwaighofer
50e28c7cfd Check that fallback last access file exists 2023-12-21 16:43:57 +09:00
Clemens Schwaighofer
65b7a6ad43 Fix date check for account created date
Use regex to check instead of empty string.
A comment could be set instead of a date
2023-12-21 16:39:05 +09:00
Clemens Schwaighofer
244461d466 sshforward group typo in lock and unlock users 2023-12-21 16:11:31 +09:00
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
8 changed files with 536 additions and 76 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,142 @@ 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";
if [ -z $(command -v curl) ]; then
echo "Missing curl application, aborting";
error=1;
fi;
if [ -z $(command -v jq) ]; then
echo "Missing jq application, aborting";
error=1;
fi;
# option 1 in list
case "${1,,}" in
text)
OUTPUT_TARGET="text";
;;
json)
OUTPUT_TARGET="json";
echo "{";
;;
csv)
CSV_LINE="%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n";
OUTPUT_TARGET="csv";
echo "Account ID,Region,Instance ID,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;
# collect info via: curl http://instance-data/latest/meta-data/
instance_id=$(curl -s http://instance-data/latest/meta-data/instance-id)
account_id=$(curl -s http://instance-data/latest/meta-data/identity-credentials/ec2/info/ | jq -r .AccountId)
region=$(curl -s http://instance-data/latest/meta-data/placement/region)
if [ "${OUTPUT_TARGET}" = "text" ]; then
LOG="${LOG}/check_ssh_user."$(date +"%F_%H%m%S")".log";
exec &> >(tee -a "${LOG}");
echo "[START] =============>";
echo "AWS ID : ${account_id}";
echo "Region : ${region}";
echo "Instance ID : ${instance_id}";
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 '"AccountId": "'${account_id}'",';
echo '"Region": "'${region}'",';
echo '"InstanceId": "'${instance_id}'",';
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 "${CSV_LINE}" "${account_id}" "${region}" "${instance_id}" "$(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 ! [[ "${user_create_date_string}" =~ ^\d{4}-\d{2}-\{2} ]]; 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
home_dir=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 6)"/.bash_logout";
user_create_date=$(stat -c %Z "${home_dir}");
if ! [[ "${user_create_date_string}" =~ ^\d{4}-\d{2}-\{2} ]]; then
# try logout or bash history
home_dir_bl=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 6)"/.bash_logout";
home_dir_bh=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 6)"/.bash_history";
# check that this file exists
if [ -f "${home_dir_bl}" ]; then
user_create_date_string=$(stat -c %Z "${home_dir_bl}");
elif [ -f "${home_dir_bh}" ]; then
user_create_date_string=$(stat -c %Z "${home_dir_bh}");
fi;
fi;
# still no date -> set empty
if ! [[ "${user_create_date_string}" =~ ^\d{4}-\d{2}-\{2} ]]; then
user_create_date_string="";
fi;
# below only works if the user logged in, a lot of them are just file upload
@@ -69,20 +179,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 "${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 +224,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 "${CSV_LINE}" "${account_id}" "${region}" "${instance_id}" "$(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

@@ -39,7 +39,7 @@ if [ -z $(cat /etc/group | grep "${ssh_reject_group}:") ]; then
exit;
fi;
ssh_allow_group="sshallow";
ssh_forward_group="sshfoward";
ssh_forward_group="sshforward";
user_group_tpl="gpasswd -d %s %s\ngpasswd -a %s %s\n";
echo "--------------------->"

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__

View File

@@ -53,7 +53,7 @@ if [ -z $(cat /etc/group | grep "${ssh_reject_group}:") ]; then
exit;
fi;
ssh_allow_group="sshallow";
ssh_forward_group="sshfoward";
ssh_forward_group="sshforward";
user_group_tpl="gpasswd -d %s %s\ngpasswd -a %s %s\n";
echo "--------------------->"