Files
wx/wx
T
2026-10-05 00:19:40 +03:00

1413 lines
34 KiB
Bash
Executable File

#!/bin/bash
if [ ! "$BASH_VERSION" ] ; then
echo "Warén Group / Infra / CLI"
echo "This command requires using BASH shell."
exit 1
fi
if [[ -L "$0" ]]
then
PWD=$(dirname -- "$(readlink -f -- "$0")")
fi
wxi-args(){
declare -gAx args
args=()
while [[ $# -gt 0 ]]; do
case "$1" in
--*=*)
key="${1%%=*}"
value="${1#*=}"
args["${key#--}"]="$value"
shift
;;
--*)
key="$1"
opt="${key#--}"
shift
if [[ $# -gt 0 && "${1}" != -* ]]; then
args["$opt"]="$1"
shift
else
args["$opt"]=true
fi
;;
-*=*)
key="${1%%=*}"
value="${1#*=}"
args["${key#-}"]="$value"
shift
;;
-*)
key="$1"
opt="${key#-}"
shift
if [[ $# -gt 0 && "${1}" != -* ]]; then
args["$opt"]="$1"
shift
else
args["$opt"]=true
fi
;;
*)
args["$((++pos))"]="${1%%=*}"
shift
;;
esac
done
}
wxi-config(){
declare -gAx config
case $1 in
create)
if [[ ! -f $HOME/.warengroup/config.json ]]
then
echo '{}' > $HOME/.warengroup/config.json
fi
;;
deploy)
if [[ ! $(jq -e . $HOME/.warengroup/config.json.tmp >/dev/null 2>&1) ]]
then
mv $HOME/.warengroup/config.json.tmp $HOME/.warengroup/config.json &> /dev/null
fi
;;
write)
jq '.'"$2"' = "'$3'"' $HOME/.warengroup/config.json &> $HOME/.warengroup/config.json.tmp
wxi-config deploy
;;
load)
while IFS=$'\t' read -r k v; do config["$k"]="$v"; done < <(
jq -r '
paths(scalars) as $p
| "\( $p|map(tostring)|join(".") )\t\( getpath($p) )"
' $HOME/.warengroup/config.json
)
;;
reload)
wxi-config load
;;
*)
WX_HOME=$HOME/.warengroup
export WX_HOME
mkdir -p $WX_HOME
chmod 700 -R "$WX_HOME"
mkdir -p "$WX_HOME/credentials" \
"$WX_HOME/credentials/ssh" \
"$WX_HOME/credentials/ssh/eas" \
"$WX_HOME/credentials/ansible-vault/eas" \
"$WX_HOME/infra/eas/credentials/ssh"
find "$WX_HOME" -type d -exec chmod 700 {} +
find "$WX_HOME" -type f -exec chmod 600 {} +
wxi-config create
if [[ -n ${args['proxy']} ]]
then
wxi-config write proxy "${args['proxy']}"
fi
wxi-config load
PROXY_ARGS=()
if [[ -n "${config['proxy']}" ]]; then
PROXY_ARGS=(--proxy "${config['proxy']}")
fi
;;
esac
}
wxi-config-legacy(){
case $1 in
login)
case $2 in
write)
jq '.login.'$ORG'.token = "'$TOKEN'"' $WX_HOME/config.json &> $WX_HOME/config.json.tmp
;;
read)
if [[ -f "$WX_HOME/config.json" && $(cat $WX_HOME/config.json | jq -r .login.$ORG.token) != 'null' && $(cat $WX_HOME/config.json | jq -r .login.$ORG.token) != '' ]]
then
cat $WX_HOME/config.json | jq -r .login.$ORG.token
else
return 1
fi
;;
erase)
TOKEN=""
wxi-config-legacy login write
;;
esac
;;
*)
echo -n ""
;;
esac
mv $WX_HOME/config.json.tmp $WX_HOME/config.json &> /dev/null
}
wxi-restricted(){
if [[ -z $1 || $1 == "--user" ]]
then
if [[ $USER == "root" || $USER == "local" ]]
then
wxi-content status "Command" "Restricted"
wxi-content text "It's not permitted to execute this command with root or local user."
wxi-repeat "\n" 3
exit 1
fi
fi
if [[ $1 == "--org" ]]
then
if [[ ! -z ${args['org']} ]]
then
case ${args['org']} in
warengroup)
ORG=warengroup
;;
cwchristerw)
ORG=cwchristerw
;;
*)
wxi-content status "Organization" "Unsupported"
wxi-stop
;;
esac
elif [[ $(hostname -d) == "devices.waren.io" ]]
then
ORG=warengroup
elif [[ $(hostname -d) == "devices.christerwaren.fi" ]]
then
ORG=cwchristerw
fi
if [[ ! -z $ORG ]]
then
case $ORG in
warengroup)
DOMAIN=waren.io
VAULT_DOMAIN=vault.cwinfo.net
ORG_HEADER="Warén Group"
;;
cwchristerw)
DOMAIN=christerwaren.fi
VAULT_DOMAIN=vault.cwinfo.net
ORG_HEADER="Christer Warén"
;;
*)
wxi-content status "Organization" "Unsupported"
wxi-stop
;;
esac
else
wxi-content status "Organization" "Required"
wxi-stop
fi
fi
if [[ -z $1 || $1 == "--vault" ]]
then
if [[ -z $VAULT_DOMAIN ]]
then
wxi-content status "Vault" "Unavailable"
wxi-repeat "\n" 3
exit 1
fi
VAULT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://$VAULT_DOMAIN/v1/sys/health)
if [[ ! $VAULT_STATUS -eq 200 ]]
then
wxi-content status "Vault" "Offline"
wxi-repeat "\n" 3
exit 1
fi
fi
}
wxi-start(){
wxi-header "Warén Group / Infra / CLI" h1
mkdir -p $HOME/.warengroup
if [[ ! -f $HOME/.warengroup/config.json || $(jq -e . < $HOME/.warengroup/config.json &>/dev/null; echo $?) -gt 0 ]]
then
echo '{}' | jq > $HOME/.warengroup/config.json
fi
mkdir -p $HOME/.ssh/keys
chmod 700 -R $HOME/.ssh/keys
mkdir -p $HOME/.ssh/multiplex
chmod 700 -R $HOME/.ssh/multiplex
echo -n "$wxiBold"
echo "Designed by"
echo -n "$wxiNormal"
wxiLink "Warén Group™" "https://waren.io"
}
wxi-stop(){
# wxi-repeat "\n" 3
# for key in "${!args[@]}"
# do
# echo "$key: ${args[$key]}"
# done
wxi-repeat "\n" 3
exit 1
}
wxi-content(){
if [[ $1 == "text" ]]
then
echo "$2"
elif [[ $1 == "text*" ]]
then
echo -n "$2"
elif [[ $1 == "status" ]]
then
echo -n "Status: "
echo "$2 - $3"
elif [[ $1 == "link" ]]
then
echo "$2 - $3"
fi
}
wxiRed=$(tput setaf 196)
wxiGreen=$(tput setaf 46)
wxiYellow=$(tput setaf 226)
wxiBlue=$(tput setaf 21)
wxiPurple=$(tput setaf 165)
wxiTurquoise=$(tput setaf 14)
wxiPink=$(tput setaf 198)
wxiOrange=$(tput setaf 202)
wxiUnderline=$(tput smul)
wxiBold=$(tput bold)
wxiNormal=$(tput sgr0)
wxiLink() {
printf '\e]8;;%s\e\\%s\e]8;;\e\\\n' "$2" "$1"
echo ""
}
wxi-header(){
if [[ $2 == "h1" ]]
then
#wxi-repeat " " $(($(tput cols)/2-${#1}/2))
echo -n "$wxiBold"
echo ${1^^}
echo -n "$wxiNormal"
echo ""
fi
if [[ $2 == "h1*" ]]
then
#wxi-repeat " " $(($(tput cols)/2-${#1}/2))
echo -n "$wxiBold"
echo ${1^^}
echo -n "$wxiNormal"
fi
if [[ $2 == "h2" || $2 == "" ]]
then
#wxi-repeat " " $(($(tput cols)/2-${#1}/2))
echo -n "$wxiBold"
echo ">> $1 <<"
echo -n "$wxiNormal"
fi
if [[ $2 == "h3" ]]
then
#wxi-repeat " " $(($(tput cols)/2-${#1}/2))
echo -n "$wxiBold"
echo "$1"
echo -n "$wxiNormal"
fi
if [[ $2 == "h4" ]]
then
#wxi-repeat " " $(($(tput cols)/2-${#1}/2))
echo -n "$wxiUnderline"
echo "$1"
echo -n "$wxiNormal"
fi
}
wxi-repeat() {
if [[ $1 == " " ]]
then
local str=$1 n=$2 spaces
printf -v spaces "%*s" $n " "
printf "%s" "${spaces// /$str}"
else
for i in $(seq 1 $2);
do
echo -en $1
done
fi
}
wx-eas(){
wxi-header "Emergency Access System" h2
LOCATION="$WX_HOME/credentials"
wxi-eas-login
wxi-repeat "\n" 1
case ${args['2']} in
data)
wxi-eas-data
;;
token)
wxi-eas-token
;;
*)
wxi-content status "Error" "This feature isn't implemented yet"
;;
esac
}
wxi-eas-login(){
if [[ $(systemd-detect-virt) == "wsl" ]]
then
echo 'KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0666", TAG+="uaccess", GROUP="plugdev", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407"' | sudo tee /etc/udev/rules.d/99-yubikey.rules > /dev/null
sudo udevadm control --reload
fi
YUBIKEYS=$(ykman list --serials 2>/dev/null | jq -R -s 'split("\n")[:-1]')
if [[ $(echo $YUBIKEYS | jq 'length') != 1 ]]
then
if [[ ${args['1']} == "eas" ]]
then
wxi-content status "Error" "You need to attach atleast one Yubikey and unplug all other Yubikeys"
wxi-stop
fi
else
SERIAL=$(echo $YUBIKEYS | jq -r '.[0]')
wxi-content text "Emergency Access System - Serial Number: $SERIAL"
export SERIAL
fi
sudo systemctl enable --now pcscd &> /dev/null
}
wx-help(){
wxi-header "Help"
wxi-content text "
Usage: $0 COMMAND [OPTIONS]
Common Commands:
init Init
help Help
ssh SSH
config Config
edit Edit
save Save
sync Sync
clean Clean
keys Keys
generate Generate
sign Sign
retrieve Retrieve
save Save
sync Sync
clean Clean
Authentication Commands:
login Login
logout Logout
Management Commands:
auto Auto
clean Clean
settings Settings
Maintenance Commands:
install Install
update Update
uninstall Uninstall
";
}
wx-infra(){
wx-login
wx-auto &> /dev/null
wxi-header "Infra"
wxi-restricted
case $USERNAME in
cwchristerw)
if [[ -d "$HOME/.warengroup/infra" ]]
then
INFRA_PATH="$HOME/.warengroup/infra"
else
INFRA_PATH="$HOME/.warengroup/infra"
mkdir -p "$INFRA_PATH" &> /dev/null
git clone ssh://git@git.waren.io:2222/warengroup-private/infra.git --config core.sshCommand="ssh -i $HOME/.ssh/keys/warengroup-legacy -o ProxyJump=none" "$INFRA_PATH" &> /dev/null
fi
if [[ ! -f "$HOME/.warengroup/credentials/ansible-vault/cwchristerw" || ! -f "$HOME/.warengroup/credentials/ansible-vault/warengroup" ]]
then
mkdir -p "$HOME/.warengroup/credentials/ansible-vault" &> /dev/null
curl \
-H "X-Vault-Token: $TOKEN" \
-X GET \
https://$VAULT_DOMAIN/v1/cli/data/cwchristerw/settings/infra -s | jq -r '.data.data.cwchristerw' > "$HOME/.warengroup/credentials/ansible-vault/cwchristerw"
curl \
-H "X-Vault-Token: $TOKEN" \
-X GET \
https://$VAULT_DOMAIN/v1/cli/data/cwchristerw/settings/infra -s | jq -r '.data.data.warengroup' > "$HOME/.warengroup/credentials/ansible-vault/warengroup"
fi
INFRA_VAULT="--vault-id warengroup@$HOME/.warengroup/credentials/ansible-vault/warengroup --vault-id cwchristerw@$HOME/.warengroup/credentials/ansible-vault/cwchristerw"
;;
*)
wxi-content status "User" "Unsupported"
wxi-stop
INFRA_PATH="$HOME/.warengroup/infra"
INFRA_VAULT="--vault-id warengroup@$HOME/.warengroup/credentials/ansible-vault/warengroup"
;;
esac
if [[ -z ${args['2']} ]]
then
echo "Tag Required"
else
cd "$INFRA_PATH/ansible"
#git pull &> /dev/null
#ansible-galaxy collection install -r requirements.yml --upgrade &> /dev/null
if [[ ${args['2']} == "init" ]]
then
wxi-header "Init" h3
host=${args['host']}
if [[ -z ${args['3']} ]]
then
tags=init
else
tags=${args['3']}
fi
ansible-playbook $INFRA_VAULT init.yml --tags $tags --limit "$host"
elif [[ ${args['2']} == "manager" ]]
then
if [[ -z ${args['host']} ]]
then
host="*"
else
host=${args['host']}
fi
operation=${args['operation']}
extra_vars=${args['extra-vars']}
wxi-header "Manager" h3
ansible-playbook $INFRA_VAULT manager.yml --tags $operation --extra-vars "host=$host" --extra-vars="$extra_vars"
else
wxi-header "Infra" h3
host=${args['host']}
tags=${args['2']}
ansible-playbook $INFRA_VAULT infra.yml --tags $tags --limit "$host"
fi
cd "$OLDPWD"
fi
}
wx-ssh(){
wx-login &> /dev/null
case ${args['2']} in
config)
wxi-ssh-config
;;
keys)
wxi-ssh-keys
;;
*)
wxi-header "SSH"
wxi-restricted
;;
esac
}
wx-welcome(){
wxi-header "Welcome"
wxi-header "Help" h3
wxi-content text "Use \"wx help\" command"
echo ""
wxi-header "Useful Links" h3
wxi-content link "Infra" "https://infra.waren.io"
wxi-content link "Status" "https://status.waren.io"
}
wx-login(){
wxi-header "Login"
wxi-restricted --user
wxi-restricted --org
wxi-restricted --vault
wxi-header "$ORG_HEADER" h3
if [[ ! -z ${args['auth-method']} ]]
then
AUTH_METHOD=${args['auth-method']}
elif [[ ! -z ${args['token']} ]]
then
AUTH_METHOD=token
elif [[ $(wxi-config-legacy login read) ]]
then
AUTH_METHOD=token
elif [[ ! -z ${args['username']} ]]
then
AUTH_METHOD=ldap
else
AUTH_METHOD=ldap
fi
if [[ ! -z $AUTH_METHOD ]]
then
case $AUTH_METHOD in
ldap)
echo -n "Username: "
if [[ ! -z ${args['username']} ]]
then
USERNAME=${args['username']}
wxi-content text "$USERNAME"
else
read USERNAME
fi
echo -n "Password: "
if [[ ! -z ${args['password']} ]]
then
PASSWORD=${args['password']}
else
read -s PASSWORD
fi
if [[ ! -z $PASSWORD ]]
then
wxi-content text "****************"
else
wxi-content text ""
fi
if [[ -z $USERNAME || -z $PASSWORD ]]
then
wxi-content status "Username & Password" "Required"
wxi-stop
fi
VAULT_LOGIN=$(curl https://$VAULT_DOMAIN/v1/auth/ldap/login/$USERNAME -X POST -d '{ "password": "'$PASSWORD'" }' -s | jq -r '.auth.client_token')
if [[ -z $VAULT_LOGIN || ${#VAULT_LOGIN} -lt 95 || ${#VAULT_LOGIN} -gt 95 ]]
then
wxi-content status "Login" "Failed"
wxi-stop
fi
TOKEN=$VAULT_LOGIN
wxi-config-legacy login write
;;
token)
echo -n "Token: "
if [[ ! -z ${args['token']} ]]
then
if [[ ${args['token']} != "true" ]]
then
TOKEN=${args['token']}
fi
elif [[ $(wxi-config-legacy login read) ]]
then
TOKEN=$(wxi-config-legacy login read)
else
read -s TOKEN
fi
if [[ ! -z $TOKEN ]]
then
wxi-content text "***********************************************************************************************"
fi
if [[ -z $TOKEN ]]
then
wxi-content status "Token" "Required"
wxi-stop
fi
if [[ ${#TOKEN} -lt 95 || ${#TOKEN} -gt 95 ]]
then
wxi-content status "Token" "Invalid"
wxi-stop
fi
VAULT_LOGIN=$(curl https://$VAULT_DOMAIN/v1/auth/token/renew-self -X POST --header "X-Vault-Token: $TOKEN" -d '{ "token": "'$TOKEN'" }' -s | jq -r '.auth.client_token')
if [[ -z $VAULT_LOGIN || ${#VAULT_LOGIN} -lt 95 || ${#VAULT_LOGIN} -gt 95 ]]
then
wxi-content status "Login" "Failed"
if [[ $(wxi-config-legacy login read) ]]
then
wx-logout &> /dev/null
wx-login
else
wxi-stop
fi
fi
TOKEN=$VAULT_LOGIN
wxi-config-legacy login write
;;
*)
wxi-content status "Login Type" "Unsupported"
wxi-stop
;;
esac
fi
VAULT_USERNAME=$(curl https://$VAULT_DOMAIN/v1/auth/token/lookup-self -X GET --header "X-Vault-Token: $TOKEN" -s | jq -r '.data.display_name')
if [[ -z $VAULT_USERNAME ]]
then
wxi-content status "Login" "Username Missing"
wxi-stop
elif [[ $VAULT_USERNAME != ldap* && $VAULT_USERNAME != oidc* ]]
then
wxi-content status "Login" "Authentication Method Invalid"
wxi-stop
elif [[ $VAULT_USERNAME == ldap* ]]
then
USERNAME=${VAULT_USERNAME#ldap-}
elif [[ $VAULT_USERNAME == oidc* ]]
then
USERNAME=${VAULT_USERNAME#oidc-}
fi
}
wx-logout(){
wxi-header "Logout"
wxi-restricted --user
wxi-restricted --org
wxi-restricted --vault
if [[ -f "$WX_HOME/config.json" && $(cat $WX_HOME/config.json | jq -r .login.$ORG.token) != 'null' ]]
then
TOKEN=$(cat $WX_HOME/config.json | jq -r .login.$ORG.token)
fi
VAULT_STATUS=$(curl https://$VAULT_DOMAIN/v1/auth/token/revoke-self -X POST --header "X-Vault-Token: $TOKEN" -s -o /dev/null -w "%{http_code}")
if [[ $VAULT_STATUS -eq 204 || $VAULT_STATUS -eq 403 ]]
then
wxi-header "$ORG_HEADER" h3
echo "Logging Out..."
wxi-config-legacy login erase
fi
}
wxi-eas-data(){
case ${args['3']} in
encrypt)
wxi-eas-data-encrypt
;;
decrypt)
wxi-eas-data-decrypt
;;
retrieve)
wxi-eas-data-retrieve
;;
deliver)
wxi-eas-data-deliver
;;
*)
wx-help
;;
esac
}
wxi-eas-token(){
case ${args['3']} in
create)
wxi-eas-token-create
;;
erase)
wxi-eas-token-erase
;;
sign)
wxi-eas-token-sign
;;
esac
}
wx-install(){
if [[ "${args['1']}" == "install" ]]
then
wxi-header "Install" h2
fi
if [[ ! -L "$HOME/bin/wx" && ! -f "/opt/ansible/bin/ansible-playbook" && ! -f "/bin/jq" && ! -f "/bin/podman" && ! -f "/bin/ykman"|| "${args['1']}" == "upgrade" ]]
then
cd "$WX_HOME/infra"
wxi-repeat "\n" 1
wxi-header "Git" h3
git stash -- cli.sh
git pull
wxi-repeat "\n" 1
wxi-header "Elevated Privileges" h3
sudo echo 'This command uses sudo!'
wxi-repeat "\n" 1
wxi-header "Ansible" h3
wxi-content text* "Dependencies: "
sudo apt-get update &> /dev/null
sudo apt-get install -y python3-pip python3-venv jq git curl lsb-release sudo sshpass rsync &> /dev/null
wxi-content text "Ready ✔"
wxi-content text* "Python 3 - Virtual Environment: "
sudo python3 -m venv /opt/ansible &> /dev/null
if [[ -d "/opt/ansible" ]]
then
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
fi
wxi-content text* "Ansible: "
sudo /opt/ansible/bin/pip3 install ansible-core &> /dev/null
if [[ -f "/opt/ansible/bin/ansible-playbook" ]]
then
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
fi
wxi-content text* "Python3 Libraries - Dependencies: "
sudo /opt/ansible/bin/pip3 install cryptography dnspython hvac jmespath netaddr passlib pexpect xmltodict ansi2html --upgrade &> /dev/null
wxi-content text "Ready ✔"
wxi-content text* "Collections: "
sudo ln -s /opt/ansible/collections /usr/share/ansible/collections &> /dev/null
sudo /opt/ansible/bin/ansible-galaxy collection install -r ansible/requirements.yml -p /usr/share/ansible/collections --upgrade &> /dev/null
wxi-content text "Ready ✔"
wxi-repeat "\n" 1
wxi-header "CLI Tool" h3
if [[ -d "./cli/src" ]]
then
wxi-content text* "Dependencies: "
sudo apt-get update &> /dev/null
sudo apt-get install -y jq yubikey-manager &> /dev/null
if [[ -f "/bin/jq" && -f "/bin/ykman" ]]
then
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
fi
wxi-content text* "Generate: "
python3 cli/generator.py
if [[ -f "./cli/cli.sh" ]]
then
wxi-content text "Ready ✔"
wxi-content text* "Deploying: "
mv -f ./cli/cli.sh ./cli.sh
chmod +x ./cli.sh
if [[ ! -L "$HOME/bin/wx" && ! -f "$HOME/bin/wx" ]]
then
mkdir -p "$HOME/bin"
ln -s "$PWD/cli.sh" "$HOME/bin/wx"
fi
if [[ $(systemd-detect-virt) == "wsl" ]]
then
if [[ ! -L "/bin/wx" ]]
then
sudo ln -s "$PWD/cli.sh" "/bin/wx"
fi
fi
if [[ -f "./cli.sh" ]]
then
wxi-content text "Ready ✔"
fi
else
wxi-content text "Failed ✖"
fi
fi
cd "$OLDPWD"
else
wxi-content text "You have already installed!"
fi
}
wx-install2(){
wxi-header "Install"
wxi-restricted --user
if [[ -f "./wx" && -f "./maintainer.sh" && -d "./src" ]]
then
./maintainer.sh
fi
mkdir -p $HOME/bin
if [[ $(curl -s -o /dev/null -w "%{http_code}" https://git.waren.io/warengroup/wx/raw/branch/master/wx) -eq 200 ]]
then
curl https://git.waren.io/warengroup/wx/raw/branch/master/wx -o $HOME/bin/wx &> /dev/null
chmod +x $HOME/bin/wx &> /dev/null
fi
CRONJOB_NAME="#Warén CLI: Auto"
CRONJOB_TASK="*/5 * * * * $HOME/bin/wx auto"
if [[ -z $(crontab -l | grep -F "$CRONJOB_NAME") || -z $(crontab -l | grep -F "$CRONJOB_TASK") ]]
then
(crontab -l ; echo "$CRONJOB_NAME" ; echo "$CRONJOB_TASK") | grep -Fv "no crontab" | crontab -
fi
}
wx-upgrade(){
wxi-header "Upgrade" h2
wx-install
}
wx-auto(){
wx-login
wxi-header "Auto"
wxi-restricted
wxi-ssh-config-sync
wxi-ssh-keys-sign
wxi-ssh-keys-sync
}
wx-clean(){
wxi-header "Clean"
wxi-restricted --user
wxi-ssh-config-clean
wxi-ssh-keys-clean
}
wx-settings(){
wx-login
wx-auto &> /dev/null
wxi-header "Settings"
wxi-restricted --user
}
wxi-ssh-config(){
case ${args['3']} in
edit)
wxi-ssh-config-sync
wxi-ssh-config-edit
wxi-ssh-config-save
;;
save)
wxi-ssh-config-save
;;
sync)
wxi-ssh-config-sync
;;
clean)
wxi-ssh-config-clean
;;
*)
wxi-ssh-config-sync
;;
esac
}
wxi-ssh-keys(){
case ${args['3']} in
generate)
wxi-ssh-keys-retrieve ${args['4']}
wxi-ssh-keys-generate ${args['4']}
wxi-ssh-keys-save ${args['4']}
;;
sign)
wxi-ssh-keys-sign
;;
retrieve)
wxi-ssh-keys-retrieve ${args['4']}
;;
save)
wxi-ssh-keys-save ${args['4']}
;;
sync)
wxi-ssh-keys-sync
;;
clean)
wxi-ssh-keys-clean
;;
*)
wxi-header "SSH / Keys"
;;
esac
}
pxi-eas-data-decrypt(){
pxi-header "Data - Encrypt" h3
if [[ -n ${args['confirm']} ]]
then
if [[ -f $LOCATION/ansible-vault/eas/$SERIAL && $(base64 "$LOCATION/ansible-vault/eas/$SERIAL") != "" ]]
then
i=0
for file in "$PWD"/eas/data/$SERIAL/*/*/credentials;
do
i=$((i + 1))
echo "$i)${file#"$PWD/eas/data/$SERIAL/"}"
ansible-vault decrypt --vault-id "Warén Group - Infra - Emergency Access System ($SERIAL)"@"$LOCATION/ansible-vault/eas/$SERIAL" "$file"
done
fi
else
pxi-content text "Confirmation Needed ✖ (--confirm)"
fi
}
pxi-eas-data-deliver(){
px-login vault
pxi-repeat "\n" 1
pxi-header "Data - Deliver" h3
if [[ -n ${args['confirm']} ]]
then
cd "$PWD/ansible"
playbook=cli
tasks=eas-data-deliver
limit="${args['limit']:-all}"
vaulted=(--vault-id "Warén Group - Infra - Emergency Access System ($SERIAL)@~/.warengroup/credentials/ansible-vault/eas/$SERIAL")
/opt/ansible/bin/ansible-playbook $playbook.yml -t "$tasks" --limit "$limit,localhost" --extra-vars "${args['vars']}" "${vaulted[@]}"
cd "$OLDPWD"
else
pxi-content text "Confirmation Needed ✖ (--confirm)"
fi
}
pxi-eas-data-encrypt(){
pxi-header "Data - Encrypt" h3
if [[ -f $LOCATION/ansible-vault/eas/$SERIAL && $(base64 "$LOCATION/ansible-vault/eas/$SERIAL") != "" ]]
then
i=0
for file in "$PWD"/eas/data/$SERIAL/*/*/credentials;
do
i=$((i + 1))
echo "$i)${file#"$PWD/eas/data/$SERIAL/"}"
ansible-vault encrypt --vault-id "Warén Group - Infra - Emergency Access System ($SERIAL)"@"$LOCATION/ansible-vault/eas/$SERIAL" "$file"
done
fi
}
pxi-eas-data-retrieve(){
px-login vault
pxi-repeat "\n" 1
pxi-header "Data - Retrieve" h3
if [[ -n ${args['confirm']} ]]
then
cd "$PWD/ansible"
playbook=cli
tasks=eas-data-retrieve
limit="${args['limit']:-all}"
vaulted=(--vault-id "Warén Group - Infra - Emergency Access System ($SERIAL)@~/.warengroup/credentials/ansible-vault/eas/$SERIAL")
/opt/ansible/bin/ansible-playbook $playbook.yml -t "$tasks" --limit "$limit,localhost" --extra-vars "${args['vars']}" "${vaulted[@]}"
cd "$OLDPWD"
else
pxi-content text "Confirmation Needed ✖ (--confirm)"
fi
}
wxi-eas-token-create(){
wxi-header "Token - Create" h3
wxi-header "Ansible Vault" h4
if [[ $(ykman piv objects export 0x005FFF16 - 2>/dev/null) == "" ]]
then
wxi-content text* "PIN: "
read -s PIN
wxi-content text "******"
if [[ -n $PIN ]]
then
wxi-content text* "Generating: "
echo $(LC_ALL=C tr -dc 'A-Z2-7' </dev/urandom | head -c 64; echo) | ykman piv objects import --pin "$PIN" 0x005FFF16 -
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
wxi-content status "Error" "PIN Required"
fi
fi
wxi-content text* "Retrieving: "
EAS_AVP=$(ykman piv objects export 0x005FFF16 - 2>/dev/null)
if [[ $EAS_AVP != "" ]]
then
echo -e "Warén Group - Infra - Emergency Access System ($SERIAL) / Ansible Vault / $EAS_AVP" > "$LOCATION/ansible-vault/eas/$SERIAL"
if [[ -f "$LOCATION/ansible-vault/eas/$SERIAL" && $(base64 "$LOCATION/ansible-vault/eas/$SERIAL") != "" ]]
then
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
fi
else
wxi-content text "Failed ✖"
fi
wxi-repeat "\n" 1
wxi-header "SSH" h4
if [[ ! -f "$LOCATION/ssh/eas/$SERIAL" || ! -f "$PWD/eas/credentials/ssh/$SERIAL.pub" ]]
then
if [[ ! -f "$LOCATION/ssh/eas/$SERIAL" && -f "$PWD/eas/credentials/ssh/$SERIAL.pub" ]]
then
OLDOLDPWD=$OLDPWD
cd "$LOCATION/ssh/eas"
wxi-content text* "Retrieving: "
wxi-content text "Processing..."
wxi-repeat "\n" 1
ssh-keygen -K
wxi-repeat "\n" 1
if [[ -f "id_ed25519_sk_rk_warengroup-infra-eas-$SERIAL" ]]
then
mv "id_ed25519_sk_rk_warengroup-infra-eas-$SERIAL" "$SERIAL"
mv "id_ed25519_sk_rk_warengroup-infra-eas-$SERIAL.pub" "$SERIAL.pub"
ssh-keygen -c -f "$LOCATION/ssh/eas/$SERIAL" -P "" -C "Warén Group - Infra - Emergency Access System ($SERIAL)" &> /dev/null
wxi-content text* "Retrieving: "
wxi-content text "Ready ✔"
else
wxi-content text* "Retrieving: "
wxi-content text "Failed ✖"
fi
wxi-repeat "\n" 1
wxi-content text* "Cleaning: "
rm -f id_ecdsa_sk_rk_*
rm -f id_ed25519_sk_rk_*
rm -f id_rsa_sk_rk_*
wxi-content text "Ready ✔"
cd "$OLDPWD"
OLDPWD=$OLDOLDPWD
elif [[ ! -f "$LOCATION/ssh/eas/$SERIAL" ]]
then
wxi-content text* "Generating: "
wxi-content text "Processing..."
wxi-repeat "\n" 1
ssh-keygen -t ed25519-sk -f "$LOCATION/ssh/eas/$SERIAL" -O resident -O verify-required -O "application=ssh:warengroup-infra-eas-$SERIAL" -N "" -C "Warén Group - Infra - Emergency Access System ($SERIAL)"
wxi-repeat "\n" 1
if [[ -f "$LOCATION/ssh/eas/$SERIAL" ]]
then
wxi-content text* "Generating: "
wxi-content text "Ready ✔"
else
wxi-content text* "Generating: "
wxi-content text "Failed ✖"
fi
wxi-repeat "\n" 1
fi
if [[ -f "$LOCATION/ssh/eas/$SERIAL.pub" && ! -f "$PWD/eas/credentials/ssh/$SERIAL.pub" ]]
then
wxi-content text* "Delivering: "
cp "$LOCATION/ssh/eas/$SERIAL.pub" "$PWD/eas/credentials/ssh/$SERIAL.pub"
if [[ -f "$PWD/eas/credentials/ssh/$SERIAL.pub" ]]
then
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
fi
fi
else
wxi-content text* "Processing: "
wxi-content text "Done ✔"
fi
}
wxi-eas-token-erase(){
wxi-header "Token - Erase" h3
wxi-content text* "Processing: "
if [[ -f "$LOCATION/$serial" || -f "$LOCATION/$serial.pub" || -f "$PWD/eas/credentials/ssh/$serial.pub" ]]
then
if [[ -n ${args['confirm']} ]]
then
rm -f "$LOCATION/ssh/eas/$serial"
rm -f "$LOCATION/ssh/eas/$serial.pub"
rm -f "$PWD/eas/credentials/ssh/$serial.pub"
if [[ ! -f "$LOCATION/ssh/eas/$serial" && ! -f "$LOCATION/ssh/eas/$serial.pub" && ! -f "$PWD/eas/credentials/ssh/$serial.pub" ]]
then
wxi-content text "Ready ✔"
else
wxi-content text "Failed ✖"
fi
else
wxi-content text "Confirmation Needed ✖ (--confirm)"
fi
else
wxi-content text "Done ✔"
fi
}
wxi-eas-token-sign(){
wxi-header "Token - Sign" h3
wxi-eas-token-sign-gen
}
wxi-eas-token-sign-gen(){
LOCATION="$WX_HOME/credentials"
if [[ -f "$LOCATION/ssh/eas/$SERIAL" ]]
then
if [[ ! -f "$LOCATION/ssh/eas/$SERIAL-" ]]
then
wxi-ssh-keys-generate "eas/$SERIAL-" "Warén Group - Infra - Emergency Access System ($SERIAL)" &> /dev/null
fi
ssh-keygen -s "$LOCATION/ssh/eas/$SERIAL" -I "Warén Group - Infra - Emergency Access System ($SERIAL)" -n root -V -1m:+30m "$LOCATION/ssh/eas/$SERIAL-.pub"
mv -f "$LOCATION/ssh/eas/$SERIAL--cert.pub" "$LOCATION/ssh/eas/$SERIAL-.sig"
fi
}
wxi-ssh-config-clean(){
wxi-header "SSH / Config / Clean"
wxi-restricted
VAULT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/config -X GET --header "X-Vault-Token: $TOKEN")
if [[ -f "$HOME/.ssh/config" && $VAULT_STATUS -eq 200 ]]
then
rm "$HOME/.ssh/config"
fi
}
wxi-ssh-config-edit(){
wxi-header "SSH / Config / Edit"
wxi-restricted
nano ~/.ssh/config
}
wxi-ssh-config-save(){
wxi-header "SSH / Config / Save"
wxi-restricted
if [[ -f "$HOME/.ssh/config" ]]
then
curl https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/config -X POST --header "X-Vault-Token: $TOKEN" -d "{ \"data\": { \"data\": \"$(cat ~/.ssh/config | base64 -w 0)\" } }" -s &> /dev/null
fi
}
wxi-ssh-config-sync(){
wxi-header "SSH / Config / Sync"
wxi-restricted
VAULT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/config -X GET --header "X-Vault-Token: $TOKEN")
if [[ $VAULT_STATUS -eq 200 ]]
then
touch ~/.ssh/config
SSH1_CONFIG_MD5=$(curl https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/config -X GET --header "X-Vault-Token: $TOKEN" -s | jq -r '.data.data.data' | base64 -d | md5sum | base64)
SSH2_CONFIG_MD5=$(cat ~/.ssh/config | md5sum | base64)
if [[ $SSH1_CONFIG_MD5 != $SSH2_CONFIG_MD5 ]]
then
echo $(curl https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/config -X GET --header "X-Vault-Token: $TOKEN" -s | jq -r '.data.data.data') | base64 -d > ~/.ssh/config 2>&1
chmod 700 ~/.ssh/config
fi
fi
}
wxi-ssh-keys-clean(){
wxi-header "SSH / Keys / Clean"
wxi-restricted
if [[ ! -z $1 ]]
then
if [[ -f "$HOME/.ssh/keys/$1" ]]
then
rm "$HOME/.ssh/keys/$1" &> /dev/null
rm "$HOME/.ssh/keys/$1.pub" &> /dev/null
rm "$HOME/.ssh/keys/$1.sig" &> /dev/null
fi
else
wxi-ssh-keys-clean $ORG
if [[ $USERNAME == "cwchristerw" ]]
then
wxi-ssh-keys-clean warengroup
fi
for file in ~/.ssh/keys/*
do
VAULT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/keys/$(basename "$file" .pub) -X GET --header "X-Vault-Token: $TOKEN")
if [[ $VAULT_STATUS -eq 200 ]]
then
rm "$file" &> /dev/null
fi
done
fi
}
wxi-ssh-keys-generate(){
wxi-header "SSH / Keys / Generate"
wxi-restricted
if [[ ! -z $1 ]]
then
if [[ ! -f "$HOME/.ssh/keys/$1" ]]
then
ssh-keygen -t ed25519 -f $HOME/.ssh/keys/$1 -q -N "" -C "$USERNAME" &> /dev/null
fi
fi
}
wxi-ssh-keys-retrieve(){
wxi-header "SSH / Keys / Retrieve"
wxi-restricted
if [[ ! -z $1 ]]
then
VAULT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/keys/$1 -X GET --header "X-Vault-Token: $TOKEN")
if [[ $VAULT_STATUS -eq 200 ]]
then
echo $(curl https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/keys/$1 -X GET --header "X-Vault-Token: $TOKEN" -s | jq -r '.data.data.private') | base64 -d > ~/.ssh/keys/$1 2>&1
chmod 700 ~/.ssh/keys/$1
echo $(curl https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/keys/$1 -X GET --header "X-Vault-Token: $TOKEN" -s | jq -r '.data.data.public') | base64 -d > ~/.ssh/keys/$1.pub 2>&1
chmod 700 ~/.ssh/keys/$1.pub
fi
fi
}
wxi-ssh-keys-save(){
wxi-header "SSH / Keys / Save"
wxi-restricted
if [[ ! -z $1 ]]
then
if [[ -f "$HOME/.ssh/keys/$1" ]]
then
curl https://$VAULT_DOMAIN/v1/cli/data/$USERNAME/settings/ssh/keys/$1 -X POST --header "X-Vault-Token: $TOKEN" -d "{ \"data\": { \"private\": \"$(cat ~/.ssh/keys/$1 | base64 -w 0)\", \"public\": \"$(cat ~/.ssh/keys/$1.pub | base64 -w 0)\" } }" -s &> /dev/null
fi
fi
}
wxi-ssh-keys-sign(){
wxi-header "SSH / Keys / Sign"
wxi-restricted
if [[ $USERNAME == "cwchristerw" ]]
then
wxi-ssh-keys-sign-create cwchristerw sysadmin 3600
wxi-ssh-keys-sign-create warengroup sysadmin 3600
else
wxi-ssh-keys-sign-create $ORG sysadmin 3600
fi
}
wxi-ssh-keys-sign-create(){
NAME=$1
ROLE=$2
PRINCIPALS=$2
TTL=$3
wxi-ssh-keys-generate $NAME &> /dev/null
if [[ -f "$HOME/.ssh/keys/$NAME" ]]
then
wxi-content text "$NAME/$ROLE"
echo $(curl https://$VAULT_DOMAIN/v1/ssh/sign/$ROLE -X POST --header "X-Vault-Token: $TOKEN" -d "{ \"public_key\": \"$(cat $HOME/.ssh/keys/$NAME.pub)\", \"valid_principals\": \"$PRINCIPALS,$USERNAME\", \"ttl\": \"$TTL\" }" -s | jq -r '.data.signed_key') > ~/.ssh/keys/$NAME.sig 2>&1
fi
}
wxi-ssh-keys-sync(){
wxi-header "SSH / Keys / Sync"
wxi-restricted
VAULT_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://$VAULT_DOMAIN/v1/cli/metadata/$USERNAME/settings/ssh/keys -X LIST --header "X-Vault-Token: $TOKEN")
if [[ $VAULT_STATUS -eq 200 ]]
then
for name in $(curl https://$VAULT_DOMAIN/v1/cli/metadata/$USERNAME/settings/ssh/keys -X LIST --header "X-Vault-Token: $TOKEN" -s | jq -r '.data.keys | @sh' | tr -d \')
do
wxi-content text $name
wxi-ssh-keys-retrieve $name &> /dev/null
done
fi
}
wxi-args "$@"
wxi-config
echo -n $wxiBold$wxiOrange
cat <<'EOF'
(`\ .-') /` ('-. _ .-') ('-. .-') _
`.( OO ),' ( OO ).-.( \( -O ) _( OO) ( OO ) )
,--./ .--. / . --. / ,------. (,------.,--./ ,--,'
| | | | \-. \ | /`. ' | .---'| \ | |\
| | | |,.-'-' | | | / | | | | | \| | )
| |.'.| |_)\| |_.' | | |_.' |(| '--. | . |/
| | | .-. | | . '.' | .--' | |\ |
| ,'. | | | | | | |\ \ | `---.| | \ |
'--' '--' `--' `--' `--' '--' `------'`--' `--'
EOF
echo -n $wxiNormal
wxi-start
if [[ ! -z ${args['1']} ]] && [[ $(type -t wx-${args['1']}) == function ]]
then
wx-${args['1']}
else
wx-welcome
fi
wxi-stop