Permit pre-existing keypair to be used for remote user creation

This commit is contained in:
Price Hiller 2021-10-11 20:59:21 -05:00
parent 0dd6a2a744
commit 7f21d2b22f

View File

@ -137,30 +137,52 @@ usage() {
Example: Example:
--user User1") --user User1")
$(arg_required "-H") <hostName: string> | $(arg_required "--host-name") <hostName: string> $(arg_required "-H") <hostName: string> | $(arg_required "--host-name") <hostName: string>
$(arg_description \ $(arg_description \
"The SSH hostname for the given host, MUST exist within your ssh configuration; typically located at ~/.ssh/config "The SSH hostname for the given host, MUST exist within your ssh configuration; typically located at ~/.ssh/config
Example: Example:
--host-name gitlab.orion-technologies.io") --host-name gitlab.orion-technologies.io")
$(arg_optional "-L") <loginUser: string> | $(arg_optional "--login-user") <loginUser: string> $(arg_optional "-L") <loginUser: string> | $(arg_optional "--login-user") <loginUser: string>
$(arg_description \ $(arg_description \
"The user used to login to your host, must be a privileged sudo user. Default user is root. "The user used to login to your host, must be a privileged sudo user. Default user is root.
Example: Example:
--login-user Admin") --login-user Admin")
$(arg_optional "-K") <keyType: string> | $(arg_optional "--key-type") <keyType: string> $(arg_optional "-K") <keyType: string> | $(arg_optional "--key-type") <keyType: string>
$(arg_description \ $(arg_description \
"The SSH key type to generate, passed to ssh-keygen's -t flag. "The SSH key type to generate, passed to ssh-keygen's -t flag.
Example: Example:
--key-type rsa") --key-type rsa")
$(arg_optional "-B") <keyBits: int> | $(arg_optional "--bits") <keyBits: int> $(arg_optional "-B") <keyBits: int> | $(arg_optional "--bits") <keyBits: int>
$(arg_description \ $(arg_description \
"The number of bits used to generate the given key, default is set at 512. "The number of bits used to generate the given key, default is set at 512.
Example: Example:
--bits 2048")" --bits 2048")
$(arg_optional "-E") <existingPrivateKey: file> | $(arg_optional "--existing-key") <existingPrivateKey: file>
$(arg_description \
"An existing private key that will be used to login the remote server. An important note, if the --pub-key option
is not passed then this will default to looking for the private key file name concatenated with .pub -- for example:
given a private-key file named id_rsa, by default this will look for id_rsa.pub in the same directory; this
behavior can be overwritten with the --pub-key option below.
Example:
--existing-key ~/.ssh/id_rsa")
$(arg_optional "-P") <existingPublicKey: file> | $(arg_optional "--pub-key") <existingPublicKey: file>
$(arg_description \
"An existing public key that will be sent to the remote server's authorized_hosts file.
Depends upon the --existing-key option being passed.
Example:
--public-key ~/.ssh/id_rsa.pub")"
} }
@ -169,6 +191,8 @@ ssh_host_name=""
ssh_key_type="ed25519" ssh_key_type="ed25519"
ssh_key_bits=512 ssh_key_bits=512
ssh_login_user="root" ssh_login_user="root"
existing_ssh_key=""
existing_pub_key=""
parse_args() { parse_args() {
# Parse input arguments # Parse input arguments
@ -199,6 +223,28 @@ parse_args() {
log "error" "No argument provided for ${1}" && log "error" "No argument provided for ${1}" &&
exit 1 exit 1
;; ;;
-E | --existing-key)
existing_ssh_key="${2}"
[[ ! -f "${existing_ssh_key}" ]] &&
log "error" "Given file, ${existing_ssh_key}, does not exist or is not a file!" &&
exit 1
local first_line
first_line="$(head -n 1 "${existing_ssh_key}")"
# Remove case sensitivity from string matching
shopt -s nocasematch
if [[ ! "${first_line}" = *"OPENSSH PRIVATE KEY"* ]]; then
log "warning" "Given key, ${existing_ssh_key}, could not be determined to be an OpenSSH Private Key!"
sleep 5
fi
shopt -u nocasematch
;;
-P | --pub-key)
existing_pub_key="${2}"
[[ ! -f "${existing_pub_key}" ]] &&
log "error" "Given file, ${existing_pub_key}, does not exist or is not a file!" &&
exit 1
;;
-K | --key-type) -K | --key-type)
ssh_key_type="${2}" ssh_key_type="${2}"
[[ -z "${ssh_key_type}" ]] && [[ -z "${ssh_key_type}" ]] &&
@ -238,8 +284,27 @@ parse_args() {
done done
} }
### ENTRY POINT ###
parse_args "$@" parse_args "$@"
### ENTRY POINT ###
### NON-BOILERPLATE FUNCTIONS ###
rollback_ssh() {
if [[ -z "${existing_ssh_key}" ]]; then
log "info" "Deleting generated SSH keypair"
rm "${SSH_KEY_FILE}"{,.pub}
fi
log "info" "Restoring old SSH Config from ${SSH_BACKUP_FILE}"
mv "${SSH_BACKUP_FILE}" "${SSH_CONFIG_FILE}"
}
### PRIMARY LOGIC ###
[[ -z "${ssh_user_to_create}" ]] && [[ -z "${ssh_user_to_create}" ]] &&
log "error" "User may not be empty" && log "error" "User may not be empty" &&
exit 1 exit 1
@ -248,41 +313,46 @@ parse_args "$@"
log "error" "--host-name may not be empty" && log "error" "--host-name may not be empty" &&
exit 1 exit 1
SSH_KEY_DIRECTORY="${HOME}/.ssh/keys/${ssh_host_name}/"
log "info" "Creating directory ${SSH_KEY_DIRECTORY} for the ssh key if it doesn't exist" if [[ -z "${existing_ssh_key}" ]]; then
mkdir -p "${SSH_KEY_DIRECTORY}" > /dev/null log "info" "Existing key not given, generating a new keypair"
SSH_KEY_DIRECTORY="${HOME}/.ssh/keys/${ssh_host_name}/"
SSH_KEY_FILE="${SSH_KEY_DIRECTORY}/${ssh_user_to_create}-id_${ssh_key_type}" log "info" "Creating directory ${SSH_KEY_DIRECTORY} for the ssh key if it doesn't exist"
mkdir -p "${SSH_KEY_DIRECTORY}" > /dev/null
[[ -f "${SSH_KEY_FILE}" ]] && SSH_KEY_FILE="${SSH_KEY_DIRECTORY}/${ssh_user_to_create}-id_${ssh_key_type}"
log "error" "${SSH_KEY_FILE} already exists! This may lead to major errors, check your SSH configuration and remove the SSH entry as well as the SSH key file or create a different user if you wish to continue." &&
exit 1
log "info" "Generating SSH key file for ${ssh_user_to_create}@${ssh_host_name} at ${SSH_KEY_FILE}" [[ -f "${SSH_KEY_FILE}" ]] &&
ssh-keygen -b 512 -t ed25519 -f "${SSH_KEY_FILE}" -N "" > /dev/null || exit "${?}" log "error" "${SSH_KEY_FILE} already exists! This may lead to major errors, check your SSH configuration and remove the SSH entry as well as the SSH key file or create a different user if you wish to continue." &&
chmod 600 "${SSH_KEY_FILE}" > /dev/null exit 1
log "info" "SSH key successfully created"
PUB_KEY_CONTENTS="$(cat "${SSH_KEY_FILE}.pub")" ssh-keygen -t "${ssh_key_type}" -b "${ssh_key_bits}" -N "" -f "${SSH_KEY_FILE}" > /dev/null
log "info" "Generated a private key file located at ${SSH_KEY_FILE}"
log "info" "Logging into remote server as ${ssh_login_user}@${ssh_host_name} to create ${ssh_user_to_create} and directories" else
ssh "${ssh_login_user}"@"${ssh_host_name}" > /dev/null <<__EOF__ log "info" "An existing SSH key was given, skipping generation of a keypair"
sudo useradd ${ssh_user_to_create} SSH_KEY_DIRECTORY="$(dirname "${existing_ssh_key}")"
mkdir -p /home/${ssh_user_to_create}/.ssh SSH_KEY_FILE="${existing_ssh_key}"
echo ${PUB_KEY_CONTENTS} >> /home/${ssh_user_to_create}/.ssh/authorized_keys log "info" "SSH key given: ${existing_ssh_key}"
chown -R ${ssh_user_to_create}:${ssh_user_to_create} /home/${ssh_user_to_create}/.ssh
__EOF__
if [[ "${?}" -ne "0" ]]; then
log "error" "Unable to login to remote server with ${ssh_login_user}@${ssh_host_name}"
log "error" "Verify the correct user and host name have been provided and that an SSH configuration exists for the pair in your SSH configuration"
rm "${SSH_KEY_FILE}"
exit 1
fi fi
if [[ -z "${existing_pub_key}" ]]; then
log "info" "A public key was not given, attempting an automatic public key lookup..."
[[ ! -f "${SSH_KEY_FILE}.pub" ]] &&
log "error" "Unable to find the corresponding public key for ${SSH_KEY_FILE}, should be ${SSH_KEY_FILE}.pub, if you intend to use a different public key pass the --pub-key option" &&
exit 1
PUB_KEY_CONTENTS="$(cat "${SSH_KEY_FILE}.pub")" || exit 1
log "info" "Found a public key: ${SSH_KEY_FILE}.pub"
else
log "info" "A public key was given, using ${existing_pub_key} for public key"
PUB_KEY_CONTENTS="$(cat "${existing_pub_key}")" || exit 1
fi
log "debug" "Pub key contents: ${PUB_KEY_CONTENTS}"
SSH_CONFIG_FILE="${HOME}/.ssh/config" SSH_CONFIG_FILE="${HOME}/.ssh/config"
log "info" "Finished creating ${ssh_user_to_create}, generating ssh configuration for ${SSH_CONFIG_FILE}" log "info" "Generating ssh configuration for ${SSH_CONFIG_FILE}"
SPACE_PADDING=" " SPACE_PADDING=" "
SSH_LINES_TO_ADD="${SPACE_PADDING}Match user ${ssh_user_to_create} host ${ssh_host_name} SSH_LINES_TO_ADD="${SPACE_PADDING}Match user ${ssh_user_to_create} host ${ssh_host_name}
@ -300,6 +370,7 @@ log "info" "Searching for a Host entry for ${ssh_host_name} within ${SSH_CONFIG_
# Remove case sensitivity from string matching # Remove case sensitivity from string matching
shopt -s nocasematch shopt -s nocasematch
wrote_new_data=0
should_write=0 should_write=0
while IFS= read -r line; do while IFS= read -r line; do
printf "%s\n" "${line}" printf "%s\n" "${line}"
@ -308,8 +379,48 @@ while IFS= read -r line; do
fi fi
if [[ "${should_write}" -eq "1" ]]; then if [[ "${should_write}" -eq "1" ]]; then
printf "%s\n" "${SSH_LINES_TO_ADD}" printf "%s\n" "${SSH_LINES_TO_ADD}"
wrote_new_data=1
should_write=0 should_write=0
fi fi
done < "${SSH_CONFIG_FILE}" > "ssh_conf.temp" && mv "ssh_conf.temp" "${SSH_CONFIG_FILE}" done < "${SSH_CONFIG_FILE}" > "ssh_conf.temp" && mv "ssh_conf.temp" "${SSH_CONFIG_FILE}"
log "info" "Successfully wrote the new SSH configuration, login with ${ssh_user_to_create}@${ssh_host_name}" cat "${SSH_CONFIG_FILE}"
shopt -u nocasematch
if [[ "${wrote_new_data}" -eq "1" ]]; then
log "info" "Successfully wrote the new SSH configuration, login with ${ssh_user_to_create}@${ssh_host_name}"
else
log "error" "Failed to write to ${SSH_CONFIG_FILE} -- Most likely cause is a missing HostName for ${ssh_host_name}"
rollback_ssh
exit 1
fi
log "info" "Logging into remote server as ${ssh_login_user}@${ssh_host_name} to create ${ssh_user_to_create} and directories"
log "info" "Verifying that user has sudo permissions"
ssh "${ssh_login_user}"@"${ssh_host_name}" sudo -v
SSH_RESULT="${?}"
if [[ "${SSH_RESULT}" -ne "0" ]]; then
log "error" "Unable to login to remote server with ${ssh_login_user}@${ssh_host_name}, received error code "${SSH_RESULT}
log "error" "Verify the correct user and host name have been provided and that an SSH configuration exists for the pair in your SSH configuration"
rollback_ssh
exit "${SSH_RESULT}"
fi
log "info" "User ${ssh_login_user} has sudo permissions, beginning the creation of user ${ssh_user_to_create} and installing the public key for login"
ssh "${ssh_login_user}"@"${ssh_host_name}" > /dev/null << __EOF__
sudo useradd ${ssh_user_to_create}
sudo mkdir -p /home/${ssh_user_to_create}/.ssh
echo ${PUB_KEY_CONTENTS} | sudo tee -a /home/${ssh_user_to_create}/.ssh/authorized_keys
sudo chown -R ${ssh_user_to_create}:${ssh_user_to_create} /home/${ssh_user_to_create}/.ssh
__EOF__
SSH_RESULT="${?}"
if [[ "${SSH_RESULT}" -ne "0" ]]; then
log "error" "Second set of SSH commands were unable to execute, ssh returned status code ${SSH_RESULT}"
exit "${SSH_RESULT}"
fi