Skip to content

Instantly share code, notes, and snippets.

@icy
Last active June 6, 2018 13:52
Show Gist options
  • Save icy/36a728d8764fc5638a5d848bc025e150 to your computer and use it in GitHub Desktop.
Save icy/36a728d8764fc5638a5d848bc025e150 to your computer and use it in GitHub Desktop.
challenge6.sh
#!/usr/bin/env bash
# Purpose : Grant/Revoke SSH access
# Author : Ky-Anh Huynh
# License : MIT
# Date : 2018-May-20
_err() {
echo >&2 ":: $(date -u): ERR: ${FUNCNAME[1]:-$0}: $*"
return 1
}
_warn() {
echo >&2 ":: $(date -u): WARN: ${FUNCNAME[1]:-$0}: $*"
}
_download_github_keys() {
local _fuser
_fuser="${1:-}"
_check_username "$_fuser" || return 1
_warn "Attempt to download public SSH key from Github for user $_fuser"
curl -Lso- "https://github.com/$_fuser.keys" \
| awk '
BEGIN {
error = 0
}
{
printf("<github key> %s\n", $0) > "/dev/stderr"
if ($0 ~ /Not Found/) {
error = 1
}
else {
print
}
}
END {
if (error == 1) {
exit(1)
}
}
'
}
_create_user() {
local _fuser
_fuser="${1:-}"
_check_username "$_fuser" || return 1
useradd "$_fuser"
mkdir -pv "/home/$_fuser/.ssh/"
chown "$_fuser" "/home/$_fuser/" "/home/$_fuser/.ssh/"
chmod 700 "/home/$_fuser/" "/home/$_fuser/.ssh/"
usermod -s /bin/bash "$_fuser"
usermod -d "/home/$_fuser/" "$_fuser"
_download_github_keys "$_fuser" \
> "/home/$_fuser/.ssh/authorized_keys"
}
_revoke_user() {
local _fuser=
local _fkey=
_fuser="${1:-1}"
_fkey="/home/${_fuser}/.ssh/authorized_keys"
_check_username "$_fuser" || return 1
usermod "$_fuser" -s /bin/true
if [[ -f "$_fkey" ]]; then
mv -fv "$_fkey" "$_fkey.revoked.$(date -u "+%Y%m%d-%H%M%S")"
else
_warn "File not found '$_fkey'"
fi
if [[ -f "$_fkey" ]]; then
_err "Unable to revoke '$_fkey'"
else
:
fi
}
_check_username() {
if [[ -z "${1:-}" ]]; then
_err "Missing user information as the first argument."
return 1
fi
case "${1:-}" in
"root"|"ubuntu"|"admin")
_err "Are you shooting yourself in the foot?"
return 1
;;
esac
echo "${1:-}" | grep -Eqs -e ' +'
# shellcheck disable=2181
if [[ $? -eq 0 ]]; then
_err "Unable to have space in username '${1:-}'."
return 1
else
:
fi
}
_main() {
set -u
_warn "This is ${FUNCNAME[*]} running as user = $(id -un)"
if [[ "$(id -un)" != "root" ]]; then
_warn "Switching to root environment thanks to sudo"
_script_contents \
| sudo -H \
"USERNAME=$USERNAME" \
"ACTION=$ACTION" \
bash -s
exit
fi
_check_username "$USERNAME" || return 1
_warn "Running script as root account. USERNAME=$USERNAME, ACTION=$ACTION"
case "$ACTION" in
"grant") _create_user "$USERNAME" ;;
"revoke") _revoke_user "$USERNAME" ;;
*) _err "Unknown action '$ACTION'" ;;
esac
}
_script_contents() {
declare -f _err
declare -f _warn
declare -f _create_user
declare -f _download_github_keys
declare -f _revoke_user
declare -f _script_contents
declare -f _check_username
declare -f _main
echo "export USERNAME=$USERNAME"
echo "export ACTION=$ACTION"
echo "_main"
}
_help() {
cat 2>&1 <<-'EOF'
challenge6.sh -- Grant or Revoke ssh user on Linux servers
Syntax:
challenge6.sh username host1 [host2...]
challenge6.sh +username host1 [host2...]
challenge6.sh -username host1 [host2...]
Given a Github `username` and a list of hosts, the script will create
new shell account or revoke them from the Linux servers. When `username`
is prefixed with a plug sign (`-`), the `revoke` action is instructed.
Public SSH key is fetched from public Github service, e.g.,
https://github.com/username.keys
For `revoke` action, the `authorized_keys` file is renamed, and the user's
shell is changed to `/usr/bin/true`.
NOTES:
* If there is a running programs on system, revoke action may not be able
to update user's shell.
* The script will not continue if the input user is `root`, `ubuntu` or `admin`
* The script requires `sudo` on remote machine to create/revoke user.
TODO:
* Logging support
* Dry-run mode support
EOF
}
# Print help message for details
case "x${1:-}" in
"x") _err "Please try -h or --help for details" ; exit ;;
"x-h"|"x--help") _help ; exit ;;
esac
# $0 user host_1 host_2 host_3...
USERNAME="${1:-}"; shift
if [[ "${USERNAME:0:1}" == "+" ]]; then
USERNAME="${USERNAME:1}"
fi
if [[ "${USERNAME:0:1}" == "-" ]]; then
ACTION="revoke"
USERNAME="${USERNAME:1}"
else
ACTION="grant"
fi
export ACTION
export USERNAME
_check_username "$USERNAME" || exit 1
while (( $# )); do
HOST="${1:-}"; shift
_warn "Attempt to $ACTION user '$USERNAME' on $HOST"
ssh "$HOST" bash -s < <(_script_contents)
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment