Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8cd628ddd | ||
|
|
76f9056069 | ||
|
|
74e7e9823f | ||
|
|
7ce8330aa6 | ||
|
|
d8f9710593 | ||
|
|
c37d17fe9f | ||
|
|
307433e0a7 | ||
|
|
f9cd0806f1 | ||
|
|
d9b3fd97fb | ||
|
|
21177e1762 | ||
|
|
3aa6de7e23 | ||
|
|
3c160a62e7 | ||
|
|
ca4616c5ee | ||
|
|
251b0bf981 | ||
|
|
6daccfe57c | ||
|
|
91f096ab0c | ||
|
|
935d6a84c9 | ||
|
|
ee7cc8555e | ||
|
|
83f84abd46 | ||
|
|
090d6f9cec | ||
|
|
5659cc010f | ||
|
|
0bd40cdd73 | ||
|
|
e4ed6fed8d | ||
|
|
5bf30a8b2f | ||
|
|
26c007dba6 | ||
|
|
785e3c116d | ||
|
|
adbfeb0074 | ||
|
|
8c7ef32894 | ||
|
|
70ef7a3fc5 | ||
|
|
89252af50b | ||
|
|
8fb833d3c4 | ||
|
|
694f04313c | ||
|
|
50e28c7cfd | ||
|
|
65b7a6ad43 | ||
|
|
244461d466 | ||
|
|
66213dfd65 | ||
|
|
39da44b546 | ||
|
|
d4bb06e3e1 | ||
|
|
cc647de495 | ||
|
|
68b450baaf | ||
|
|
8452a1b8c0 | ||
|
|
3fcb74ac47 |
2
.shellcheckrc
Normal file
2
.shellcheckrc
Normal file
@@ -0,0 +1,2 @@
|
||||
shell=bash
|
||||
external-sources=true
|
||||
103
Readme.md
103
Readme.md
@@ -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,41 @@ 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
|
||||
|
||||
### create_user.sh: create_user.cfg
|
||||
|
||||
A `create_user.cfg` can be created to set a differen HOME_LOCATION and PASSWORD_LENGTH values
|
||||
|
||||
eg:
|
||||
|
||||
```ini
|
||||
HOME_LOCATION="/storage"
|
||||
PASSWORD_LENGTH=14
|
||||
```
|
||||
|
||||
### authorized_key_location_change.sh: authorized_key_location_change.ignore
|
||||
|
||||
For this script a `authorized_key_location_change.ignore` with a list of user names to ignore for the
|
||||
move
|
||||
|
||||
eg:
|
||||
|
||||
```ini
|
||||
foo_user
|
||||
bar_user
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
@@ -47,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
|
||||
@@ -65,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;;;
|
||||
...
|
||||
```
|
||||
|
||||
@@ -257,6 +291,61 @@ The script can be put into the crontab and run once a month, it prints to STDOUT
|
||||
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> ...`
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,131 +4,321 @@
|
||||
# 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');
|
||||
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
|
||||
AUTH_LOG="${BASE_FOLDER}/../auth-log/user_auth.log";
|
||||
|
||||
if [ $(whoami) != "root" ]; then
|
||||
error=0;
|
||||
if [ "$(whoami)" != "root" ]; then
|
||||
echo "Script must be run as root user";
|
||||
exit;
|
||||
error=1;
|
||||
fi;
|
||||
if [ ! -d "${LOG}" ]; then
|
||||
echo "log folder ${LOG} not found";
|
||||
error=1;
|
||||
fi;
|
||||
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;
|
||||
if [ $error -eq 1 ]; then
|
||||
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";
|
||||
for ssh_group in ${ssh_groups[@]}; do
|
||||
echo "--------------------->"
|
||||
echo "Checking Group : ${ssh_group}";
|
||||
for username in $(cat /etc/group|grep "${ssh_group}:" | cut -d ":" -f 4 | sed -e 's/,/ /g'); do
|
||||
# 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://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") &&
|
||||
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)
|
||||
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";
|
||||
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
|
||||
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;
|
||||
while read -r username; 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)
|
||||
# shellcheck disable=SC2059
|
||||
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=$(grep "${username}:" /etc/passwd | 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=$(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}");
|
||||
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
|
||||
# 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="";
|
||||
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;
|
||||
if [ ! -z "${found}" ]; then
|
||||
last_login_date=$(grep "${username};" "${AUTH_LOG}" | cut -d ";" -f 2 | date +"%s" -f -);
|
||||
# always pre work account dates if they exist, but output only if text
|
||||
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
|
||||
#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 [ -n "${found}" ]; then
|
||||
last_login_date_string=$(grep "${username};" "${AUTH_LOG}" | cut -d ";" -f 2);
|
||||
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";
|
||||
lock_user=1;
|
||||
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="WARN [last ssh login ${last_login} days ago]";
|
||||
else
|
||||
out_string="OK [ssh]";
|
||||
out_string="OK [ssh, ${last_login} days ago]";
|
||||
fi;
|
||||
elif [ ! -z "${last_login_string##*$search*}" ]; then
|
||||
login_source="ssh";
|
||||
# rewrite to Y-M-D, aka
|
||||
last_login_date="${last_login_date_string}"
|
||||
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";
|
||||
lock_user=1;
|
||||
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="WARN [last terminal login ${last_login} days ago]";
|
||||
else
|
||||
out_string="OK [lastlog]";
|
||||
out_string="OK [lastlog, ${last_login} days ago]";
|
||||
fi;
|
||||
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;
|
||||
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 [ -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 [first login]";
|
||||
out_string="OK [Never logged in, created ${account_age} days ago]";
|
||||
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}";
|
||||
done;
|
||||
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)
|
||||
# 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 <<< "$(grep "${ssh_group}:" /etc/group | cut -d ":" -f 4 | sed -e 's/,/\n/g')";
|
||||
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 [ -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 [ -n "${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__
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}";
|
||||
@@ -87,6 +90,13 @@ if [ ! -d "${HOME_FOLDER}" ]; then
|
||||
echo "Home folder location not found: ${HOME_FOLDER}";
|
||||
error=1;
|
||||
fi;
|
||||
# allow 10 to 39 length for password
|
||||
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
|
||||
PASSWORD_LENGTH=14;
|
||||
fi;
|
||||
# home dir error abort
|
||||
if [ $error -eq 1 ]; then
|
||||
exit;
|
||||
@@ -104,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;
|
||||
@@ -126,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
|
||||
@@ -152,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;
|
||||
@@ -176,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}";
|
||||
@@ -192,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";
|
||||
@@ -210,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 [!!]";
|
||||
@@ -265,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
|
||||
@@ -279,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;
|
||||
@@ -290,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
|
||||
@@ -309,7 +339,11 @@ 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 14 1));
|
||||
password=$(printf "%s" "$(pwgen "${PASSWORD_LENGTH}" 1)");
|
||||
elif [ "${_password}" = "SET_NO_PASSWORD" ]; then
|
||||
# set empty
|
||||
echo "* No password set";
|
||||
password="";
|
||||
else
|
||||
echo "! Override password set";
|
||||
password=${_password};
|
||||
@@ -318,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}"
|
||||
@@ -328,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
|
||||
@@ -348,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}";
|
||||
@@ -382,42 +416,52 @@ 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
|
||||
exit;
|
||||
fi;
|
||||
# check if there are any files in the SSH_KEYGEN_FOLDER, else skip zip file creation and file move
|
||||
has_pem_files=0;
|
||||
if (shopt -s nullglob dotglob; f=("${SSH_KEYGEN_FOLDER}"*".pem"*); ((${#f[@]}))); then
|
||||
has_pem_files=1;
|
||||
fi;
|
||||
# zip everything and remove data in ssh key folder, delete output file with passwords
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
zip -r \
|
||||
"${ROOT_FOLDER}${output_zip_folder}${output_zip}" \
|
||||
"${input_file}" \
|
||||
"${output_file}" \
|
||||
"${SSH_KEYGEN_FOLDER}" \
|
||||
-x\*.gitignore;
|
||||
if [ "${has_pem_files}" -eq 1 ]; then
|
||||
zip -r \
|
||||
"${ROOT_FOLDER}${output_zip_folder}${output_zip}" \
|
||||
"${input_file}" \
|
||||
"${output_file}" \
|
||||
"${SSH_KEYGEN_FOLDER}" \
|
||||
-x\*.gitignore;
|
||||
echo "Download: ${ROOT_FOLDER}${output_zip_folder}${output_zip}";
|
||||
else
|
||||
echo "Skip ZIP file creation, no pem files";
|
||||
fi;
|
||||
else
|
||||
echo "zip -r \\"
|
||||
echo "${ROOT_FOLDER}${output_zip_folder}${output_zip} \\"
|
||||
@@ -425,15 +469,19 @@ else
|
||||
echo "${output_file} \\"
|
||||
echo "${SSH_KEYGEN_FOLDER} \\"
|
||||
echo "-x\*.gitignore;"
|
||||
echo "Download: ${ROOT_FOLDER}${output_zip_folder}${output_zip}";
|
||||
fi;
|
||||
echo "Download: ${ROOT_FOLDER}${output_zip_folder}${output_zip}";
|
||||
# cleam up user log file and ssh keys
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
# move pub to created folders
|
||||
mv "${ROOT_FOLDER}${SSH_KEYGEN_FOLDER}"*.pub "${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}";
|
||||
# delete the rest
|
||||
rm "${ROOT_FOLDER}${output_file}";
|
||||
rm "${ROOT_FOLDER}${SSH_KEYGEN_FOLDER}"*;
|
||||
if [ "${has_pem_files}" -eq 1 ]; then
|
||||
# move pub to created folders
|
||||
mv "${ROOT_FOLDER}${SSH_KEYGEN_FOLDER}"*.pub "${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}";
|
||||
# delete the rest
|
||||
rm "${ROOT_FOLDER}${output_file}";
|
||||
rm "${ROOT_FOLDER}${SSH_KEYGEN_FOLDER}"*;
|
||||
else
|
||||
echo "Skip pub file move and cleanup, no pem files";
|
||||
fi;
|
||||
else
|
||||
echo "$> mv ${ROOT_FOLDER}${SSH_KEYGEN_FOLDER}*.pub ${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB};";
|
||||
echo "$> rm ${ROOT_FOLDER}${output_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;
|
||||
|
||||
@@ -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,12 +38,12 @@ 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;
|
||||
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 "--------------------->"
|
||||
@@ -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}";
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,24 +41,24 @@ 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;
|
||||
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 "--------------------->"
|
||||
@@ -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}";
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user