#!/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 ----------------------------------------------------------