Compare commits

...

18 Commits

Author SHA1 Message Date
Clemens Schwaighofer
76f9056069 Fix user create with groups
Move the params into array that we add as dynamic parameters to call
2024-10-11 14:39:56 +09:00
Clemens Schwaighofer
74e7e9823f Bug fix for user create group part 2024-10-11 09:25:41 +09:00
Clemens Schwaighofer
7ce8330aa6 shellcheck fixup 2024-09-27 18:49:36 +09:00
Clemens Schwaighofer
d8f9710593 Merge branch 'development' into shellecheck-cleanup 2024-09-24 11:40:13 +09:00
Clemens Schwaighofer
c37d17fe9f ReadMe file update 2024-09-24 11:38:45 +09:00
Clemens Schwaighofer
307433e0a7 Merge branch 'development' into shellecheck-cleanup 2024-09-20 09:22:20 +09:00
Clemens Schwaighofer
f9cd0806f1 Fix in Readme file for exmaple user_list.txt 2024-09-20 09:22:02 +09:00
Clemens Schwaighofer
d9b3fd97fb Merge branch 'development' into shellecheck-cleanup 2024-09-20 09:20:36 +09:00
Clemens Schwaighofer
21177e1762 Updates for ReadMe file for no login shell settings 2024-09-20 09:20:01 +09:00
Clemens Schwaighofer
3aa6de7e23 check last login shellcheck fixes 2024-09-06 14:44:34 +09:00
Clemens Schwaighofer
3c160a62e7 Merge branch 'development' into shellecheck-cleanup 2024-09-06 14:37:37 +09:00
Clemens Schwaighofer
ca4616c5ee Text fix for error strings in last login check 2024-09-06 14:36:09 +09:00
Clemens Schwaighofer
251b0bf981 SSH login last date check was wrong 2024-09-06 14:34:38 +09:00
Clemens Schwaighofer
6daccfe57c Check last login update with more days info
if WARN then write WARN instead of OK.
Add day numbers if OK

Some minor shellscript updates
2024-09-06 14:25:28 +09:00
Clemens Schwaighofer
91f096ab0c Merge branch 'master' into shellecheck-cleanup 2024-09-06 10:58:13 +09:00
Clemens Schwaighofer
935d6a84c9 Add login shell type select (bash login or no login), fix ssh base groups
no ssh allow/forward/reject base group was set if an optional sub group was set

Add possibility to chose no login when setting the ssh access type to "...|no_login"
2024-09-06 10:44:31 +09:00
Clemens Schwaighofer
ee7cc8555e Merge branch 'development' into shellecheck-cleanup 2024-09-04 14:05:51 +09:00
Clemens Schwaighofer
e4ed6fed8d shellcheck based code cleanup 2024-09-04 11:16:05 +09:00
10 changed files with 256 additions and 197 deletions

View File

