diff --git a/scripts/gogo/gogo.sh b/scripts/gogo/gogo.sh new file mode 100755 index 0000000..3df5abd --- /dev/null +++ b/scripts/gogo/gogo.sh @@ -0,0 +1,466 @@ +#!/usr/bin/env bash + +# █▀▀ █▀█ █▀▀ █▀█ ▀ +# █▄█ █▄█ █▄█ █▄█ ▄ +# -- -- -- -- -- -- + +# INIT GLOBAL VARIABLES: +_VERSION="0.1.0" +_SCRIPT_NAME="$0" +_GO_CMD="go3" +_DEBUG_MODE=false + +_CONFIG_DIR="${HOME}/.config/gogo" +_CONFIG="${_CONFIG_DIR}/gogo.conf" + +_IS_TTY=false +_IS_SSH_ONLY=false +_IS_MGRCTL_ARGS=false +_MGRCTL_ARGS="" +_MGRCTL_BIN="mgrctl" +_MGRCTL_CMD="" +_MGRCTL_RUN="" +_MGRCTL_KEY="" + +_PLATFORM_TYPE="" +_PLATFORM_GENERATION=6 +_PLATFORM_SSH_PORT=22 +_PLATFORM_WEB_PORT=443 +_PLATFORM_IP_ADDR="" +_PLATFORM_CONFIG_FILE="" +_PLATFORM_NETWORK_NAME="" + +_SSH_CONNECT_CMD="" +_SSH_REMOTE_CMD="" + +_ACCESS_LINK="" + + +# Colorize output +# Usage - $(colorize CYAN "Hello, friend!") +colorize() { + local RED="\033[0;31m" + local GREEN="\033[0;32m" # <-- [0 means not bold + local YELLOW="\033[1;33m" # <-- [1 means bold + local BLUE="\033[0;34m" + local MAGNETA="\033[0;35" + local CYAN="\033[1;36m" + # ... Add more colors if you like + + local NC="\033[0m" # No Color + + # printf "${(P)1}${2} ${NC}\n" # <-- zsh + # printf "${!1}${2} ${NC}\n" # <-- bash + echo -e "${!1}${2}${NC}" # <-- all-purpose +} + + +# Print help message how used it script +help() { + # colorize value + local script=$(colorize GREEN "$_SCRIPT_NAME") + local required=$(colorize RED "required") + # help message + printf "Usage: $script [options [parameters]] \n" + printf " \n" + printf "Examples: \n" + printf " \n" + printf "./gogo.sh --init | init config file \n" + printf "./gogo.sh --crt | get ssh certificate for go3 connections \n" + printf " \n" + printf "./gogo.sh --bill my.example.com \n" + printf "./gogo.sh --vm 0.0.0.0 --ssh | only ssh access \n" + printf "./gogo.sh --vm 0.0.0.0 --tty | use mgrctl interactive \n" + printf " \n" + printf "./gogo.sh --dci 0.0.0.0 --mgrctl user access --id 3 --count 5 \n" + printf "./gogo.sh --dci 0.0.0.0 --mgrctl user ls --admins \n" + printf "./gogo.sh --dci 0.0.0.0 --mgrctl user --help \n" + printf "./gogo.sh --vm 0.0.0.0 --port 22122 --mgrctl user ls --admins \n" + printf "./gogo.sh --dns ns1.example.com --web-port 1501 \n" + printf "./gogo.sh --dns ns1.example.com --port 22122 --web-port 1501 \n" + printf "./gogo.sh --bill my.example.com --port 22 --web-port 1501 \n" + printf " \n" + printf "Options: \n" + printf " \n" + printf " --vm[dci|bill|dns|ip] expected ip_addr $required \n" + printf " --port | -p ssh port, default 22 \n" + printf " --web-port | -wp web port, default 443 \n" + printf " --go/--go3 go version, default go3 \n" + printf " --tty for vm6/dci6 echo cmd for run container\n" + printf " --mgrctl [args] for vm6/dci6 customize access params \n" + printf " \n" + printf " --init | -i generate configuration \n" + printf " --crt | -c generate ssh cert \n" + printf " --version | -v print version \n" + printf " --help | -h print this message and exit \n" +} + +# Ask confirmation user if No - exit with 1 state +continue_handler() { + read -p "Continue? (Y/N): " confirm \ + && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1 +} + +# Init script configuration file: +init_config() { + # Lables: + local warning=$(colorize RED "WARNING! ") + local success=$(colorize GREEN "SUCCESS! ") + local script_name=$(colorize GREEN "${_SCRIPT_NAME}") + # check if config file exists: + if [ -f $_CONFIG ]; then + echo "${warning}: Config file is already exists" + echo "New initialization rewrites current config" + continue_handler + fi + # get user unputs: + read -p "Enter go server address: " _GO_SERVER_ADDR + read -p "Enter vault server address: " _VAULT_SERVER_ADDR + read -p "Enter username: " _SSH_PRIVATE_KEY_USER + read -p "Enter full path to ssh private key: " _SSH_PRIVATE_KEY_PATH + read -p "Enter full path to ssh public key: " _SSH_PUBLIC_KEY_PATH + read -p "Enter full path to ssh certificate: " _SSH_CRT_FILE + read -p "Enter mgrctl image name: " _MGRCTL_IMAGE + # save config: + mkdir -p $_CONFIG_DIR + cat << EOF > "${_CONFIG}" +GO_SERVER_ADDR=$_GO_SERVER_ADDR +VAULT_SERVER_ADDR=$_VAULT_SERVER_ADDR +SSH_PRIVATE_KEY_USER=$_SSH_PRIVATE_KEY_USER +SSH_PRIVATE_KEY_PATH=$_SSH_PRIVATE_KEY_PATH +SSH_PUBLIC_KEY_PATH=$_SSH_PUBLIC_KEY_PATH +SSH_CRT_FILE=$_SSH_CRT_FILE +MGRCTL_IMAGE=$_MGRCTL_IMAGE +DEBUG_MODE=false +EOF + echo "${success}: Config file was created, run ${script_name} again" +} + + +# Read config file that contains key=value params +load_config() { + local file="$_CONFIG" + + if ! [ -f $_CONFIG ]; then + help + local warning=$(colorize RED "WARNING!") + echo "" + echo "${warning} Config file doesn't exist" + echo "Init new config: ${_CONFIG}" + continue_handler + init_config + fi + + while IFS="=" read -r key value; do + case "$key" in + "GO_SERVER_ADDR") + _GO_SERVER_ADDR="$value" + ;; + "VAULT_SERVER_ADDR") + _VAULT_SERVER_ADDR="$value" + ;; + "SSH_PRIVATE_KEY_USER") + _SSH_PRIVATE_KEY_USER="$value" + ;; + "SSH_PRIVATE_KEY_PATH") + _SSH_PRIVATE_KEY_PATH="$value" + ;; + "SSH_PUBLIC_KEY_PATH") + _SSH_PUBLIC_KEY_PATH="$value" + _VAULT_SSH_PUBLIC_KEY="@$value" # @ sybol is important + ;; + "SSH_CRT_FILE") + _SSH_CRT_FILE="$value" + ;; + "MGRCTL_IMAGE") + _MGRCTL_IMAGE="$value" + ;; + "DEBUG_MODE") + _DEBUG_MODE="$value" + ;; + esac + done < "$file" +} + +# Generate key for coremgr based platrorms access link: +gen_random_key() { + _MGRCTL_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) +} + + +gen_coremgr_access_params() { + # get opt name: + local opt=$1 + # gen access key: + gen_random_key + # fill current parametrs: + _PLATFORM_TYPE=$(sed 's~[^[:alpha:]/]\+~~g' <<< "$opt") + _PLATFORM_GENERATION=5 + _MGRCTL_BIN="/usr/local/mgr5/sbin/mgrctl" + _MGRCTL_ARGS="-m ${_PLATFORM_TYPE}mgr session.newkey key=$_MGRCTL_KEY" + + # override _PLATFORM_GENERATION for bill6 or dns6 + if [[ $opt == "--bill" ]] || [[ $opt == "--dns" ]]; then + _PLATFORM_GENERATION=6 + fi + # override _MGRCTL_BIN _MGRCTL_ARGS for dns6 + if [[ $opt == "--dns" ]]; then + _MGRCTL_BIN="/opt/ispsystem/${_PLATFORM_TYPE}manager6/sbin/mgrctl" + _MGRCTL_ARGS="-m ${_PLATFORM_TYPE}mgr session.newkey key=$_MGRCTL_KEY" + fi +} + + +gen_docker_access_params(){ + # get opt name: + local opt=$1 + # fill current parametrs: + _PLATFORM_TYPE=$(sed 's~[^[:alpha:]/]\+~~g' <<< "$opt") + _PLATFORM_GENERATION=6 + _PLATFORM_CONFIG_FILE="/opt/ispsystem/${_PLATFORM_TYPE}/config.json" + # set platform docker network name: + if [[ $_PLATFORM_TYPE == "vm" ]]; then + _PLATFORM_NETWORK_NAME="vm_vm_box_net" + else + _PLATFORM_NETWORK_NAME="dci_auth" + fi +} + + +gen_ssh_connect_cmd(){ + # get params: + local go_server="${_GO_SERVER_ADDR}" + local go_cmd="${_GO_CMD}" + local address="${_PLATFORM_IP_ADDR}" + local port="${_PLATFORM_SSH_PORT}" + local key_path="${_SSH_PRIVATE_KEY_PATH}" + local key_user="${_SSH_PRIVATE_KEY_USER}" + local ssh_args="${key_user}@${go_server} ${go_cmd} ${address} -p ${port}" + # generate cmd: + _SSH_CONNECT_CMD="ssh -A -t -i ${key_path} ${ssh_args}" +} + + +gen_ssh_remote_cmd() { + # ? VMmanager6 || DCImanager6: + if [[ $_PLATFORM_TYPE == "vm" ]] || \ + [[ $_PLATFORM_TYPE == "dci" ]] && \ + [[ $_PLATFORM_GENERATION -eq 6 ]]; then + # use default mgrctl cmd if not set args: + if [ -z "${_MGRCTL_ARGS}" ]; then + _MGRCTL_ARGS="${_PLATFORM_TYPE}6 auth user access --random" + _MGRCTL_CMD="${_MGRCTL_BIN} ${_MGRCTL_ARGS}" + else + _MGRCTL_CMD="${_MGRCTL_BIN} ${_PLATFORM_TYPE}6 ${_MGRCTL_ARGS}" + fi + # silent mode: + local hide_output=">> /dev/null" + if $_DEBUG_MODE; then + hide_output="" + fi + # image: + local image=${_MGRCTL_IMAGE} + # docker cmd: + local docker_bin="/usr/bin/docker" + local docker_pull="${docker_bin} pull ${image} ${hide_output}" + local docker_rm="${docker_bin} image rm -f ${image} ${hide_output}" + local docker_run="${docker_bin} run" + # mount config: + local mount_src="source=${_PLATFORM_CONFIG_FILE}" + local mount_trg="target=${_PLATFORM_CONFIG_FILE}" + local mount_opt="type=bind,${mount_src},${mount_trg},readonly" + local mount="--mount ${mount_opt}" + # network config: + local network="--network=${_PLATFORM_NETWORK_NAME}" + # environment config: + local envs="-e PLATFORM_TYPE=${_PLATFORM_TYPE}" + # container args: + local args="${_MGRCTL_CMD}" + # mgrctl container params: + local container="${network} ${mount} ${envs} --rm ${image} ${args}" + # docker commands: + local cmd="${docker_pull} && ${docker_run} ${container} && ${docker_rm}" + # final cmd: + _SSH_REMOTE_CMD="${cmd}" + # set cmd for manual start container: + if $_IS_TTY; then + # override parammetrs if DEBUG_MODE=false add -it flag: + docker_pull="${docker_bin} pull ${image}" + docker_rm="${docker_bin} image rm -f ${image}" + container="${network} ${mount} ${envs} --rm -i -t ${image}" + cmd="${docker_pull} && ${docker_run} ${container} && ${docker_rm}" + _MGRCTL_RUN="${cmd}" + fi + # ? BILLmanager6 || DNSmanager6 || IP/DNS/DCI/VMmanager5: + else + # final cmd: + _SSH_REMOTE_CMD="${_MGRCTL_BIN} ${_MGRCTL_ARGS}" + echo_access_link + fi +} + + +gen_access_link() { + local url="https://${_PLATFORM_IP_ADDR}" + local port="${_PLATFORM_WEB_PORT}" + local platform="${_PLATFORM_TYPE}mgr" + local func="func=auth&key=${_MGRCTL_KEY}" + _ACCESS_LINK="${url}:${port}/${platform}?${func}" +} + + +echo_access_link() { + gen_access_link + echo "mgr link" + echo "----- -------------------------------------------------------------" + echo "${_PLATFORM_TYPE}${_PLATFORM_GENERATION} ${_ACCESS_LINK}" + echo "" +} + +echo_mgrctl_run_msg() { + echo "--------------------------------------------------------------------" + echo "To run the mgrctl container manually on the client server:" + echo "copy and paste the command into the terminal." + echo "This will download the image and run the container interactively." + echo "After exiting the container and its image will be deleted." + echo "--------------------------------------------------------------------" + echo "${_MGRCTL_RUN}" + echo "--------------------------------------------------------------------" +} + + +get_access() { + gen_ssh_connect_cmd + if $_IS_SSH_ONLY; then + # run connection: + $_SSH_CONNECT_CMD + else + gen_ssh_remote_cmd + # run connection send remote cmd: + $_SSH_CONNECT_CMD "${_SSH_REMOTE_CMD}" + if [[ $_PLATFORM_TYPE == "vm" ]] || \ + [[ $_PLATFORM_TYPE == "dci" ]] && \ + [[ $_PLATFORM_GENERATION -eq 6 ]] && \ + $_IS_TTY; then + echo_mgrctl_run_msg + fi + # use default mgrctl cmd if not set args: + # run connection again for ssh tty session: + $_SSH_CONNECT_CMD + fi +} + + +get_vault_crt() { + local public_key=$1 + local crt_file=$2 + vault login -method=oidc + if [ ! -f $crt_file ]; then + touch $crt_file + fi + vault write -field=signed_key ssh/sign/support \ + public_key=$public_key valid_principals=root > $crt_file +} + + +set_ssh_agent() { + local secret_key=$1 + ssh-add -D + ssh-add $secret_key +} + + +renewal_crt() { + export VAULT_ADDR=$_VAULT_SERVER_ADDR + get_vault_crt $_VAULT_SSH_PUBLIC_KEY $_SSH_CRT_FILE + set_ssh_agent $SSH_PRIVATE_KEY_PATH +} + + +# Parse user options +optparser() { + # count user-passed options: + local count_options=$# + # run help if empty and exit: + if [[ count_options -eq 0 ]]; then + help + exit 2 + fi + # parse opts: + while [ ! -z "$1" ]; do + case "$1" in + --vm|--dci) + gen_docker_access_params "$1" + shift + _PLATFORM_IP_ADDR="$1" + ;; + --bill|--dns|--bill5|--ip5|--dns5|--vm5|--dci5) + gen_coremgr_access_params "$1" + shift + _PLATFORM_IP_ADDR="$1" + ;; + --port|-p) + shift + _PLATFORM_SSH_PORT="$1" + ;; + --web-port|-wp) + shift + _PLATFORM_WEB_PORT="$1" + ;; + --go|--go3) + _GO_CMD=$(sed 's~[^[:alnum:]/]\+~~g' <<< "$1") + ;; + --mgrctl|--tty|--ssh) + if [[ "$1" == "--mgrctl" ]]; then + _IS_MGRCTL_ARGS=true + shift + _MGRCTL_ARGS=$@ + elif [[ "$1" == "--tty" ]]; then + if $_IS_MGRCTL_ARGS; then + local error=$(colorize RED "ERROR!") + echo "${error} $1 must be in before --mgrctl not after" + exit 1 + fi + _IS_TTY=true + elif [[ "$1" == "--ssh" ]]; then + _IS_SSH_ONLY=true + fi + ;; + --init|-i) + init_config + exit 0 + ;; + --crt|-c) + renewal_crt + exit 0 + ;; + --help|-h) + help + exit 0 + ;; + --version|-v) + printf "$_VERSION\n" + exit 0 + ;; + *) + if ! $_IS_MGRCTL_ARGS; then + help + exit 1 + fi + ;; + esac + shift + done +} + + +# Entrypoint: +main() { + load_config + optparser $@ + get_access +} + + +# RUN IT: +main $@