Add new_sudo_user_cert
This commit is contained in:
parent
245b634422
commit
c2a158c46e
283
new_sudo_user_cert
Normal file
283
new_sudo_user_cert
Normal file
@ -0,0 +1,283 @@
|
||||
#!/usr/bin/env bash
|
||||
# user_manage.sh
|
||||
# Interactive script to create/delete sudo users and manage SSH keys.
|
||||
# - Generates ed25519 keypair per user and saves them to /root/created_user_keys/<username>-<timestamp>/
|
||||
# - Installs public key into user's authorized_keys and sets permissions
|
||||
# - Adds user to sudo/wheel group
|
||||
# - Allows deleting user and cleaning keys/home
|
||||
#
|
||||
# Usage: sudo ./user_manage.sh
|
||||
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
BASE_KEY_DIR="/root/created_user_keys"
|
||||
|
||||
# UI helpers — send user messages to stderr so functions can return values on stdout
|
||||
function step() { printf "\n\033[1;34m==> %s\033[0m\n" "$1" >&2; }
|
||||
function ok() { printf " \033[1;32m[OK]\033[0m %s\n" "$1" >&2; }
|
||||
function warn() { printf " \033[1;33m[WARN]\033[0m %s\n" "$1" >&2; }
|
||||
function fail() { printf " \033[1;31m[FAIL]\033[0m %s\n" "$1" >&2; }
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
fail "This script must be run as root. Use: sudo $0"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
mkdir -p "$BASE_KEY_DIR"
|
||||
chmod 700 "$BASE_KEY_DIR"
|
||||
|
||||
# Detect distro and sudo group
|
||||
SUDO_GROUP="sudo"
|
||||
if getent group sudo >/dev/null 2>&1; then
|
||||
SUDO_GROUP="sudo"
|
||||
elif getent group wheel >/dev/null 2>&1; then
|
||||
SUDO_GROUP="wheel"
|
||||
fi
|
||||
|
||||
# Helper to create user (common tasks)
|
||||
create_user_common() {
|
||||
local USERNAME="$1"
|
||||
if id "$USERNAME" &>/dev/null; then
|
||||
fail "User $USERNAME already exists."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if command -v adduser >/dev/null 2>&1 && { [ -f /etc/debian_version ] || command -v apt-get >/dev/null 2>&1 || [ -f /etc/lsb-release ] ; }; then
|
||||
step "Creating user '$USERNAME' (adduser)"
|
||||
adduser --disabled-password --gecos "" "$USERNAME"
|
||||
else
|
||||
step "Creating user '$USERNAME' (useradd fallback)"
|
||||
useradd -m -s /bin/bash "$USERNAME"
|
||||
fi
|
||||
|
||||
ok "User $USERNAME created."
|
||||
|
||||
# add to sudo/wheel
|
||||
usermod -aG "$SUDO_GROUP" "$USERNAME"
|
||||
ok "Added $USERNAME to $SUDO_GROUP group."
|
||||
}
|
||||
|
||||
# generate_keypair: prints only the key directory on stdout (so callers can capture it)
|
||||
generate_keypair() {
|
||||
local USERNAME="$1"
|
||||
local DATESTAMP
|
||||
DATESTAMP="$(date '+%Y%m%d_%H%M%S')"
|
||||
local KEY_DIR="$BASE_KEY_DIR/$USERNAME-$DATESTAMP"
|
||||
mkdir -p "$KEY_DIR"
|
||||
chmod 700 "$KEY_DIR"
|
||||
|
||||
# generate ed25519 keypair WITHOUT passphrase; to add passphrase remove -N ""
|
||||
ssh-keygen -t ed25519 -f "$KEY_DIR/id_ed25519" -N "" -C "$USERNAME@$(hostname -f)" >/dev/null 2>&1
|
||||
|
||||
chmod 600 "$KEY_DIR/id_ed25519"
|
||||
chmod 644 "$KEY_DIR/id_ed25519.pub"
|
||||
|
||||
# status message to stderr
|
||||
ok "Generated ed25519 keypair for $USERNAME in $KEY_DIR"
|
||||
|
||||
# echo only the path on stdout so the caller can capture it safely
|
||||
echo "$KEY_DIR"
|
||||
}
|
||||
|
||||
# Install public key into user's authorized_keys
|
||||
install_pubkey_for_user() {
|
||||
local USERNAME="$1"
|
||||
local PUBKEY_LINE="$2"
|
||||
|
||||
local USER_HOME
|
||||
USER_HOME=$(eval echo "~$USERNAME")
|
||||
local SSH_DIR="$USER_HOME/.ssh"
|
||||
local AUTH_KEYS="$SSH_DIR/authorized_keys"
|
||||
|
||||
mkdir -p "$SSH_DIR"
|
||||
chmod 700 "$SSH_DIR"
|
||||
chown "$USERNAME:$USERNAME" "$SSH_DIR"
|
||||
|
||||
echo "$PUBKEY_LINE" > "$AUTH_KEYS"
|
||||
chmod 600 "$AUTH_KEYS"
|
||||
chown "$USERNAME:$USERNAME" "$AUTH_KEYS"
|
||||
|
||||
ok "Installed public key to $AUTH_KEYS (owner: $USERNAME)"
|
||||
}
|
||||
|
||||
# Simple sudo verification
|
||||
verify_sudo() {
|
||||
local USERNAME="$1"
|
||||
if su - "$USERNAME" -c 'sudo -l' >/tmp/sudo_check 2>&1; then
|
||||
echo "Output of 'sudo -l' for $USERNAME:" >&2
|
||||
sed -n '1,200p' /tmp/sudo_check >&2 || true
|
||||
ok "Sudo appears configured for $USERNAME"
|
||||
else
|
||||
warn "Sudo check produced output (inspect below):" >&2
|
||||
sed -n '1,200p' /tmp/sudo_check >&2 || true
|
||||
warn "If problems, ensure $USERNAME is in $SUDO_GROUP or update /etc/sudoers with visudo." >&2
|
||||
fi
|
||||
rm -f /tmp/sudo_check
|
||||
}
|
||||
|
||||
# Delete user and cleanup
|
||||
delete_user() {
|
||||
local USERNAME="$1"
|
||||
if ! id "$USERNAME" &>/dev/null; then
|
||||
fail "User $USERNAME does not exist."
|
||||
return 1
|
||||
fi
|
||||
|
||||
read -rp "Are you sure you want to DELETE user '$USERNAME' and remove their home dir and saved keys? This is irreversible. [type 'yes' to confirm]: " CONF
|
||||
if [ "$CONF" != "yes" ]; then
|
||||
warn "Aborted deletion."
|
||||
return 2
|
||||
fi
|
||||
|
||||
step "Killing processes for $USERNAME"
|
||||
pkill -u "$USERNAME" || true
|
||||
ok "Killed processes (if any)."
|
||||
|
||||
step "Removing user and home directory"
|
||||
if userdel -r "$USERNAME" >/dev/null 2>&1; then
|
||||
ok "userdel -r succeeded for $USERNAME"
|
||||
else
|
||||
warn "userdel -r failed or partially failed; attempting manual cleanup of home directory"
|
||||
rm -rf "$(eval echo "~$USERNAME")" || true
|
||||
ok "Manual home cleanup attempted"
|
||||
fi
|
||||
|
||||
step "Cleaning created key folders for $USERNAME in $BASE_KEY_DIR"
|
||||
find "$BASE_KEY_DIR" -maxdepth 1 -type d -name "$USERNAME*" -exec rm -rf {} \; || true
|
||||
ok "Removed saved key directories matching $USERNAME* in $BASE_KEY_DIR"
|
||||
|
||||
ok "User $USERNAME deletion finished."
|
||||
return 0
|
||||
}
|
||||
|
||||
# MAIN MENU
|
||||
while true; do
|
||||
cat <<'MENU' >&2
|
||||
|
||||
=== USER MANAGEMENT MENU ===
|
||||
1) Create new sudo user AND auto-generate SSH keypair (private key saved for copying)
|
||||
2) Create new sudo user from an EXISTING public key (paste)
|
||||
3) Delete a user and remove their home + saved keys
|
||||
4) Show saved key directories (/root/created_user_keys)
|
||||
5) Exit
|
||||
MENU
|
||||
|
||||
read -rp "Choose an option [1-5]: " CHOICE
|
||||
|
||||
case "$CHOICE" in
|
||||
1)
|
||||
read -rp $'\nEnter the username to create (example: alice): ' NEWUSER
|
||||
NEWUSER="${NEWUSER:-}"
|
||||
if [ -z "$NEWUSER" ]; then fail "No username entered."; continue; fi
|
||||
|
||||
read -rp "Create user '$NEWUSER' and generate keypair? [y/N]: " CONF
|
||||
CONF=${CONF,,}
|
||||
if [[ "$CONF" != "y" && "$CONF" != "yes" ]]; then warn "Cancelled."; continue; fi
|
||||
|
||||
step "Creating user and setting up keys for $NEWUSER"
|
||||
if ! create_user_common "$NEWUSER"; then warn "User creation failed. Aborting."; continue; fi
|
||||
|
||||
# generate keys (capture only the path)
|
||||
KEY_DIR="$(generate_keypair "$NEWUSER")"
|
||||
# read public key
|
||||
PUBKEY_LINE="$(cat "$KEY_DIR/id_ed25519.pub" | tr -d '\r\n')"
|
||||
install_pubkey_for_user "$NEWUSER" "$PUBKEY_LINE"
|
||||
|
||||
read -rp "Lock local password for $NEWUSER (disallow password login for this account)? [y/N]: " LOCKCHOICE
|
||||
LOCKCHOICE=${LOCKCHOICE,,}
|
||||
if [[ "$LOCKCHOICE" == "y" || "$LOCKCHOICE" == "yes" ]]; then
|
||||
passwd -l "$NEWUSER" >/dev/null 2>&1 || true
|
||||
ok "Password locked for $NEWUSER (key-only)."
|
||||
else
|
||||
ok "Password not locked; you may set one with: sudo passwd $NEWUSER"
|
||||
fi
|
||||
|
||||
step "Verifying sudo for $NEWUSER"
|
||||
verify_sudo "$NEWUSER"
|
||||
|
||||
step "Result & next steps"
|
||||
echo " - Keys saved in: $KEY_DIR" >&2
|
||||
echo " - Files to copy to the user (deliver PRIVATE key securely):" >&2
|
||||
echo " $KEY_DIR/id_ed25519 (private - deliver securely)" >&2
|
||||
echo " $KEY_DIR/id_ed25519.pub (public - for records)" >&2
|
||||
echo " - Installed public key location on server:" >&2
|
||||
echo " /home/$NEWUSER/.ssh/authorized_keys" >&2
|
||||
echo "" >&2
|
||||
echo "Example: to copy private key to your workstation (run locally on workstation):" >&2
|
||||
echo " scp root@server:$KEY_DIR/id_ed25519 /local/path/" >&2
|
||||
ok "Creation complete for $NEWUSER."
|
||||
;;
|
||||
|
||||
2)
|
||||
read -rp $'\nEnter the username to create (example: bob): ' NEWUSER
|
||||
if [ -z "$NEWUSER" ]; then fail "No username entered."; continue; fi
|
||||
echo "Paste the PUBLIC SSH key (single line), then press Enter:" >&2
|
||||
read -r PKEY
|
||||
PKEY="${PKEY:-}"
|
||||
if [ -z "$PKEY" ]; then fail "No public key provided."; continue; fi
|
||||
|
||||
read -rp "Create user '$NEWUSER' and install pasted key? [y/N]: " CONF
|
||||
CONF=${CONF,,}
|
||||
if [[ "$CONF" != "y" && "$CONF" != "yes" ]]; then warn "Cancelled."; continue; fi
|
||||
|
||||
step "Creating user and installing provided public key"
|
||||
if ! create_user_common "$NEWUSER"; then warn "User creation failed. Aborting."; continue; fi
|
||||
|
||||
DATESTAMP="$(date '+%Y%m%d_%H%M%S')"
|
||||
KEY_DIR="$BASE_KEY_DIR/$NEWUSER-$DATESTAMP"
|
||||
mkdir -p "$KEY_DIR"
|
||||
echo "$PKEY" > "$KEY_DIR/from_user.pub"
|
||||
chmod 600 "$KEY_DIR/from_user.pub"
|
||||
ok "Saved provided public key to $KEY_DIR/from_user.pub"
|
||||
|
||||
install_pubkey_for_user "$NEWUSER" "$PKEY"
|
||||
|
||||
read -rp "Lock local password for $NEWUSER (disallow password login for this account)? [y/N]: " LOCKCHOICE
|
||||
LOCKCHOICE=${LOCKCHOICE,,}
|
||||
if [[ "$LOCKCHOICE" == "y" || "$LOCKCHOICE" == "yes" ]]; then
|
||||
passwd -l "$NEWUSER" >/dev/null 2>&1 || true
|
||||
ok "Password locked for $NEWUSER (key-only)."
|
||||
else
|
||||
ok "Password not locked; you may set one with: sudo passwd $NEWUSER"
|
||||
fi
|
||||
|
||||
step "Verifying sudo for $NEWUSER"
|
||||
verify_sudo "$NEWUSER"
|
||||
|
||||
step "Result & next steps"
|
||||
echo " - Stored provided public key: $KEY_DIR/from_user.pub" >&2
|
||||
ok "Creation complete for $NEWUSER."
|
||||
;;
|
||||
|
||||
3)
|
||||
read -rp $'\nEnter the username to DELETE: ' DELUSER
|
||||
if [ -z "$DELUSER" ]; then fail "No username entered."; continue; fi
|
||||
delete_user "$DELUSER" || { warn "Delete encountered problems or was aborted."; continue; }
|
||||
;;
|
||||
|
||||
4)
|
||||
step "Saved key directories:"
|
||||
if [ -d "$BASE_KEY_DIR" ]; then
|
||||
ls -la "$BASE_KEY_DIR" >&2 || true
|
||||
else
|
||||
echo "(no saved keys yet)" >&2
|
||||
fi
|
||||
echo "" >&2
|
||||
echo "To download a private key to your workstation, use scp. Example:" >&2
|
||||
echo " scp root@server:$BASE_KEY_DIR/username-YYYYMMDD_HHMMSS/id_ed25519 /local/path/" >&2
|
||||
;;
|
||||
|
||||
5)
|
||||
echo "Exiting." >&2
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*)
|
||||
warn "Invalid choice."
|
||||
;;
|
||||
esac
|
||||
|
||||
echo
|
||||
read -rp "Press Enter to return to menu..." dummy
|
||||
done
|
||||
Loading…
x
Reference in New Issue
Block a user