Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c801ef40b4 | ||
|
|
125cb27de8 | ||
|
|
e45b89c582 | ||
|
|
4a8dab7b01 | ||
|
|
fa47178ed1 | ||
|
|
4629b58a7e | ||
|
|
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 |
2
.shellcheckrc
Normal file
2
.shellcheckrc
Normal file
@@ -0,0 +1,2 @@
|
||||
shell=bash
|
||||
external-sources=true
|
||||
66
Readme.md
66
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
|
||||
|
||||
@@ -11,20 +11,50 @@ The folder holding the script must be owned by *root* and have *600* permissions
|
||||
|
||||
```sh
|
||||
cd /root/
|
||||
git clone http://gitlab-ap.factory.tools/scripts-collections/aws-user-create.git users
|
||||
git clone <UrlToGitRepository> users
|
||||
chown root. users
|
||||
chgrp 600 users
|
||||
```
|
||||
|
||||
Alternate download:
|
||||
`git clone https://git.tequila.jp/ScriptsCollections/AwsUserCreate.git users`
|
||||
|
||||
## Folders
|
||||
|
||||
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 +77,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 +95,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;;;
|
||||
...
|
||||
```
|
||||
|
||||
@@ -235,7 +266,7 @@ If not set it defaults to allow, if a user_list.txt file with this user exist it
|
||||
|
||||
There are two scripts that can be user to check if and when the user has logged in the last time.
|
||||
|
||||
Because of users who do not open shells (for example sftp users) we cannot rely on lastlog, so a script called `collect_login_data.sh` exists that parses the systemd logind info or /var/log/secure for user authentication data.
|
||||
Because of users who do not open shells (for example sftp users) we cannot rely on lslogins, so a script called `collect_login_data.sh` exists that parses the systemd logind info or /var/log/secure for user authentication data.
|
||||
|
||||
Data is stored in `auth-log/user_auth.log` folder as `user;last login date`
|
||||
|
||||
@@ -247,7 +278,7 @@ This script should be run every day via crontab as root:
|
||||
|
||||
The script `check_last_login.sh` will go through the ssh allow groups (sshallow/sshforward) users and flag out those that have not logged in, in the last 60 days and recommend to lock them. The script will also check for user accounts that never logged in and where created in the last 30 days and recomment to lock them too.
|
||||
|
||||
This script will first check the `auth-log/user_auth.log` file, then lastlog output and finally check for creation time in passwd file or home director for when the user was created.
|
||||
This script will first check the `auth-log/user_auth.log` file, then lslogins output and finally check for creation time in passwd file or home director for when the user was created.
|
||||
|
||||
Currently only information is printed out and no action is done itself.
|
||||
|
||||
@@ -297,13 +328,8 @@ some.host,name_b,staff,sshallow,2021-11-15,767,2023-12-20 22:18:36,1,ssh,false,O
|
||||
"SubGroups": [
|
||||
"sudo",
|
||||
"users",
|
||||
"ikea",
|
||||
"harley",
|
||||
"aeon",
|
||||
"primaham",
|
||||
"nisshin",
|
||||
"nissan",
|
||||
"pfizer"
|
||||
"group_a",
|
||||
"group_b",
|
||||
],
|
||||
"AccountCreatedDate": "2021-11-15",
|
||||
"AccountAge": "767",
|
||||
|
||||
@@ -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
|
||||
@@ -84,23 +88,44 @@ if [ -f "${BASE_FOLDER}${IGNORE_USER_FILE}" ]; then
|
||||
echo "Reading ${IGNORE_USER_FILE}";
|
||||
fi;
|
||||
|
||||
LOG="${BASE_FOLDER}/../log/user_management.log";
|
||||
function write_log()
|
||||
{
|
||||
text="${1}";
|
||||
do_echo="${2}";
|
||||
log_prefix="";
|
||||
# log prefix for testing
|
||||
if [ ${TEST} -eq 1 ]; then
|
||||
log_prefix="[TEST] ";
|
||||
fi;
|
||||
# write log not in info run
|
||||
echo "[$(date +"%F %T")] [$0] ${log_prefix}${text}" >> "${LOG}";
|
||||
if [ "${do_echo}" = "1" ]; then
|
||||
echo "${text}";
|
||||
fi;
|
||||
}
|
||||
write_log "START SCRIPT RUN";
|
||||
|
||||
# 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";
|
||||
write_log "[NO ACT] ${username} 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";
|
||||
write_log "[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";
|
||||
write_log "[SKIP] ${username} skip from ignore config file";
|
||||
continue;
|
||||
fi;
|
||||
home_folder=$(echo "${user_home}" | cut -d ":" -f 2);
|
||||
@@ -109,17 +134,20 @@ while read user_home; do
|
||||
# but do we have an auth folder, if yes -> exist skip
|
||||
if [ -f "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}" ]; then
|
||||
printf "${PRINTF_INFO}" "DONE" "." "${username}" "already moved";
|
||||
write_log "[DONE] ${username} already moved";
|
||||
else
|
||||
printf "${PRINTF_INFO}" "IGNORE" "?" "${username}" "no authorized_keys file";
|
||||
write_log "[IGNORE] ${username} no authorized_keys file";
|
||||
fi;
|
||||
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";
|
||||
write_log "[ABORT] ${username} authorized key is not matching the master key file";
|
||||
exit;
|
||||
fi;
|
||||
fi;
|
||||
@@ -128,6 +156,7 @@ while read user_home; do
|
||||
ssh_key_diff=$(diff -u "${home_folder}/.ssh/authorized_keys" "${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}/${username}");
|
||||
if [ -z "${ssh_key_diff}" ]; then
|
||||
printf "${PRINTF_INFO}" "REMOVE" "-" "${username}" ".ssh/authorized_keys";
|
||||
write_log "[REMOVE] ${username} .ssh/authorized_keys";
|
||||
if [ ${master_user} -eq 0 ]; then
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
rm "${home_folder}/.ssh/authorized_keys";
|
||||
@@ -135,33 +164,36 @@ while read user_home; do
|
||||
echo "$> rm \"${home_folder}/.ssh/authorized_keys\"";
|
||||
fi;
|
||||
else
|
||||
echo "[!] No delete for master user, must be done manually";
|
||||
write_log "[!] No delete for master user, must be done manually" "1";
|
||||
fi;
|
||||
continue;
|
||||
fi;
|
||||
# No update, alert
|
||||
printf "${PRINTF_INFO}" "DIFF" "???" "${username}" "Different authorized keys in home dir, SKIPPED";
|
||||
write_log "[DIFF] ${username} Different authorized keys in home dir, SKIPPED";
|
||||
continue;
|
||||
fi;
|
||||
printf "${PRINTF_INFO}" "MOVE" ">" "${username}" "Move SSH Key to central location";
|
||||
write_log "[MOVE] ${username} Move SSH Key to central location";
|
||||
# move public keys over
|
||||
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}";
|
||||
write_log "[ERROR] ${username} Move problem ${ssh_key_diff}";
|
||||
break;
|
||||
fi;
|
||||
# remove home .ssh/authorized_keys (do not remove folder)
|
||||
if [ ${master_user} -eq 0 ]; then
|
||||
rm "${home_folder}/.ssh/authorized_keys";
|
||||
else
|
||||
echo "=> No delete for master user, must be done manually";
|
||||
write_log "=> No delete for master user, must be done manually" "1";
|
||||
fi;
|
||||
else
|
||||
echo "[START] ====>";
|
||||
|
||||
@@ -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';
|
||||
@@ -27,12 +27,29 @@ 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;
|
||||
# use lslogins instead of last log
|
||||
if [ -z "$(command -v lslogins)" ]; then
|
||||
echo "Missing lslogins application, aborting";
|
||||
error=1;
|
||||
fi;
|
||||
if [ $error -eq 1 ]; then
|
||||
exit;
|
||||
fi;
|
||||
# option 1 in list
|
||||
@@ -45,44 +62,64 @@ case "${1,,}" in
|
||||
echo "{";
|
||||
;;
|
||||
csv)
|
||||
CSV_LINE="%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n";
|
||||
OUTPUT_TARGET="csv";
|
||||
echo "Hostname,Username,Main Group,SSH Group,Account Created Date,Account Age,Last Login Date,Last Login Age,Never Logged In,Login Source,Status";
|
||||
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;
|
||||
|
||||
if [ "${OUTPUT_TARGET}" == "text" ]; then
|
||||
LOG="${LOG}/check_ssh_user."$(date +"%F_%H%m%S")".log";
|
||||
# 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 "Hostname : "$(hostname);
|
||||
echo "Run date : "$(date +"%F %T");
|
||||
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
|
||||
elif [ "${OUTPUT_TARGET}" = "json" ]; then
|
||||
echo '"Info": {'
|
||||
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
|
||||
if [ "${OUTPUT_TARGET}" == "text" ]; then
|
||||
for ssh_group in "${ssh_groups[@]}"; do
|
||||
if [ "${OUTPUT_TARGET}" = "text" ]; then
|
||||
echo "--------------------->"
|
||||
if [ "${ssh_group}" == "${ssh_reject_group}" ]; then
|
||||
if [ "${ssh_group}" = "${ssh_reject_group}" ]; then
|
||||
echo "Showing current SSH Reject users:";
|
||||
unlock_flag=1
|
||||
else
|
||||
echo "Checking Group : ${ssh_group}";
|
||||
fi;
|
||||
fi;
|
||||
for username in $(cat /etc/group|grep "${ssh_group}:" | cut -d ":" -f 4 | sed -e 's/,/ /g'); do
|
||||
while read -r username; do
|
||||
# skip empty, if group exists but has no users
|
||||
if [ "${username}" = "" ]; then
|
||||
continue;
|
||||
fi;
|
||||
# check that user exists in passwd
|
||||
if ! id "${username}" &>/dev/null; then
|
||||
out_string="[!] User $username does not exists in /etc/passwd file";
|
||||
@@ -92,8 +129,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": "",';
|
||||
@@ -102,17 +139,18 @@ for ssh_group in ${ssh_groups[@]}; do
|
||||
echo '"LastLoginAge": "",';
|
||||
echo '"LoginSource": "",';
|
||||
echo '"NeverLoggedIn": true,';
|
||||
echo '"Status": "'${out_string}'"';
|
||||
echo '"Status": "'"${out_string}"'"';
|
||||
echo "}";
|
||||
;;
|
||||
csv)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" "$(hostname)" "${username}" "" "${ssh_group}" "" "" "" "" "true" "${out_string}"
|
||||
# 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
|
||||
if [ "${OUTPUT_TARGET}" = "json" ] && [ $first_run -eq 0 ]; then
|
||||
echo ",";
|
||||
fi;
|
||||
first_run=0;
|
||||
@@ -129,24 +167,43 @@ 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 [ -z "${user_create_date_string}" ]; then
|
||||
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 [ -z "${user_create_date_string}" ]; then
|
||||
home_dir=$(cat /etc/passwd | grep "${username}:" | cut -d ":" -f 6)"/.bash_logout";
|
||||
user_create_date_string=$(stat -c %Z "${home_dir}");
|
||||
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);
|
||||
search="Never logged in";
|
||||
# for the rest use lslogin, returns ":" separted list, not set is never logged in
|
||||
# LAST LOGIN :FAILED LOGIN
|
||||
# 2025-09-12T09:56:22+09:00:
|
||||
last_login_string=$(
|
||||
lslogins \
|
||||
-c --noheadings --notruncate \
|
||||
--time-format=iso \
|
||||
-o LAST-LOGIN,FAILED-LOGIN \
|
||||
-l "${username}"
|
||||
);
|
||||
last_login_date=$(echo "${last_login_string}" | cut -d ":" -f 1);
|
||||
# search="Never logged in";
|
||||
never_logged_in="false";
|
||||
found="";
|
||||
login_source="";
|
||||
@@ -158,7 +215,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 "${found}" ] && [ ! -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
|
||||
@@ -166,44 +223,48 @@ 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";
|
||||
lock_user=1;
|
||||
elif [ ${last_login} -gt ${warn_age_login} ]; then
|
||||
out_string="OK [last ssh login ${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="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_date}" ]; 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
|
||||
# we get an ISO DATE with timezone
|
||||
last_login_date=$(echo "${last_login_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 terminal log in ${last_login} days ago";
|
||||
lock_user=1;
|
||||
elif [ ${last_login} -gt ${warn_age_login} ]; then
|
||||
out_string="OK [last terminal login ${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="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
|
||||
last_login_date=$(echo "${last_login_string}" | 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";
|
||||
lock_user=1;
|
||||
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
|
||||
@@ -211,7 +272,7 @@ for ssh_group in ${ssh_groups[@]}; do
|
||||
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;
|
||||
case "${OUTPUT_TARGET}" in
|
||||
@@ -222,7 +283,7 @@ for ssh_group in ${ssh_groups[@]}; do
|
||||
sub_groups_string="["
|
||||
sub_group_first=1
|
||||
for s_group in $sub_groups; do
|
||||
if [ "${sub_group_first}" == 0 ]; then
|
||||
if [ "${sub_group_first}" = 0 ]; then
|
||||
sub_groups_string="${sub_groups_string},";
|
||||
fi;
|
||||
sub_groups_string="${sub_groups_string}\"${s_group}\"";
|
||||
@@ -230,44 +291,45 @@ 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)
|
||||
printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" "$(hostname)" "${username}" "${main_group}" "${ssh_group}" "${user_create_date_out}" "${account_age}" "${last_login_date}" "${last_login}" "${never_logged_in}" "${login_source}" "${out_string}"
|
||||
# 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/,/\n/g')";
|
||||
done;
|
||||
if [ "${OUTPUT_TARGET}" == "text" ]; then
|
||||
if [ ! -z "${lock_accounts}" ]; then
|
||||
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 [ ! -z "${unlock_accounts}" ]; then
|
||||
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 ${lock_accounts}";
|
||||
echo "bin/unlock_user.sh -s allow ${unlock_accounts}";
|
||||
echo "";
|
||||
echo "For FORWARDONLY:"
|
||||
echo "bin/unlock_user.sh -s forward ${lock_accounts}";
|
||||
echo "bin/unlock_user.sh -s forward ${unlock_accounts}";
|
||||
fi;
|
||||
echo "[END] ===============>"
|
||||
elif [ "${OUTPUT_TARGET}" == "json" ]; then
|
||||
elif [ "${OUTPUT_TARGET}" = "json" ]; then
|
||||
# users
|
||||
echo "]";
|
||||
# overall
|
||||
|
||||
@@ -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;
|
||||
@@ -164,6 +176,12 @@ if [ $(whoami) != "root" ]; then
|
||||
fi;
|
||||
fi;
|
||||
|
||||
# do not allow test and info at the same
|
||||
if [ ${TEST} -eq 1 ] && [ ${INFO} -eq 1 ]; then
|
||||
echo "Cannot have --test and --info option at the same time";
|
||||
error=1;
|
||||
fi;
|
||||
|
||||
# exit if not -g parameter set
|
||||
if [ $GO -eq 0 ]; then
|
||||
echo "Script has to be run with -g option for actual user creation.";
|
||||
@@ -175,58 +193,99 @@ if [ $error -eq 1 ]; then
|
||||
exit;
|
||||
fi;
|
||||
|
||||
LOG="${BASE_FOLDER}/../log/user_management.log";
|
||||
function write_log()
|
||||
{
|
||||
text="${1}";
|
||||
do_echo="${2}";
|
||||
log_prefix="";
|
||||
# log prefix for testing
|
||||
if [ ${TEST} -eq 1 ]; then
|
||||
log_prefix="[TEST] ";
|
||||
fi;
|
||||
# write log not in info run
|
||||
if [ ${INFO} -eq 0 ]; then
|
||||
echo "[$(date +"%F %T")] [$0] ${log_prefix}${text}" >> "${LOG}";
|
||||
fi;
|
||||
if [ "${do_echo}" = "1" ]; then
|
||||
echo "${text}";
|
||||
fi;
|
||||
}
|
||||
write_log "START SCRIPT RUN";
|
||||
|
||||
# used for test run only
|
||||
overall_run_error=0;
|
||||
|
||||
# MARK: LOOP START
|
||||
# create users
|
||||
cat "${ROOT_FOLDER}${input_file}" |
|
||||
while read i; do
|
||||
while read -r i; do
|
||||
# run error for one row
|
||||
run_error=0;
|
||||
# skip rows start with # (comment)
|
||||
if [[ "${i}" =~ ^\# ]]; then
|
||||
continue;
|
||||
fi;
|
||||
|
||||
# log create inly on not info
|
||||
if [ ${INFO} -eq 0 ]; then
|
||||
write_log "[CREATE] ROW: $i";
|
||||
fi;
|
||||
|
||||
# MARK: VALUES CHECK
|
||||
# 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}";
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
break;
|
||||
fi;
|
||||
run_error=1;
|
||||
write_log "[ERROR] User name can only be a-z 0-9 - _ . and cannot start or end with - . or _: ${username}" "1";
|
||||
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";
|
||||
ssh_access_type="allow";
|
||||
run_error=1;
|
||||
write_log "[ERROR] Not valid ssh access type ${ssh_access_type}" "1";
|
||||
fi;
|
||||
if [ $ssh_forward_ok -eq 0 ] && [ "${ssh_access_type}" = "forward" ]; then
|
||||
echo "[!!!] sshforward group does not exsts, cannot set user ${username}";
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
break;
|
||||
fi;
|
||||
write_log "[ERROR] sshforward group does not exsts, cannot set user ${username}" "1";
|
||||
run_error=1;
|
||||
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 [!!]";
|
||||
@@ -235,24 +294,35 @@ while read i; do
|
||||
fi;
|
||||
# user & group not set
|
||||
if [ -z "${username}" ] || [ -z "${_group}" ]; then
|
||||
echo "[!!!!!] Missing user or group entry for ${username}/${_group}";
|
||||
echo "[*** ABORT RUN ***]"
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
break;
|
||||
fi;
|
||||
run_error=1;
|
||||
write_log "[ERROR] Missing user or group entry for ${username}/${_group}" "1";
|
||||
else
|
||||
group_error=0;
|
||||
# check group names valid
|
||||
for create_group in ${_group//,/ }; do
|
||||
if ! [[ "${create_group}" =~ ^[a-z0-9]+([a-z0-9_-]+[a-z0-9])?$ ]]; then
|
||||
echo "Group name can only be a-z 0-9 - _ and cannot start or end with - or _: ${create_group}";
|
||||
write_log "[ERROR] Group name can only be a-z 0-9 - _ and cannot start or end with - or _: ${create_group}" "1";
|
||||
group_error=1;
|
||||
fi;
|
||||
done;
|
||||
if [ $group_error -eq 1 ] && [ ${TEST} -eq 0 ]; then
|
||||
break;
|
||||
if [ $group_error -eq 1 ]; then
|
||||
run_error=1;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
# error & test -> break
|
||||
if [ ${run_error} -eq 1 ]; then
|
||||
overall_run_error=1;
|
||||
write_log "[*** ABORT RUN ***]" "1";
|
||||
# end if not test and not info
|
||||
if [ ${TEST} -eq 0 ] && [ ${INFO} -eq 0 ]; then
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
# MARK: SSH NAMES SET
|
||||
# SSH file name part without folder
|
||||
ssh_keygen_id="${hostname}${separator}${group}${separator}${username}${separator}${ssh_keytype}.pem";
|
||||
# the full file including folder name
|
||||
@@ -262,24 +332,25 @@ while read i; do
|
||||
# check existing pub file
|
||||
ssh_keyfile_check_pub="${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}${ssh_keygen_id}.pub";
|
||||
|
||||
# MARK: INFO
|
||||
if [ ${INFO} -eq 1 ]; then
|
||||
info_string="User: '${username}:${group}(${sub_group});${ssh_group}', SSH: ${ssh_keygen_id}";
|
||||
# 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
|
||||
echo -n ", User exists";
|
||||
if getent passwd "${username}" > /dev/null 2>&1; then
|
||||
info_string="${info_string}, User exists";
|
||||
fi;
|
||||
if [ -f "${ssh_keyfile_check_pub}" ]; then
|
||||
echo -n ", SSH Pub key OK";
|
||||
info_string="${info_string}, SSH Pub key OK";
|
||||
fi;
|
||||
# line break
|
||||
echo "";
|
||||
echo "${info_string}";
|
||||
continue;
|
||||
fi;
|
||||
|
||||
# MARK: CREATE
|
||||
# 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;
|
||||
@@ -287,14 +358,20 @@ while read i; do
|
||||
# check if user is not already created
|
||||
# if getent passwd ${username} > /dev/null 2>&1; then
|
||||
if id "${username}" &>/dev/null; then
|
||||
echo "-- Skip '${username}:${group}(${sub_group})'";
|
||||
write_log "-- Skip '${username}:${group}(${sub_group})'" "1";
|
||||
else
|
||||
echo "++ Create '${username}:${group}(${sub_group})'";
|
||||
write_log "++ Create '${username}:${group}(${sub_group})'" "1";
|
||||
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,16 +386,20 @@ 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};
|
||||
fi;
|
||||
# create SSH key
|
||||
echo " > Create ssh key-pair '${ssh_keyfile}'";
|
||||
write_log " > Create ssh key-pair: ${ssh_keyfile}" "1";
|
||||
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,50 +409,51 @@ 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";
|
||||
write_log "-- Skip SSH Key creation: ${ssh_keygen_id}.pub" "1";
|
||||
else
|
||||
# override previously set with stored one
|
||||
ssh_keyfile_pub=${ssh_keyfile_check_pub};
|
||||
echo " < Use existing public ssh key '${ssh_keygen_id}.pub'";
|
||||
write_log " < Use existing public ssh key: ${ssh_keygen_id}.pub" "1";
|
||||
# Password already set notification
|
||||
fi;
|
||||
password="[ALREADY SET]";
|
||||
fi;
|
||||
if [ ${skip_ssh} -eq 0 ]; then
|
||||
# MARK: SSH CREATE
|
||||
# write login info to output file
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
create_output_file="${ROOT_FOLDER}${output_file}";
|
||||
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 +464,54 @@ 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;
|
||||
|
||||
# MARK: ZIP FILE CREATE
|
||||
# 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,19 +519,28 @@ 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}";
|
||||
echo "$> rm ${ROOT_FOLDER}${SSH_KEYGEN_FOLDER}*";
|
||||
fi;
|
||||
|
||||
# MARK: TEST ERROR INFO
|
||||
if [ ${TEST} -eq 1 ] && [ ${overall_run_error} -eq 1 ]; then
|
||||
echo "[ERROR] Some errors occoured during the run, they will prohibit the live run of this script";
|
||||
fi;
|
||||
|
||||
# __END__
|
||||
|
||||
@@ -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,27 +53,23 @@ 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
|
||||
LOG="${BASE_FOLDER}/../log/delete_user."$(date +"%F_%H%m%S");
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
LOG="${LOG}.log";
|
||||
else
|
||||
LOG="${LOG}.test.log";
|
||||
fi;
|
||||
HISTORY="${BASE_FOLDER}/../log/delete_user.log";
|
||||
# ignore users (root and admin users)
|
||||
ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
|
||||
# detect ssh authorized_keys setting
|
||||
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER='';
|
||||
SSH_AUTHORIZED_FILE='';
|
||||
for cf in $(grep "^AuthorizedKeysFile" /etc/ssh/sshd_config | grep "%u"); do
|
||||
if [ ! -z $(echo "${cf}" | grep "%u") ]; then
|
||||
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER=$(echo "${cf}" | sed -e 's/%u//');
|
||||
# shellcheck disable=SC2013
|
||||
for cf in $(grep "^AuthorizedKeysFile" "/etc/ssh/sshd_config" | grep "%u"); do
|
||||
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;
|
||||
@@ -86,17 +82,39 @@ if [ ! -f "${user_list_file}" ]; then
|
||||
exit;
|
||||
fi;
|
||||
|
||||
LOG="${BASE_FOLDER}/../log/user_management.log";
|
||||
function write_log()
|
||||
{
|
||||
text="${1}";
|
||||
do_echo="${2}";
|
||||
log_prefix="";
|
||||
# log prefix for testing
|
||||
if [ ${TEST} -eq 1 ]; then
|
||||
log_prefix="[TEST] ";
|
||||
fi;
|
||||
# write log not in info run
|
||||
echo "[$(date +"%F %T")] [$0] ${log_prefix}${text}" >> "${LOG}";
|
||||
if [ "${do_echo}" = "1" ]; then
|
||||
echo "${text}";
|
||||
fi;
|
||||
}
|
||||
write_log "START SCRIPT RUN";
|
||||
|
||||
# used for test run only
|
||||
overall_run_error=0;
|
||||
|
||||
# $1 ... $n
|
||||
for username in "$@"; do
|
||||
error=0;
|
||||
# skip if there is an option hidden
|
||||
# shellcheck disable=SC2154
|
||||
if [[ ${_arg:0:1} = "-" ]]; then
|
||||
continue;
|
||||
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
|
||||
echo "[!] User ${username} is in the ignore user list";
|
||||
if [[ " ${ignore_users[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
|
||||
write_log "[!] User ${username} is in the ignore user list" "1";
|
||||
continue;
|
||||
fi;
|
||||
|
||||
@@ -104,31 +122,33 @@ for username in "$@"; do
|
||||
# if missing in or another do not continue
|
||||
if ! id "${username}" &>/dev/null; then
|
||||
# not in passwd
|
||||
echo "[!!!] User ${username} does not exist in /etc/passwd";
|
||||
write_log "[ERRPR] User ${username} does not exist in /etc/passwd" "1";
|
||||
error=1;
|
||||
fi;
|
||||
user_list_entry=$(grep "${username}" "${user_list_file}");
|
||||
if [ -z "${user_list_entry}" ]; then
|
||||
echo "[!!!] User ${username} does not exist in user_list.txt file";
|
||||
write_log "[ERROR] User ${username} does not exist in user_list.txt file" "1";
|
||||
error=1;
|
||||
elif [[ "${user_list_entry}" =~ ^#DELETED ]]; then
|
||||
echo "[!!!] User ${username} is flagged as deleted in user_list.txt file";
|
||||
write_log "[ERROR] User ${username} is flagged as deleted in user_list.txt file" "1";
|
||||
error=1;
|
||||
fi;
|
||||
|
||||
if [ $error -eq 1 ]; then
|
||||
overall_run_error=1;
|
||||
write_log "[*** ABORT RUN ***]" "1";
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
break;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
echo "=> Delete: ${username}";
|
||||
write_log "=> Delete: ${username}" "1";
|
||||
# ssh authorized file
|
||||
SSH_AUTHORIZED_FILE="${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}${username}";
|
||||
|
||||
# make backup from /home
|
||||
if [ ${BACKUP} -eq 1 ]; then
|
||||
home_folder=$(getent passwd ${username} | cut -d ":" -f 6);
|
||||
home_folder=$(getent passwd "${username}" | cut -d ":" -f 6);
|
||||
backup_file="${backup_folder}${host}${separator}${username}.${timestamp}.tar.bz2";
|
||||
files_list="${home_folder}";
|
||||
if [ -f "${SSH_AUTHORIZED_FILE}" ]; then
|
||||
@@ -136,7 +156,7 @@ for username in "$@"; do
|
||||
fi;
|
||||
echo "[0] Backup ${files_list} to ${backup_file}";
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
tar cfjp "${backup_file}" ${file_list};
|
||||
tar cfjp "${backup_file}" "${files_list}";
|
||||
else
|
||||
echo "$> tar cfjp \"${backup_file}\" ${files_list};";
|
||||
fi;
|
||||
@@ -144,9 +164,13 @@ for username in "$@"; do
|
||||
|
||||
echo "[1] Remove user + home dir";
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
userdel -r ${username}
|
||||
# remove all secondary group entries first before we delete the user
|
||||
# there might be cases where they are left
|
||||
usermod -G "" "${username}";
|
||||
userdel -r "${username}";
|
||||
else
|
||||
echo "$> userdel -r ${username}";
|
||||
echo "$> usermod -G \"\" \"${username}\"";
|
||||
echo "$> userdel -r \"${username}\"";
|
||||
fi;
|
||||
|
||||
# remove ssh files in pub
|
||||
@@ -162,7 +186,7 @@ for username in "$@"; do
|
||||
fi;
|
||||
else
|
||||
# Not critical error
|
||||
echo "[?] Cannot find ${SSH_AUTHORIZED_FILE}";
|
||||
write_log "[?] Cannot find ${SSH_AUTHORIZED_FILE}" "1";
|
||||
fi;
|
||||
|
||||
# Update user_list.txt file and add # for the line
|
||||
@@ -172,11 +196,17 @@ for username in "$@"; do
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
sed -i -e "s/^\([A-Za-z0-9]\{1,\};${username};\)/#DELETED-${delete_date}:\1/" "${user_list_file}";
|
||||
else
|
||||
# shellcheck disable=SC2028
|
||||
echo "$> sed -i -e \"s/^\([A-Za-z0-9]\{1,\};${username};\)/#DELETED-${delete_date}:\1/\" \"${user_list_file}\";";
|
||||
fi;
|
||||
|
||||
echo $(date +"%F %T")";${host};${username}" >> "${LOG}";
|
||||
echo "$(date +"%F %T");${host};${username};${TEST}" >> "${HISTORY}";
|
||||
|
||||
done;
|
||||
|
||||
# MARK: TEST ERROR INFO
|
||||
if [ ${TEST} -eq 1 ] && [ ${overall_run_error} -eq 1 ]; then
|
||||
echo "[ERROR] Some errors occoured during the run, they will prohibit the live run of this script";
|
||||
fi;
|
||||
|
||||
# __END__
|
||||
|
||||
@@ -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,35 +38,58 @@ 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";
|
||||
|
||||
# base folder for all data
|
||||
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
|
||||
LOG="${BASE_FOLDER}/../log/user_management.log";
|
||||
function write_log()
|
||||
{
|
||||
text="${1}";
|
||||
do_echo="${2}";
|
||||
log_prefix="";
|
||||
# log prefix
|
||||
if [ ${TEST} -eq 1 ]; then
|
||||
log_prefix="TEST";
|
||||
fi;
|
||||
if [ -n "${log_prefix}" ]; then
|
||||
log_prefix="[${log_prefix}] ";
|
||||
fi;
|
||||
echo "[$(date +"%F %T")] [$0] ${log_prefix}${text}" >> "${LOG}";
|
||||
if [ "${do_echo}" = "1" ]; then
|
||||
echo "${text}";
|
||||
fi;
|
||||
}
|
||||
write_log "START SCRIPT RUN";
|
||||
|
||||
echo "--------------------->"
|
||||
# $1 ... $n
|
||||
for username in "$@"; do
|
||||
# skip if there is an option hidden
|
||||
# shellcheck disable=SC2154
|
||||
if [[ ${_arg:0:1} = "-" ]]; then
|
||||
continue;
|
||||
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
|
||||
echo "[!] User ${username} is in the ignore user list";
|
||||
if [[ " ${ignore_users[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
|
||||
write_log "[ERROR] User ${username} is in the ignore user list" "1";
|
||||
continue;
|
||||
fi;
|
||||
# check that user exists in passwd
|
||||
if ! id "${username}" &>/dev/null; then
|
||||
echo "[!] User ${username} does not exists in /etc/passwd file";
|
||||
write_log "[ERROR] User ${username} does not exists in /etc/passwd file" "1";
|
||||
continue;
|
||||
fi;
|
||||
# if not check if in reject list
|
||||
if id -nGz "${username}" | grep -qzxF "${ssh_reject_group}"; then
|
||||
echo "[.] User ${username} already in the ${ssh_reject_group} list";
|
||||
write_log "[.] User ${username} already in the ${ssh_reject_group} list";
|
||||
continue;
|
||||
fi;
|
||||
# check if user is in sshallow/forward list
|
||||
@@ -72,16 +99,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
|
||||
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.";
|
||||
if [ -n "${ssh_remove_group}" ]; then
|
||||
write_log "[!!!! 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." "1";
|
||||
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}";
|
||||
write_log "[*] User ${username} will be removed from ${ssh_remove_group}" "1";
|
||||
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}";
|
||||
@@ -89,7 +117,7 @@ for username in "$@"; do
|
||||
fi;
|
||||
else
|
||||
# skip not ssh user
|
||||
echo "[?] User ${username} not in any ssh allow/foward groups";
|
||||
write_log "[?] User ${username} not in any ssh allow/foward groups" "1";
|
||||
fi;
|
||||
done;
|
||||
|
||||
|
||||
@@ -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,35 +47,29 @@ 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
|
||||
LOG="${BASE_FOLDER}/../log/rename_user."$(date +"%F_%H%m%S");
|
||||
if [ ${TEST} -eq 0 ]; then
|
||||
LOG="${LOG}.log";
|
||||
else
|
||||
LOG="${LOG}.test.log";
|
||||
fi;
|
||||
# ignore users (root and admin users)
|
||||
ignore_users=('root' 'ec2-user' 'ubuntu' 'admin');
|
||||
# detect ssh authorized_keys setting
|
||||
SSH_CENTRAL_AUTHORIZED_FILE_FOLDER='';
|
||||
SSH_AUTHORIZED_FILE='';
|
||||
# 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 +95,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 +122,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;
|
||||
@@ -143,34 +137,55 @@ if [ $error -eq 1 ]; then
|
||||
exit;
|
||||
fi;
|
||||
|
||||
# log file
|
||||
LOG="${BASE_FOLDER}/../log/user_management.log";
|
||||
function write_log()
|
||||
{
|
||||
text="${1}";
|
||||
do_echo="${2}";
|
||||
log_prefix="";
|
||||
# log prefix
|
||||
if [ ${TEST} -eq 1 ]; then
|
||||
log_prefix="TEST";
|
||||
fi;
|
||||
if [ -n "${log_prefix}" ]; then
|
||||
log_prefix="[${log_prefix}] ";
|
||||
fi;
|
||||
echo "[$(date +"%F %T")] [$0] ${log_prefix}${text}" >> "${LOG}";
|
||||
if [ "${do_echo}" = "1" ]; then
|
||||
echo "${text}";
|
||||
fi;
|
||||
}
|
||||
write_log "START SCRIPT RUN";
|
||||
|
||||
# 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
|
||||
ssh_keytype=${default_ssh_keytype};
|
||||
fi;
|
||||
|
||||
echo "* Rename ${OLD_USERNAME} to ${NEW_USERNAME}";
|
||||
write_log "* Rename ${OLD_USERNAME} to ${NEW_USERNAME}" "1";
|
||||
|
||||
old_home_dir=$(getent passwd "${OLD_USERNAME}" | cut -d: -f6);
|
||||
new_home_dir=$(echo "${old_home_dir}" | sed -e "s/\/${OLD_USERNAME}$/\/${NEW_USERNAME}/");
|
||||
# rename user
|
||||
if [ $TEST -eq 0 ]; then
|
||||
echo "usermod with ${new_home_dir}";
|
||||
usermod -l ${NEW_USERNAME} -m -d "${new_home_dir}" ${OLD_USERNAME};
|
||||
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
|
||||
@@ -201,7 +216,7 @@ NEW_SSH_AUTHORIZED_FILE="${SSH_CENTRAL_AUTHORIZED_FILE_FOLDER}${NEW_USERNAME}";
|
||||
|
||||
if [ -f "${OLD_SSH_AUTHORIZED_FILE}" ]; then
|
||||
if [ $TEST -eq 0 ]; then
|
||||
echo "rename to ${NEW_SSH_AUTHORIZED_FILE}";
|
||||
write_log "rename to ${NEW_SSH_AUTHORIZED_FILE}" "1";
|
||||
chattr -i "${OLD_SSH_AUTHORIZED_FILE}";
|
||||
mv "${OLD_SSH_AUTHORIZED_FILE}" "${NEW_SSH_AUTHORIZED_FILE}";
|
||||
chattr +i "${NEW_SSH_AUTHORIZED_FILE}";
|
||||
@@ -211,7 +226,7 @@ if [ -f "${OLD_SSH_AUTHORIZED_FILE}" ]; then
|
||||
echo "$> chattr +i \"${NEW_SSH_AUTHORIZED_FILE}\";";
|
||||
fi;
|
||||
else
|
||||
echo "[?] ${OLD_SSH_AUTHORIZED_FILE} is missing";
|
||||
write_log "[?] ${OLD_SSH_AUTHORIZED_FILE} is missing" "1";
|
||||
fi;
|
||||
|
||||
# rename keygen public file
|
||||
@@ -220,13 +235,13 @@ NEW_ssh_keygen_pub="${ROOT_FOLDER}${SSH_KEYGEN_FOLDER_CREATED_PUB}${hostname}${s
|
||||
|
||||
if [ -f "${OLD_ssh_keygen_pub}" ]; then
|
||||
if [ $TEST -eq 0 ]; then
|
||||
echo "rename to ${NEW_ssh_keygen_pub}";
|
||||
write_log "rename to ${NEW_ssh_keygen_pub}" "1";
|
||||
mv "${OLD_ssh_keygen_pub}" "${NEW_ssh_keygen_pub}";
|
||||
else
|
||||
echo "$> mv \"${OLD_ssh_keygen_pub}\" \"${NEW_ssh_keygen_pub}\";";
|
||||
fi;
|
||||
else
|
||||
echo "[?] ${OLD_ssh_keygen_pub} is missing";
|
||||
write_log "[?] ${OLD_ssh_keygen_pub} is missing" "1";
|
||||
fi;
|
||||
|
||||
# rename entry in user list txt file
|
||||
@@ -234,6 +249,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,51 +41,72 @@ 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";
|
||||
|
||||
LOG="${BASE_FOLDER}/../log/user_management.log";
|
||||
function write_log()
|
||||
{
|
||||
text="${1}";
|
||||
do_echo="${2}";
|
||||
log_prefix="";
|
||||
# log prefix
|
||||
if [ ${TEST} -eq 1 ]; then
|
||||
log_prefix="TEST";
|
||||
fi;
|
||||
if [ -n "${log_prefix}" ]; then
|
||||
log_prefix="[${log_prefix}] ";
|
||||
fi;
|
||||
echo "[$(date +"%F %T")] [$0] ${log_prefix}${text}" >> "${LOG}";
|
||||
if [ "${do_echo}" = "1" ]; then
|
||||
echo "${text}";
|
||||
fi;
|
||||
}
|
||||
write_log "START SCRIPT RUN";
|
||||
|
||||
echo "--------------------->"
|
||||
# $1 ... $n
|
||||
for username in "$@"; do
|
||||
# skip if there is an option hidden
|
||||
# shellcheck disable=SC2154
|
||||
if [[ ${_arg:0:1} = "-" ]]; then
|
||||
continue;
|
||||
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
|
||||
echo "[!] User ${username} is in the ignore user list";
|
||||
if [[ " ${ignore_users[*]} " =~ [[:space:]]${username}[[:space:]] ]]; then
|
||||
write_log "[ERROR] User ${username} is in the ignore user list" "1";
|
||||
continue;
|
||||
fi;
|
||||
# check that user exists in passwd
|
||||
if ! id "${username}" &>/dev/null; then
|
||||
echo "[!] User ${username} does not exists in /etc/passwd file";
|
||||
write_log "[ERROR] User ${username} does not exists in /etc/passwd file" "1";
|
||||
continue;
|
||||
fi;
|
||||
# check if already in OK groups
|
||||
if id -nGz "${username}" | grep -qzxF "${ssh_allow_group}"; then
|
||||
echo "[.] User ${username} already in the ${ssh_allow_group} list";
|
||||
write_log "[.] User ${username} already in the ${ssh_allow_group} list" "1";
|
||||
continue;
|
||||
fi;
|
||||
if id -nGz "${username}" | grep -qzxF "${ssh_forward_group}"; then
|
||||
echo "[.] User ${username} already in the ${ssh_forward_group} list";
|
||||
write_log "[.] User ${username} already in the ${ssh_forward_group} list" "1";
|
||||
continue;
|
||||
fi;
|
||||
# try to find user in user_list.txt and get the allow/forward flag from there,
|
||||
@@ -88,9 +114,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}";
|
||||
@@ -98,8 +124,9 @@ for username in "$@"; do
|
||||
# check if user is in reject group remove
|
||||
if id -nGz "${username}" | grep -qzxF "${ssh_reject_group}"; then
|
||||
# remove user from ssh group and add to reject groups
|
||||
echo "[*] User ${username} will be added to ${ssh_add_group}";
|
||||
write_log "[*] User ${username} will be added to ${ssh_add_group}" "1";
|
||||
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}";
|
||||
@@ -107,7 +134,7 @@ for username in "$@"; do
|
||||
fi;
|
||||
else
|
||||
# skip not ssh user
|
||||
echo "[?] User ${username} not in the ssh reject group";
|
||||
write_log "[?] User ${username} not in the ssh reject group" "1";
|
||||
fi;
|
||||
done;
|
||||
|
||||
|
||||
@@ -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