#!/usr/bin/env bash # █▀▀ █▀█ █▀▀ █▀█ ▀ # █▄█ █▄█ █▄█ █▄█ ▄ # -- -- -- -- -- -- # INIT GLOBAL VARIABLES: _VERSION="0.1.0" _SCRIPT_NAME="$(basename $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 "${script} --init | init config file \n" printf "${script} --crt | get ssh certificate for go3 connections \n" printf " \n" printf "${script} --bill my.example.com \n" printf "${script} --vm 0.0.0.0 --ssh | only ssh access \n" printf "${script} --vm 0.0.0.0 --tty | use mgrctl interactive \n" printf " \n" printf "${script} --dci 0.0.0.0 --mgrctl user access --id 3 --count 5 \n" printf "${script} --dci 0.0.0.0 --mgrctl user ls --admins \n" printf "${script} --dci 0.0.0.0 --mgrctl user --help \n" printf "${script} --vm 0.0.0.0 --port 22122 --mgrctl user ls --admins \n" printf "${script} --vm 0.0.0.0 --tty --mgrctl user ls --admins \n" printf "${script} --dns ns1.example.com --web-port 1501 \n" printf "${script} --dns ns1.example.com --port 22122 --web-port 1501 \n" printf "${script} --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 " --ssh open only ssh session \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 "" echo "${success} Config file was created, run ${script_name} again" echo "" } # 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 # run init config if flag --init and exit: if [[ "$1" == "--init" ]]; then init_config exit 0 fi # load config from config file: load_config # 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 ;; --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() { optparser $@ get_access } # RUN IT: main $@