@@ -1,4 +1,4 @@
# AWS User Creation
# User creation on AWS Servers
Two files to create new user entries with an SSH key and zip all the data for download
@@ -23,8 +23,16 @@ Alternate download:
Inside the base folder there are
- ssh-keygen for temporary holding the PEM/PUB files
- zip file which holds the created user list, password and PEM/PUB files
- auth-log/: access logs from users for the last login check
- bin/: scripts folder
- backup/: for removed users home directories
- config/: config settings (eg alternative home base folder
- log/: user creation and other action logs
- ssh-keygen/: PEM keys are stored here during creation and then zip-ed into the zip folder
- ssh-keygen-created-pub/: Public keys are stored here and stay here (used for checking)
- user_list.txt: users that should exist on this server with various settings
- [user_password.YYYYMMDD-HHmmss.txt] temporary file with username and password, zip-ed into the zip folder
- zip/: after user creation the password and PEM files are stored in here
## Config
@@ -72,12 +80,12 @@ In the `/root/users/` folder there needs to be a file called '*user_list.txt*'
This is a CSV type file with the following layout
ID | Username | Group and Sub Group | SSH Access Type | Optional Password | Override host name | Override ssh key type
ID | Username | Group and Sub Group | SSH Access Type and No Login flag | Optional Password | Override host name | Override ssh key type
-|-|-|-|-|-|-
1: The ID, Username and Group column must be filled.
2: For sub groups add them with a *,* The first group is the master group
3: SSH Access type as: allow/forward. allow is default
2: For sub groups add them with a MASTER_GROUP,SUB_GROUP_A,SUB_GROUP_B,... The first group is the master group
3: SSH Access type as: allow/forward. allow is default, additional separated by | can be a "no_login" to set a no login shell, else bash shell will be set
4: If the password column is filled, the string from here will be used as the PEM Key password.
5: If a override hostname is set it will be used instead of `hostname`
6: If the ssh key type is set, it will override the default *ed25519* type. Only *rsa* is allowed. This is for setting up backwards compatible lists. Change is not recommended
@@ -90,11 +98,12 @@ The file can hold comments. The first character in the line must be a *#*
Example file
```csv
#user_id;user_name;group,subgroup;ssh access type;override password;override hostname;override ssh type
#user_id;user_name;group,subgroup;ssh access type|no login flag;override password;override hostname;override ssh type
user1;some.name;group-a;allow;;hostname;
user2;othername;group-a;allow;;;
# I am a comment
;username;groupC;allow;setpassword;;
;username_c;groupC;allow|no_login;;;
...
```

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env bash
# shellcheck disable=SC2059
# check if we need to move the users authorized keys to the central location
TEST=1;
@@ -7,14 +9,14 @@ LIST=0;
SKIP_USERS=();
while getopts ":gls:" opt; do
case "${opt}" in
g|go)
g) # go
# default we test
TEST=0;
;;
s|skip)
s) # skip
SKIP_USERS+=("${OPTARG}");
;;
l|list)
l) # list
LIST=1;
;;
\?)
@@ -29,10 +31,11 @@ done;
# detect ssh authorized_keys setting
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER='';
SSH_MASTER_AUTHORIZED_FILE='';
SSH_AUTHORIZED_FILE='';
# SSH_AUTHORIZED_FILE='';
# shellcheck disable=SC2013
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 echo "$cf" | grep -q "%u"; then
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER="${cf/%%u//}";
if [ ! -d "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then
echo "ssh central authorized_file folder could not be found: ${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}";
exit;
@@ -43,8 +46,9 @@ if [ -z "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then
echo "No central authorized_keys file detected, no change check needed";
exit;
fi;
# shellcheck disable=SC2013
for cf in $(grep "^AuthorizedKeysFile" /etc/ssh/sshd_config | grep -- "--master"); do
if [ ! -z $(echo "${cf}" | grep -- "--master") ]; then
if ! echo "${cf}" | grep -q -- "--master"; then
SSH_MASTER_AUTHORIZED_FILE="${cf}";
if [ ! -f "${SSH_MASTER_AUTHORIZED_FILE}" ]; then
echo "ssh master authorized_file could not be found: ${SSH_MASTER_AUTHORIZED_FILE}"l
@@ -66,7 +70,7 @@ if [ ${LIST} -eq 1 ]; then
fi;
# base folder
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
# output printf
PRINTF_INFO="%-8s [%3s]: %-25s: %s\n";
# list of user accounts we will never touch
@@ -86,20 +90,20 @@ fi;
# loop over passwd file
# if not in no action then check if .ssh/authorized_keys file exists
cat /etc/passwd | cut -d ":" -f 1,6 |
while read user_home; do
cut -d ":" -f 1,6 /etc/passwd |
while read -r user_home; do
username=$(echo "${user_home}" | cut -d ":" -f 1);
master_user=0;
# skip admin usernames
if [[ " ${NO_ACTION[*]} " =~ " ${username} " ]]; then
if [[ " ${NO_ACTION[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
printf "${PRINTF_INFO}" "NO ACT" "!" "${username}" "user in NO ACTION list";
continue;
fi;
if [[ " ${SKIP_USERS[*]} " =~ " ${username} " ]]; then
if [[ " ${SKIP_USERS[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
printf "${PRINTF_INFO}" "SKIP" "*" "${username}" "skip forced via command line";
continue;
fi;
if [[ " ${IGNORE_USER[*]} " =~ " ${username} " ]]; then
if [[ " ${IGNORE_USER[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
printf "${PRINTF_INFO}" "SKIP" "**" "${username}" "skip from ignore config file";
continue;
fi;
@@ -115,10 +119,10 @@ while read user_home; do
continue;
fi;
# check those keys are in the master key list
if [[ " ${MASTER_KEY[*]} " =~ " ${username} " ]]; then
if [[ " ${MASTER_KEY[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
master_user=1;
ssh_key_diff=$(diff -u "${home_folder}/.ssh/authorized_keys" "${SSH_MASTER_AUTHORIZED_FILE}");
if [ ! -z "${ssh_key_diff}" ]; then
if [ -n "${ssh_key_diff}" ]; then
printf "${PRINTF_INFO}" "ABORT" "!!!" "${username}" "authorized key is not matching the master key file";
exit;
fi;
@@ -148,12 +152,12 @@ while read user_home; do
if [ ${TEST} -eq 0 ]; then
cat "${home_folder}/.ssh/authorized_keys" > "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}";
# secure new folder: chown/chmod/chattr
chown ${username} "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}";
chown "${username}" "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}";
chmod 400 "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}";
chattr +i "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}";
# confirm
ssh_key_diff=$(diff -u "${home_folder}/.ssh/authorized_keys" "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}");
if [ ! -z "${ssh_key_diff}" ]; then
if [ -n "${ssh_key_diff}" ]; then
printf "${PRINTF_INFO}" "ERROR" "!!!" "${username}" "Move problem ${ssh_key_diff}";
break;
fi;

View File

@@ -4,7 +4,7 @@
# if user login >30days, remoe user from sshallow group and write log
# base folder
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
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';
@@ -28,7 +28,7 @@ LOG="${BASE_FOLDER}/../log";
AUTH_LOG="${BASE_FOLDER}/../auth-log/user_auth.log";
error=0;
if [ $(whoami) != "root" ]; then
if [ "$(whoami)" != "root" ]; then
echo "Script must be run as root user";
error=1;
fi;
@@ -36,11 +36,11 @@ if [ ! -d "${LOG}" ]; then
echo "log folder ${LOG} not found";
error=1;
fi;
if [ -z $(command -v curl) ]; then
if [ -z "$(command -v curl)" ]; then
echo "Missing curl application, aborting";
error=1;
fi;
if [ -z $(command -v jq) ]; then
if [ -z "$(command -v jq)" ]; then
echo "Missing jq application, aborting";
error=1;
fi;
@@ -68,7 +68,7 @@ esac;
# collect info via: curl http://169.254.169.254/latest/meta-data/
instance_data=$(
TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` &&
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") &&
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/dynamic/instance-identity/document
)
instance_id=$(echo "${instance_data}" | jq .instanceId)
@@ -76,31 +76,31 @@ account_id=$(echo "${instance_data}" | jq .accountId)
region=$(echo "${instance_data}" | jq .region)
if [ "${OUTPUT_TARGET}" = "text" ]; then
LOG="${LOG}/check_ssh_user."$(date +"%F_%H%m%S")".log";
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 "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 '"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
for ssh_group in "${ssh_groups[@]}"; do
if [ "${OUTPUT_TARGET}" = "text" ]; then
echo "--------------------->"
if [ "${ssh_group}" = "${ssh_reject_group}" ]; then
@@ -110,7 +110,7 @@ for ssh_group in ${ssh_groups[@]}; do
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
while read -r username; do
# check that user exists in passwd
if ! id "${username}" &>/dev/null; then
out_string="[!] User $username does not exists in /etc/passwd file";
@@ -120,8 +120,8 @@ for ssh_group in ${ssh_groups[@]}; do
;;
json)
echo "{";
echo '"Username": "'${username}'",';
echo '"SshGroup": "'${ssh_group}'",';
echo '"Username": "'"${username}"'",';
echo '"SshGroup": "'"${ssh_group}"'",';
echo '"MainGroup": "",';
echo '"SubGroups": [],';
echo '"AccountCreatedDate": "",';
@@ -130,10 +130,11 @@ for ssh_group in ${ssh_groups[@]}; do
echo '"LastLoginAge": "",';
echo '"LoginSource": "",';
echo '"NeverLoggedIn": true,';
echo '"Status": "'${out_string}'"';
echo '"Status": "'"${out_string}"'"';
echo "}";
;;
csv)
# shellcheck disable=SC2059
printf "${CSV_LINE}" "${account_id}" "${region}" "${instance_id}" "$(hostname)" "${username}" "" "${ssh_group}" "" "" "" "" "true" "${out_string}"
;;
esac;
@@ -157,17 +158,17 @@ for ssh_group in ${ssh_groups[@]}; do
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);
user_create_date_string=$(grep "${username}:" /etc/passwd | cut -d ":" -f 5);
# if empty try last password set time
if ! [[ "${user_create_date_string}" =~ ^\d{4}-\d{2}-\{2} ]]; then
# user L 11/09/2020 0 99999 7 -1
user_create_date_string=$(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 ! [[ "${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";
home_dir_bl=$(grep "${username}:" /etc/passwd | cut -d ":" -f 6)"/.bash_logout";
home_dir_bh=$(grep "${username}:" /etc/passwd | 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}");
@@ -184,7 +185,7 @@ for ssh_group in ${ssh_groups[@]}; do
# 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);
last_login_string=$(lastlog -u "${username}" | sed 1d);
search="Never logged in";
never_logged_in="false";
found="";
@@ -197,7 +198,7 @@ for ssh_group in ${ssh_groups[@]}; do
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
if [ -n "${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
@@ -205,50 +206,50 @@ for ssh_group in ${ssh_groups[@]}; do
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
if [ -n "${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_date=$(echo "${last_login_date_string}" | 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";
if [ "${last_login}" -gt ${max_age_login} ]; then
out_string="[!] Last ssh log in ${last_login} days ago";
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]";
elif [ "${last_login}" -gt ${warn_age_login} ]; then
out_string="WARN [last ssh login ${last_login} days ago]";
else
out_string="OK [ssh]";
out_string="OK [ssh, ${last_login} days ago]";
fi;
login_source="ssh";
# rewrite to Y-M-D, aka
last_login_date="${last_login_date_string}"
elif [ ! -z "${last_login_string##*$search*}" ]; then
elif [ -n "${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";
if [ "${last_login}" -gt ${max_age_login} ]; then
out_string="[!] Last terminal log in ${last_login} days ago";
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]";
elif [ "${last_login}" -gt ${warn_age_login} ]; then
out_string="WARN [last terminal login ${last_login} days ago]";
else
out_string="OK [lastlog]";
out_string="OK [lastlog, ${last_login} days ago]";
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
elif [ -n "${user_create_date}" ]; then
if [ "${account_age}" -gt ${max_age_create} ]; then
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 [Never logged in]";
out_string="OK [Never logged in, created ${account_age} days ago]";
fi;
never_logged_in="true";
else
@@ -275,33 +276,34 @@ for ssh_group in ${ssh_groups[@]}; do
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 '"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)
# shellcheck disable=SC2059
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 <<< "$(grep "${ssh_group}:" /etc/group | cut -d ":" -f 4 | sed -e 's/,/ /g')";
done;
if [ "${OUTPUT_TARGET}" = "text" ]; then
if [ ! -z "${lock_accounts}" ]; then
if [ -n "${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
if [ -n "${unlock_accounts}" ]; then
echo "--------------------->"
echo "% Run script below to move users to allow or forward ssh group";
echo "";

View File

@@ -9,7 +9,7 @@ if [[ "$EUID" -ne "0" ]]; then
fi;
# base folder
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
# auth log file
AUTH_LOG="${BASE_FOLDER}/../auth-log/user_auth.log";
if [ ! -f "${AUTH_LOG}" ]; then
@@ -22,13 +22,19 @@ RUN_FULL_LOG=0;
# option parsing
while getopts ":fd" opt; do
case "${opt}" in
f|full)
f) # full
echo "[!!!] Run through all log files to collect data";
RUN_FULL_LOG=1;
;;
d|deubg)
d) # deubg
DEBUG=1;
;;
\?)
echo "";
echo "-f Collect all log data again";
echo "-d Debug output";
exit 1;
;;
esac;
done;
@@ -37,8 +43,8 @@ function prD()
message="${1}";
debug=${2:-0};
lb_off=${3:-0};
if [ ${debug} -eq 1 ]; then
if [ ${lb_off} -eq 1 ]; then
if [ "${debug}" -eq 1 ]; then
if [ "${lb_off}" -eq 1 ]; then
echo -n "${message}";
else
echo "${message}";
@@ -72,25 +78,26 @@ function parseLog()
# $(printf "USER: %-20s: %19s" "${auth_user}" "${auth_date}")
# prD "USER: $auth_user | DATE: $auth_date" ${debug} 1;
printf -v msg "Source: %-10s | Year: %4s | Last auth user: %-20s: %19s" "${logger}" "${start_year}" "${auth_user}" "${auth_date}"
prD "${msg}" ${debug} 1;
prD "${msg}" "${debug}" 1;
# find auth user in current auth file
# if not there attach, else replace date only
found=$(grep "${auth_user};" "${auth_log}");
if [ -z "${found}" ]; then
prD " | Write new" ${debug};
prD " | Write new" "${debug}";
echo "${auth_user};${auth_date}" >> "${auth_log}";
else
prD " | Replace old" ${debug};
prD " | Replace old" "${debug}";
sed -i "s/${auth_user};.*$/${auth_user};${auth_date}/" "${auth_log}";
fi;
}
printf -v msg "Run date: %s %s" $(date +"%F %T")
printf -v msg "Run date: %s" "$(date +"%F %T")"
prD "${msg}" ${DEBUG};
# Collector script for login information via journalctl
# if no systemd installed, try to get info from /var/log/secure or /var/log/auth.log
readonly init_version=$(/proc/1/exe --version | head -n 1);
init_version=$(/proc/1/exe --version | head -n 1);
readonly init_version;
if [ -z "${init_version##*systemd*}" ]; then
LOG_TARGET="systemd";
# for journalctl
@@ -103,8 +110,8 @@ if [ -z "${init_version##*systemd*}" ]; then
fi;
# READ as other format so we get the YEAR -o short-iso
START_YEAR=$(date +%Y -d "1 day ago");
journalctl -u systemd-logind --no-pager -o short-iso ${OPT_START_DATE} ${OPT_END_DATE} | grep ": New session" |
while read line; do
journalctl -u systemd-logind --no-pager -o short-iso "${OPT_START_DATE}" "${OPT_END_DATE}" | grep ": New session" |
while read -r line; do
# # Nov 21 14:15:46 we.are.hostname.com systemd-logind[1865]: New session 12345 of user some^user.
# date: 5 chars
# time: 8 chars
@@ -120,11 +127,11 @@ else
# for secure/auth log
if [ $RUN_FULL_LOG -eq 1 ]; then
# we loop over EACH file and get the DATE so we can have the correct YEAR
for sfile in $(ls -1 /var/log/secure*bz2); do
for sfile in /var/log/secure*bz2; do
tz=$(stat -c %Z "${sfile}");
START_YEAR=$(date +%Y -d @${tz});
START_YEAR=$(date +%Y -d @"${tz}");
bunzip2 -ck "${sfile}" | grep ": session opened for user" | grep " by (uid=0)" |
while read line; do
while read -r line; do
parseLog "${line}" "${AUTH_LOG}" "${START_YEAR}" "${LOG_TARGET}" ${DEBUG};
done;
done;
@@ -132,8 +139,8 @@ else
START_DATE="sshd"
fi;
START_YEAR=$(date +%Y -d "1 day ago");
cat /var/log/secure | grep "${START_DATE}" | grep ": session opened for user" | grep " by (uid=0)" |
while read line; do
grep "${START_DATE}" "/var/log/secure" | grep ": session opened for user" | grep " by (uid=0)" |
while read -r line; do
parseLog "${line}" "${AUTH_LOG}" "${START_YEAR}" "${LOG_TARGET}" ${DEBUG};
done;
fi;

View File

@@ -2,13 +2,14 @@
# * input file
# user_list.txt
# <ignored id>;<user name>;<group>[,sub group,sub group];<ssh access type>;[override password];[override hostname];[override ssh key type]
# <ignored id>;<user name>;<group>[,sub group,sub group];<ssh access type>|<no login flag>;[override password];[override hostname];[override ssh key type]
# lines with # are skipped
# already created users are skipped
# Mandatory: <ignored id>;<user name>;<group>;<ssh access type>
# <ssh access type> can be
# allow (full login access)
# forward (forward/jump host only)
# if in this column with pipe (|) the flag "no_login" is set then the default shell will change to "/sbin/nologin"
# * output file
# <date>;<target connect host name>;<hostname>;<username>;<password>;<ssh access type>
# If already existing PEM key is used then <password> is [ALREADY SET]
@@ -30,16 +31,16 @@ INFO=0; # no creation of anything, just print info strings
GO=0; # without this flag the script will exit with an info box
while getopts ":gtih:" opt; do
case "${opt}" in
g|go)
g) # go
GO=1;
;;
t|test)
t) # test
TEST=1;
;;
i|info)
i) # info
INFO=1;
;;
h|home)
h) # home
HOME_LOCATION="${OPTARG}";
;;
\?)
@@ -58,7 +59,7 @@ 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))"/";
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
# home folder is always thome
HOME_BASE="/home/";
# config location
@@ -66,10 +67,12 @@ CONFIG_BASE="${BASE_FOLDER}../config/";
# check config folder for .env file with HOME_LOCATION
# only use if HOME_LOCATION not yet set
if [ -z "${HOME_LOCATION}" ] && [ -f "${CONFIG_BASE}create_user.cfg" ]; then
source <(grep = ${CONFIG_BASE}create_user.cfg | sed 's/ *= */=/g')
# shellcheck source=../config/create_user.cfg"
# shellcheck disable=SC1091
source <(grep "=" "${CONFIG_BASE}create_user.cfg" | sed 's/ *= */=/g')
fi;
if [ ! -z "${HOME_LOCATION}" ]; then
if [ -n "${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}";
@@ -88,10 +91,10 @@ if [ ! -d "${HOME_FOLDER}" ]; then
error=1;
fi;
# allow 10 to 39 length for password
if [ ! -z "${PASSWORD_LENGTH}" ] && ! [[ "${PASSWORD_LENGTH}" =~ ^[13][0-9]$ ]]; then
if [ -n "${PASSWORD_LENGTH}" ] && ! [[ "${PASSWORD_LENGTH}" =~ ^[13][0-9]$ ]]; then
echo "Password length set error, can only be a value between 10 and 39";
error=1;
elif [ -z ${PASSWORD_LENGTH} ]; then
elif [ -z "${PASSWORD_LENGTH}" ]; then
PASSWORD_LENGTH=14;
fi;
# home dir error abort
@@ -111,12 +114,17 @@ ssh_keytype='';
# sshallow or sshforward
ssh_group='';
ssh_forward_ok=0;
# login shells
login_shell="/bin/bash";
no_login_shell="/sbin/nologin";
user_login_shell="";
# detect ssh authorized_keys setting
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER='';
SSH_AUTHORIZED_FILE='';
# shellcheck disable=SC2013
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 echo "$cf" | grep -q "%u"; then
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER="${cf/%%u//}";
if [ ! -d "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then
echo "ssh central authorized_file folder could not be found: ${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}";
exit;
@@ -133,24 +141,21 @@ if [ ! -d "${ROOT_FOLDER}${output_zip_folder}" ]; then
mkdir "${ROOT_FOLDER}${output_zip_folder}";
fi;
# check if password generate software is installed
# if [ ! command -v pwgen &> /dev/null ]; then
if [ -z $(command -v pwgen) ]; then
if [ -z "$(command -v pwgen)" ]; then
echo "Missing pwgen application, aborting";
error=1;
fi;
# check for zip
# if [ ! command -v zip &> /dev/null ]; then
if [ -z $(command -v zip) ]; then
if [ -z "$(command -v zip)" ]; then
echo "Missing zip application, aborting";
error=1;
fi;
# check if sshallow or sshfoward group exists
if [ -z $(cat /etc/group | grep "sshallow:") ]; then
if ! grep -q "sshallow:" "/etc/group"; then
echo "Missing ssh access group: sshallow";
error=1;
fi;
# flag if we can set ssh forward
if [ ! -z $(cat /etc/group | grep "sshforward:") ]; then
if ! grep -q "sshforward:" "/etc/group"; then
ssh_forward_ok=1;
fi;
# check if user list file exists
@@ -159,10 +164,10 @@ if [ ! -f "${ROOT_FOLDER}${input_file}" ]; then
error=1;
fi;
# make sure my own folder is owned by root and 600 (except for testing)
if [ $(stat -c %a .) != "600" ]; then
if [ "$(stat -c %a .)" != "600" ]; then
echo "!!!! RECOMMENDED TO HAVE BASE FOLDER SET TO '600' AND USER 'root' !!!!"
fi;
if [ $(whoami) != "root" ]; then
if [ "$(whoami)" != "root" ]; then
if [ ${TEST} -eq 0 ] && [ ${INFO} -eq 0 ]; then
echo "Script must be run as root user";
error=1;
@@ -183,14 +188,13 @@ if [ $error -eq 1 ]; then
fi;
# create users
cat "${ROOT_FOLDER}${input_file}" |
while read i; do
while read -r i; do
# skip rows start with # (comment)
if [[ "${i}" =~ ^\# ]]; then
continue;
fi;
# POS 2: make lower case, remove spaces
username=$(echo "${i}" | cut -d ";" -f 2 | tr A-Z a-z | tr -d ' ');
username=$(echo "${i}" | cut -d ";" -f 2 | tr "[:upper:]" "[:lower:]" | tr -d ' ');
# check username is alphanumeric with .
if ! [[ "${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 _: ${username}";
@@ -199,11 +203,24 @@ while read i; do
fi;
fi;
# POS 3: groups
_group=$(echo "${i}" | cut -d ";" -f 3 | tr A-Z a-z | tr -d ' ');
_group=$(echo "${i}" | cut -d ";" -f 3 | tr "[:upper:]" "[:lower:]" | tr -d ' ');
group=$(echo "${_group}" | cut -d "," -f 1);
sub_group="";
# POS 4: ssh access type
ssh_access_type=$(echo "${i}" | cut -d ";" -f 4 | tr A-Z a-z | tr -d ' ');
# POS 4: ssh access type and no login flag
# no login flag
no_login_flag="";
# if there is a pipe, check, else ignore
if echo "${i}" | cut -d ";" -f 4 | grep -q "|"; then
no_login_flag=$(echo "${i}" | cut -d ";" -f 4 | cut -d "|" -f 2);
fi;
# anything set in no login shell flag, we set no login shell
if [ -n "${no_login_flag}" ]; then
user_login_shell="${no_login_shell}";
else
user_login_shell="${login_shell}";
fi;
# ssh access type
ssh_access_type=$(echo "${i}" | cut -d ";" -f 4 | cut -d "|" -f 1 | tr "[:upper:]" "[:lower:]" | tr -d ' ');
# if not allow or forward, set to access
if [ "${ssh_access_type}" != "allow" ] && [ "${ssh_access_type}" != "forward" ]; then
echo "[!!] Not valid ssh access type ${ssh_access_type}, set to allow";
@@ -217,23 +234,23 @@ while read i; do
fi;
ssh_group="ssh${ssh_access_type}";
# sshallow group is always added
sub_group_opt=" -G ${ssh_group}";
sub_group_opt=("${ssh_group}");
# check if "," inside and extract sub groups
if [ -z "${_group##*,*}" ]; then
sub_group=$(echo "${_group}" | cut -d "," -f 2-);
sub_group_opt=" -G ${sub_group}";
sub_group_opt+=("${sub_group}");
fi;
# POS 5: do we have a password preset
_password=$(echo "${i}" | cut -d ";" -f 5);
# POS 6: override host name, lowercase and spaces removed
_hostname=$(echo "${i}" | cut -d ";" -f 6 | tr A-Z a-z | tr -d ' ');
_hostname=$(echo "${i}" | cut -d ";" -f 6 | tr "[:upper:]" "[:lower:]" | tr -d ' ');
if [ -z "${_hostname}" ]; then
hostname=${host};
else
hostname=${_hostname};
fi;
# POS 7: ssh keytype override
_ssh_keytype=$(echo "${i}" | cut -d ";" -f 7 | tr A-Z a-z | tr -d ' ');
_ssh_keytype=$(echo "${i}" | cut -d ";" -f 7 | tr "[:upper:]" "[:lower:]" | tr -d ' ');
if [ "${_ssh_keytype}" = "rsa" ]; then
ssh_keytype="${_ssh_keytype}";
#echo "[!!] BACKWARDS COMPATIBLE RSA TYPE SELECTION [!!]";
@@ -272,7 +289,7 @@ while read i; do
if [ ${INFO} -eq 1 ]; then
# test if pub file exists or not, test if user exists
echo -n "User: '${username}:${group}(${sub_group});${ssh_group}', SSH: ${ssh_keygen_id}";
if getent passwd ${username} > /dev/null 2>&1; then
if getent passwd "${username}" > /dev/null 2>&1; then
echo -n ", User exists";
fi;
if [ -f "${ssh_keyfile_check_pub}" ]; then
@@ -286,7 +303,7 @@ while read i; do
# add group for each entry in _group
for create_group in ${_group//,/ }; do
if [ ${TEST} -eq 0 ]; then
groupadd -f ${create_group};
groupadd -f "${create_group}";
else
echo "$> groupadd -f ${create_group}";
fi;
@@ -297,11 +314,17 @@ while read i; do
echo "-- Skip '${username}:${group}(${sub_group})'";
else
echo "++ Create '${username}:${group}(${sub_group})'";
params=(
"-c" "$(date +"%F")" "-s" "${user_login_shell}"
"-g" "${group}" "-G" "$(IFS=, ; echo "${sub_group_opt[*]}")"
"-d" "${HOME_FOLDER}${username}" "-m"
"${username}"
);
if [ ${TEST} -eq 0 ]; then
# comment is user create time
useradd -c `date +"%F"` -s /bin/bash -g ${group}${sub_group_opt} -d "${HOME_FOLDER}${username}" -m ${username};
useradd "${params[@]}";
else
echo "$> useradd -c `date +"%F"` -s /bin/bash -g ${group}${sub_group_opt} -d "${HOME_FOLDER}${username}" -m ${username}";
echo "$> useradd ${params[*]}";
fi;
fi;
# set the auth file
@@ -316,7 +339,7 @@ while read i; do
# Note we only create a password if we need it
# password + store pwgen 10 1 -1
if [ -z "${_password}" ]; then
password=$(printf "%s" $(pwgen ${PASSWORD_LENGTH} 1));
password=$(printf "%s" "$(pwgen "${PASSWORD_LENGTH}" 1)");
elif [ "${_password}" = "SET_NO_PASSWORD" ]; then
# set empty
echo "* No password set";
@@ -329,7 +352,7 @@ while read i; do
echo " > Create ssh key-pair '${ssh_keyfile}'";
if [ ${TEST} -eq 0 ]; then
ssh-keygen \
-t ${ssh_keytype} \
-t "${ssh_keytype}" \
-f "${ssh_keyfile}" \
-C "${hostname}: ${username}@${group}" \
-a 100 -N "${password}"
@@ -339,9 +362,9 @@ while read i; do
else
found='';
if [ -f "${SSH_AUTHORIZED_FILE}" ]; then
found=$(grep "$(cat ${ssh_keyfile_check_pub})" ${SSH_AUTHORIZED_FILE});
found=$(grep "$(cat "${ssh_keyfile_check_pub}")" "${SSH_AUTHORIZED_FILE}");
fi;
if [ ! -z "${found}" ]; then
if [ -n "${found}" ]; then
skip_ssh=1;
echo "-- Skip SSH Key creation: ${ssh_keygen_id}.pub";
else
@@ -359,30 +382,30 @@ while read i; do
else
create_output_file="${ROOT_FOLDER}${output_file}.TEST";
fi;
echo $(date +"%F %T")";"${host}";"${_hostname}";"${username}";"${password}";"${ssh_access_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
echo " > Create .ssh folder";
if [ ${TEST} -eq 0 ]; then
mkdir ${HOME_FOLDER}${username}/.ssh/;
mkdir "${HOME_FOLDER}${username}/.ssh/";
else
echo "$> mkdir ${HOME_FOLDER}${username}/.ssh/";
echo "$> mkdir \"${HOME_FOLDER}${username}/.ssh/\"";
fi;
fi;
# add
echo " > Add public into authorized_keys file";
if [ ${TEST} -eq 0 ]; then
if
[ ! -z "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ] &&
[ -n "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ] &&
[ -f "${SSH_AUTHORIZED_FILE}" ];
then
chattr -i ${SSH_AUTHORIZED_FILE};
chattr -i "${SSH_AUTHORIZED_FILE}";
fi;
cat "${ssh_keyfile_pub}" > ${SSH_AUTHORIZED_FILE};
cat "${ssh_keyfile_pub}" > "${SSH_AUTHORIZED_FILE}";
else
if
[ ! -z "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ] &&
[ -n "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ] &&
[ -f "${SSH_AUTHORIZED_FILE}" ];
then
echo "$> chattr -i ${SSH_AUTHORIZED_FILE}";
@@ -393,29 +416,29 @@ while read i; do
if [ -z "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}" ]; then
echo " > Secure home directory folder .ssh and authorized_keys file";
if [ ${TEST} -eq 0 ]; then
chown -R ${username}:${group} ${HOME_FOLDER}${username}/.ssh/;
chmod 700 ${HOME_FOLDER}${username}/.ssh/;
chmod 600 ${SSH_AUTHORIZED_FILE};
chown -R "${username}":"${group}" "${HOME_FOLDER}${username}/.ssh/";
chmod 700 "${HOME_FOLDER}${username}/.ssh/";
chmod 600 "${SSH_AUTHORIZED_FILE}";
else
echo "$> chown -R ${username}:${group} ${HOME_FOLDER}${username}/.ssh/";
echo "$> chmod 700 ${HOME_FOLDER}${username}/.ssh/";
echo "$> chmod 600 ${SSH_AUTHORIZED_FILE}";
echo "$> chown -R \"${username}\":\"${group}\" \"${HOME_FOLDER}${username}/.ssh/\"";
echo "$> chmod 700 \"${HOME_FOLDER}${username}/.ssh/\"";
echo "$> chmod 600 \"${SSH_AUTHORIZED_FILE}\"";
fi;
else
echo " > Secure central authorized_keys file";
if [ ${TEST} -eq 0 ]; then
chown ${username}:root ${SSH_AUTHORIZED_FILE};
chmod 400 ${SSH_AUTHORIZED_FILE};
chown "${username}":root "${SSH_AUTHORIZED_FILE}";
chmod 400 "${SSH_AUTHORIZED_FILE}";
# set +i so user can't change file
chattr +i ${SSH_AUTHORIZED_FILE};
chattr +i "${SSH_AUTHORIZED_FILE}";
else
echo "$> chown ${username}:root ${SSH_AUTHORIZED_FILE}";
echo "$> chmod 400 ${SSH_AUTHORIZED_FILE}";
echo "$> chattr +i ${SSH_AUTHORIZED_FILE}";
echo "$> chown \"${username}\":root \"${SSH_AUTHORIZED_FILE}\"";
echo "$> chmod 400 \"${SSH_AUTHORIZED_FILE}\"";
echo "$> chattr +i \"${SSH_AUTHORIZED_FILE}\"";
fi;
fi;
fi;
done;
done <<< "$(cat "${ROOT_FOLDER}${input_file}")";
# End before anything because this is just info run
if [ ${INFO} -eq 1 ]; then

View File

@@ -15,10 +15,10 @@ TEST=0; # do not run any actions
BACKUP=1;
while getopts ":tb" opt; do
case "${opt}" in
t|test)
t) # var/log/secure*bz2
TEST=1;
;;
b|nobackup)
b) # nobackup
BACKUP=0;
;;
\?)
@@ -32,7 +32,7 @@ while getopts ":tb" opt; do
done;
shift "$((OPTIND-1))"
if [ $(whoami) != "root" ]; then
if [ "$(whoami)" != "root" ]; then
if [ ${TEST} -eq 0 ]; then
echo "Script must be run as root user";
exit;
@@ -53,10 +53,10 @@ 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))"/";
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
root_folder="${BASE_FOLDER}../";
backup_folder="${BASE_FOLDER}../backup/";
SSH_KEYGEN_FOLDER_CREATED_PUB='ssh-keygen-created-pub/';
# SSH_KEYGEN_FOLDER_CREATED_PUB='ssh-keygen-created-pub/';
input_file='user_list.txt';
user_list_file="${root_folder}${input_file}";
# log file
@@ -72,7 +72,7 @@ ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
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
if [ -n "$(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}";
@@ -95,7 +95,7 @@ for username in "$@"; do
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[*]} " =~ " ${username} " ]]; then
if [[ " ${ignore_users[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
echo "[!] User ${username} is in the ignore user list";
continue;
fi;

View File

@@ -9,14 +9,18 @@
TEST=0; # no delete, just print
while getopts ":t" opt; do
case "${opt}" in
t|test)
t) # test
TEST=1;
;;
\?)
echo "";
echo "-t test run, do not lock users";
;;
esac;
done;
shift "$((OPTIND-1))"
if [ $(whoami) != "root" ]; then
if [ "$(whoami)" != "root" ]; then
if [ ${TEST} -eq 0 ]; then
echo "Script must be run as root user";
exit;
@@ -34,7 +38,7 @@ fi;
ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
# ssh reject group
ssh_reject_group="sshreject";
if [ -z $(cat /etc/group | grep "${ssh_reject_group}:") ]; then
if ! grep -q "${ssh_reject_group}:" /etc/group; then
echo "Missing ssh reject group: ${ssh_reject_group}";
exit;
fi;
@@ -51,7 +55,7 @@ for username in "$@"; do
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[*]} " =~ " ${username} " ]]; then
if [[ " ${ignore_users[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
echo "[!] User ${username} is in the ignore user list";
continue;
fi;
@@ -72,16 +76,17 @@ for username in "$@"; do
fi;
# if user is in ssh allow group and ALSO in ssh forward group -> bad
if id -nGz "${username}" | grep -qzxF "${ssh_forward_group}"; then
if [ ! -z "${ssh_remove_group}" ]; then
if [ -n "${ssh_remove_group}" ]; then
echo "[!!!! ERROR !!!!] User ${username} exists in both ${ssh_allow_group} and ${ssh_forward_group} group which should not be allowed. Remove user from one group and run script again.";
break;
fi;
ssh_remove_group="${ssh_forward_group}";
fi;
if [ ! -z "${ssh_remove_group}" ]; then
if [ -n "${ssh_remove_group}" ]; then
# remove user from ssh group and add to reject groups
echo "[*] User ${username} will be removed from ${ssh_remove_group}";
if [ ${TEST} -eq 1 ]; then
# shellcheck disable=SC2059
printf "${user_group_tpl}" "${username}" "${ssh_remove_group}" "${username}" "${ssh_reject_group}";
else
gpasswd -d "${username}" "${ssh_remove_group}";

View File

@@ -12,15 +12,15 @@ OLD_USERNAME="";
NEW_USERNAME="";
while getopts ":to:n:" opt; do
case "${opt}" in
t|test)
t) # test
TEST=1;
;;
o|old-user)
o) # old-user
if [ -z "${OLD_USERNAME}" ]; then
OLD_USERNAME="${OPTARG}";
fi;
;;
n|new-user)
n) # new-user
if [ -z "${NEW_USERNAME}" ]; then
NEW_USERNAME="${OPTARG}";
fi;
@@ -36,7 +36,7 @@ while getopts ":to:n:" opt; do
done;
shift "$((OPTIND-1))"
if [ $(whoami) != "root" ]; then
if [ "$(whoami)" != "root" ]; then
if [ ${TEST} -eq 0 ]; then
echo "Script must be run as root user";
exit;
@@ -47,15 +47,15 @@ fi;
error=0;
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
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
root_folder="${BASE_FOLDER}../";
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}";
user_list_file="${ROOT_FOLDER}${input_file}";
default_ssh_keytype='ed25519';
ssh_keytype='';
# log file
@@ -69,13 +69,14 @@ fi;
ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
# detect ssh authorized_keys setting
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER='';
SSH_AUTHORIZED_FILE='';
# SSH_AUTHORIZED_FILE='';
# shellcheck disable=SC2013
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 echo "$cf" | grep -q "%u"; then
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER="${cf/%%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;
exit;
fi;
fi;
done;
@@ -101,11 +102,11 @@ 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
if [[ " ${ignore_users[*]} " =~ [[:space:]]${OLD_USERNAME}[[:space:]] ]]; then
echo "[!] User ${OLD_USERNAME} is in the ignore user list";
error=1;
fi;
if [[ " ${ignore_users[*]} " =~ " ${NEW_USERNAME} " ]]; then
if [[ " ${ignore_users[*]} " =~ [[:space:]]${NEW_USERNAME}[[:space:]] ]]; then
echo "[!] User ${NEW_USERNAME} is in the ignore user list";
error=1;
fi;
@@ -128,12 +129,12 @@ if [ -f "${user_list_file}" ]; then
error=1;
fi;
# if the old user exists but as DELETED -> no go
if [ ! -z $(echo "${user_list_entry}" | grep "#DELETED-") ]; then
if ! echo "${user_list_entry}" | grep -q "#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
if grep -q "${NEW_USERNAME}" "${user_list_file}"; then
echo "[!!!] User ${NEW_USERNAME} exists in user_list.txt file";
error=1;
fi;
@@ -146,17 +147,17 @@ 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 "${user_list_entry}" | cut -d ";" -f 3 | tr '[:upper:]' '[:lower:]' | 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 ' ');
_hostname=$(echo "${user_list_entry}" | cut -d ";" -f 6 | tr '[:upper:]' '[:lower:]' | 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 ' ');
_ssh_keytype=$(echo "${user_list_entry}" | cut -d ";" -f 7 | tr '[:upper:]' '[:lower:]' | tr -d ' ');
if [ "${_ssh_keytype}" = "rsa" ]; then
ssh_keytype="${_ssh_keytype}";
else
@@ -170,7 +171,7 @@ new_home_dir=$(echo "${old_home_dir}" | sed -e "s/\/${OLD_USERNAME}$/\/${NEW_USE
# rename user
if [ $TEST -eq 0 ]; then
echo "usermod with ${new_home_dir}";
usermod -l ${NEW_USERNAME} -m -d "${new_home_dir}" ${OLD_USERNAME};
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
@@ -234,6 +235,8 @@ 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
# just as is print the sed command from above
# shellcheck disable=SC2028
echo "$> sed -i -e \"s/^\([A-Za-z0-9]\{1,\}\);${OLD_USERNAME};/\1;${NEW_USERNAME};/\" \"${user_list_file}\";";
fi;

View File

@@ -10,19 +10,24 @@ TEST=0; # no delete, just print
SSH_GROUP_ADD='';
while getopts ":ts:" opt; do
case "${opt}" in
t|test)
t) # test
TEST=1;
;;
s|sshgroup)
s) # sshgroup
if [ -z "${SSH_GROUP_ADD}" ]; then
SSH_GROUP_ADD=${OPTARG};
fi;
;;
\?)
echo "";
echo "-t Test only, do not change user lock status";
echo "-s <group> Override ssh group from user_list.txt for this user";
;;
esac;
done;
shift "$((OPTIND-1))"
if [ $(whoami) != "root" ]; then
if [ "$(whoami)" != "root" ]; then
if [ ${TEST} -eq 0 ]; then
echo "Script must be run as root user";
exit;
@@ -36,19 +41,19 @@ if [ $# -eq 0 ]; then
exit;
fi;
if [ ! -z "${SSH_GROUP_ADD}" ] && [ "${SSH_GROUP_ADD}" != "allow" ] && [ "${SSH_GROUP_ADD}" != "forward" ]; then
if [ -n "${SSH_GROUP_ADD}" ] && [ "${SSH_GROUP_ADD}" != "allow" ] && [ "${SSH_GROUP_ADD}" != "forward" ]; then
echo "sshgroup option can only be 'allow' or 'forward'";
exit;
fi;
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
root_folder="${BASE_FOLDER}../";
input_file='user_list.txt';
# ignore users (root and admin users)
ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
# ssh reject group
ssh_reject_group="sshreject";
if [ -z $(cat /etc/group | grep "${ssh_reject_group}:") ]; then
if ! grep -q "${ssh_reject_group}:" /etc/group; then
echo "Missing ssh reject group: ${ssh_reject_group}";
exit;
fi;
@@ -65,7 +70,7 @@ for username in "$@"; do
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[*]} " =~ " ${username} " ]]; then
if [[ " ${ignore_users[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
echo "[!] User ${username} is in the ignore user list";
continue;
fi;
@@ -88,9 +93,9 @@ for username in "$@"; do
# if not valid use allow
ssh_add_group="${SSH_GROUP_ADD}";
if [ -z "${SSH_GROUP_ADD}" ] && [ -f "${root_folder}${input_file}" ]; then
ssh_add_group=$(grep "${username}" "${root_folder}${input_file}" | cut -d ";" -f 4 | tr A-Z a-z | tr -d ' ');
ssh_add_group=$(grep "${username}" "${root_folder}${input_file}" | cut -d ";" -f 4 | tr '[:upper]' '[:lower:]' | tr -d ' ');
fi;
if [ "${ssh_access_type}" != "allow" ] && [ "${ssh_access_type}" != "forward" ]; then
if [ "${ssh_add_group}" != "allow" ] && [ "${ssh_add_group}" != "forward" ]; then
ssh_add_group="allow";
fi;
ssh_add_group="ssh${ssh_add_group}";
@@ -100,6 +105,7 @@ for username in "$@"; do
# remove user from ssh group and add to reject groups
echo "[*] User ${username} will be added to ${ssh_add_group}";
if [ ${TEST} -eq 1 ]; then
# shellcheck disable=SC2059
printf "${user_group_tpl}" "${username}" "${ssh_reject_group}" "${username}" "${ssh_add_group}";
else
gpasswd -d "${username}" "${ssh_reject_group}";

View File

@@ -1 +1 @@
#user_id;user_name;group,subgroup;ssh access type;override password;override hostname;override ssh type
#user_id;user_name;group,subgroup;ssh access type|no login flag;override password;override hostname;override ssh type