ctctl/install.sh

249 lines
8.5 KiB
Bash
Executable File

#!/usr/bin/env bash
BIN_DIR=~/bin
DEFAULT_USER=${CTCTL_USER:-$(whoami | sed -r 's/\@.*//')}
DEFAULT_DOMAIN=${CTCTL_DOMAIN:-consul}
read -p "Enter your user login [${DEFAULT_USER}] " INSTALL_USER
INSTALL_USER=${INSTALL_USER:-${DEFAULT_USER}}
read -p "Enter container domain [${DEFAULT_DOMAIN}] " INSTALL_DOMAIN
INSTALL_DOMAIN=${INSTALL_DOMAIN:-${DEFAULT_DOMAIN}}
function get_gh_release() {
local VERSION
# Check if cached version file exists and has been modified less than 6 hours ago
if [[ -e "~/.ctctl/versions/$1" && $(stat -c %Y -- "~/.ctctl/versions/$1") -gt $(($EPOCHSECONDS - 21600)) ]]; then
VERSION=$(cat ~/.ctctl/versions/$1)
else
VERSION=$(curl --silent "https://api.github.com/repos/$1/releases/latest" | \
jq -r .tag_name | sed -E 's/^v//')
# Cache the last version so we don't ask github API every time
mkdir -p $(dirname ~/.ctctl/versions/$1)
echo -n ${VERSION} > ~/.ctctl/versions/$1
fi
echo ${VERSION}
}
# Detect OS
SYSTEM="$(uname -s)"
case "${SYSTEM}" in
Linux*) MACHINE=linux;;
Darwin*) MACHINE=darwin;;
*) MACHINE=unknown;;
esac
# Architesture, so we support Apple M1/M2 chips
CPU=$(uname -m)
case "${ARCH}" in
x86_64) ARCH=amd64;;
arm64) ARCH=arm64;;
*) ARCH=amd64;;
esac
if [ "${MACHINE}" = "unknown" ]; then
echo "Unsupported system"
exit 1
fi
# Check that we have the required utilities
for TOOL in jq openssl curl unzip fzf git; do
if ! command -v $TOOL > /dev/null 2>&1; then
echo "$TOOL not found. Please install it first"
exit 1
fi
done
[ -d ${BIN_DIR} ] || mkdir -p ${BIN_DIR}
mkdir -p ~/.ctctl/versions
# Install hashicorp binaries
for UTIL in vault consul consul-template nomad levant; do
LAST_VER=$(get_gh_release "hashicorp/${UTIL}")
echo "Last version of ${UTIL} is v${LAST_VER}"
if [ -x "${BIN_DIR}/${UTIL}" ]; then
CUR_VER=$(${BIN_DIR}/${UTIL} --version 2>/dev/null | head -1 | sed -E 's/.* v([0-9]+(\.[0-9]+)*).*/\1/')
echo "${UTIL} v${CUR_VER} is installed"
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo "Installing ${UTIL} v${LAST_VER}"
curl -L -O https://releases.hashicorp.com/${UTIL}/${LAST_VER}/${UTIL}_${LAST_VER}_${MACHINE}_${ARCH}.zip
unzip -o -d ~/bin/ ${UTIL}_${LAST_VER}_${MACHINE}_${ARCH}.zip
rm -f ${UTIL}_${LAST_VER}_${MACHINE}_${ARCH}.zip
else
echo "Last ${UTIL} version (v${CUR_VER}) is already installed"
fi
done
## Install logcli
for UTIL in logcli; do
LAST_VER=$(get_gh_release "grafana/loki")
if [ -x "${BIN_DIR}/${UTIL}" ]; then
CUR_VER=$(${BIN_DIR}/${UTIL} --version 2>&1 | head -1 | sed -E 's/.* version ([0-9]+(\.[0-9]+)*).*/\1/')
echo "${UTIL} v${CUR_VER} is installed"
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo "Installing ${UTIL} v${LAST_VER}"
curl -L -O https://github.com/grafana/loki/releases/download/v${LAST_VER}/logcli-${MACHINE}-${ARCH}.zip
unzip -o -d ~/bin/ ${UTIL}-${MACHINE}-${ARCH}.zip
rm -f ${UTIL}-${MACHINE}-${ARCH}.zip
mv -f ~/bin/logcli-${MACHINE}-${ARCH} ~/bin/logcli
else
echo "Last ${UTIL} version (v${CUR_VER}) is already installed"
fi
done
# Install yq
for UTIL in yq; do
LAST_VER=$(get_gh_release "mikefarah/yq")
if [ -x "${BIN_DIR}/${UTIL}" ]; then
CUR_VER=$(${BIN_DIR}/${UTIL} --version 2>&1 | sed -E 's/.* version v([0-9]+(\.[0-9]+)*).*/\1/')
echo "${UTIL} v${CUR_VER} is installed"
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo "Installing ${UTIL} v${LAST_VER}"
curl -L -o ${BIN_DIR}/${UTIL} https://github.com/mikefarah/${UTIL}/releases/download/v${LAST_VER}/${UTIL}_${MACHINE}_${ARCH}
chmod +x ${BIN_DIR}/${UTIL}
else
echo "Last ${UTIL} version (v${CUR_VER}) is already installed"
fi
done
# Install gomplate
for UTIL in gomplate; do
LAST_VER=$(get_gh_release "hairyhenderson/${UTIL}")
if [ -x "${BIN_DIR}/${UTIL}" ]; then
CUR_VER=$(${BIN_DIR}/${UTIL} --version 2>&1 | sed -E 's/gomplate version ([0-9]+(\.[0-9]+)*)/\1/')
echo "${UTIL} v${CUR_VER} is installed"
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo "Installing ${UTIL} v${LAST_VER}"
curl -L -o ${BIN_DIR}/${UTIL} https://github.com/hairyhenderson/${UTIL}/releases/download/v${LAST_VER}/${UTIL}_${MACHINE}-${ARCH}
chmod +x ${BIN_DIR}/${UTIL}
else
echo "Last ${UTIL} version (v${CUR_VER}) is already installed"
fi
done
mkdir -p ~/.bashrc.d
mkdir -p ~/.ctctl/${INSTALL_DOMAIN}
mkdir -p ~/.ctctl/bin
source ~/.bashrc
PREV_IFS=$IFS
DIR_IN_PATH=0
IFS=":"
for P in $PATH; do
[ "$P" = "~/bin" -o "$P" = "$(realpath ~/bin)" ] && DIR_IN_PATH=1
done
IFS=$PREV_IFS
echo "Configuring the environment"
echo
echo "Installing ct env scripts"
cp -f ctctl ~/.ctctl/bin/
mkdir -p ~/.local/share/bash-completion/completions
cp -f bash_completion ~/.local/share/bash-completion/completions/ctctl
chmod 755 ~/.ctctl/bin/*
cp -f ctctl.example.conf ~/.ctctl/${INSTALL_DOMAIN}/ctctl.example.conf
cat <<_EOF > ~/.ctctl/${INSTALL_DOMAIN}/ctctl.conf
CTCTL_USER=${INSTALL_USER}
CTCTL_DOMAIN=${INSTALL_DOMAIN}
_EOF
cat << '_EOF' > ~/.local/share/bash-completion/completions/vault
complete -C ~/bin/vault vault
_EOF
cat << '_EOF' > ~/.local/share/bash-completion/completions/nomad
complete -C ~/bin/nomad nomad
_EOF
cat << '_EOF' > ~/.local/share/bash-completion/completions/consul
complete -C ~/bin/consul consul
_EOF
logcli --completion-script-bash > ~/.local/share/bash-completion/completions/logcli
cat <<_EOF > ~/.bashrc.d/ctctl
alias ctctl='source ~/.ctctl/bin/ctctl'
_EOF
if [ "${DIR_IN_PATH}" = "0" ]; then
cat <<_EOF >> ~/.bashrc.d/ctctl
export PATH=$(realpath ~/bin):$PATH
_EOF
source ~/.bashrc.d/ctctl
fi
echo
echo "Configuring Vault access"
cat <<_EOF >> ~/.ctctl/${INSTALL_DOMAIN}/ctctl.conf
VAULT_ADDR=https://active.vault.service.${INSTALL_DOMAIN}:8200
_EOF
echo
echo "Configuring Nomad access"
cat <<_EOF >> ~/.ctctl/${INSTALL_DOMAIN}/ctctl.conf
NOMAD_ADDR=https://nomad.service.${INSTALL_DOMAIN}:4646
NOMAD_CACERT=~/.ctctl/${INSTALL_DOMAIN}/nomad/ca.crt
NOMAD_CLIENT_CERT=~/.ctctl/${INSTALL_DOMAIN}/nomad/cli.crt
NOMAD_CLIENT_KEY=~/.ctctl/${INSTALL_DOMAIN}/nomad/cli.key
_EOF
echo
echo "Configuring Consul access"
cat <<_EOF >> ~/.ctctl/${INSTALL_DOMAIN}/ctctl.conf
CONSUL_HTTP_ADDR=https://consul.service.${INSTALL_DOMAIN}:8501
CONSUL_CACERT=~/.ctctl/${INSTALL_DOMAIN}/consul/ca.crt
CONSUL_CLIENT_CERT=~/.ctctl/${INSTALL_DOMAIN}/consul/cli.crt
CONSUL_CLIENT_KEY=~/.ctctl/${INSTALL_DOMAIN}/consul/cli.key
_EOF
# Install the certificate renewer scripts
# We'll use consul-template to obtain and renew certificates for Nomad and Consul
for UTIL in nomad consul; do
mkdir -p ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}
# Create the files so realpath doesn't fail
# Note : on Linux we could use realpath -m, but not on MAC OS
for FILE in ca.crt cli.crt cli.key cli.p12 bundle.pem; do
touch ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/${FILE}
done
cat <<_EOF > ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/bundle.pem.tpl
{{ with pkiCert "pki/${UTIL}/issue/${UTIL}-user" "common_name=${CTCTL_USER:-$(whoami | sed -r 's/\@.*//')}.${UTIL}.${INSTALL_DOMAIN}" "ttl=8760h" }}
{{ .CA }}
{{ .Cert }}
{{ .Key }}
{{ .CA | writeToFile "$(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/ca.crt)" "" "" "0644" }}
{{ .Cert | writeToFile "$(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/cli.crt)" "" "" "0644" }}
{{ .Key | writeToFile "$(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/cli.key)" "" "" "0600" }}
{{ end }}
_EOF
cat <<_EOF > ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/consul-template.hcl
template {
source = "$(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/bundle.pem.tpl)"
destination = "$(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/bundle.pem)"
perms = 0640
exec {
# We create a PKCS12 bundle so we can easily import it in a web browser
command = "openssl pkcs12 -export -out $(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/cli.p12) -in $(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/cli.crt) -inkey $(realpath ~/.ctctl/${INSTALL_DOMAIN}/${UTIL}/cli.key) -passout pass:${UTIL}"
}
}
_EOF
done
source ~/.bashrc
echo
echo
echo ----------------------------------------------------------
echo Installation done. You can now switch to your new env with
echo ctctl switch ${INSTALL_DOMAIN}
echo
echo Then authenticate using
echo ctctl auth
echo
echo ----------------------------------------------------------