Move ctctl to its own repo

This commit is contained in:
Daniel Berteaud 2023-07-05 15:28:07 +02:00
parent c0da6d17e8
commit 007cdfe413
17 changed files with 1053 additions and 0 deletions

28
bash_completion Normal file
View File

@ -0,0 +1,28 @@
_ctctl(){
local cur prev
_init_completion || return
case $prev in
auth|disconnect|prep|current|tokens|list|volumes|logs|conf)
return
;;
build|build-no-cache)
COMPREPLY=($(compgen -W "$(
(
for JOB in $(find . -maxdepth 1 \( -name \*.nomad -o -name \*.nomad.hcl \)); do
nomad run -output $JOB | jq '.Job.TaskGroups' | jq '.[] | .Tasks' | jq -r '.[] | .Config.image' 2>/dev/null;
done
) | perl -ne 'print "$1 " if /^oci\.ehtrace\.com\/([^:]+):.*/' | sort -u)
" -- $cur))
return
;;
switch)
COMPREPLY=($(compgen -W "$(ls -1 ~/.ctctl/*/bashrc | xargs dirname | xargs basename -a)" -- "$cur"))
return
;;
esac
COMPREPLY=($(compgen -W 'auth switch current disconnect prep tokens list build build-no-cache volumes logs conf' -- "$cur"))
} &&
complete -F _ctctl ctctl

503
ctctl Executable file
View File

@ -0,0 +1,503 @@
#!/usr/bin/env bash
# Print current environnement
current_env(){
if [ -z "${CT_DOMAIN}" ]; then
echo "Unknown container domain"
kill -INT $$
fi
echo "${CT_DOMAIN}"
if [ -z "${CT_ENV}" ]; then
echo "Unknown container environment"
fi
}
check_env() {
if [ -n "${CT_DOMAIN}" -a -n "${CT_ENV}" ]; then
echo 1
else
echo 0
fi
}
# Switch to a target environment (either from no current, or from another current env)
switch_env(){
TARGET_DOM=$1
TARGET_ENV=$2
if [ -z "${TARGET_DOM}" ]; then
echo "Select the container install you want to work on"
select T_DOM in $(ls_env); do
if [ "${REPLY}" -ge 1 ] && [ "${REPLY}" -le $(ls_env | wc -w) ]; then
TARGET_DOM=${T_DOM}
break
else
echo "Invalid selection"
fi
done
elif [ ! -e ~/.ctctl/${TARGET_DOM}/bashrc ]; then
echo "Env ${TARGET_DOM} doesn't exist"
kill -INT $$
fi
for VAR in $(printenv | perl -ne 'print if /^(CONSUL|VAULT|NOMAD).*/' | cut -d= -f1); do
unset $VAR
done
mkdir -p ~/.bashrc.d
cp -f ~/.ctctl/${TARGET_DOM}/bashrc ~/.bashrc.d/ctctl
source ~/.bashrc.d/ctctl
if [ -z "${TARGET_ENV}" ]; then
echo "Select the env you are working in"
select T_ENV in $(echo -n ${CT_VALID_ENV} | sed 's/,/ /g'); do
if [ "${REPLY}" -ge 1 ] && [ "${REPLY}" -le $(echo -n ${CT_VALID_ENV} | sed 's/,/ /g' | wc -w) ]; then
TARGET_ENV=${T_ENV}
break
else
echo "Invalid selection, please select the env you'll be working in"
fi
done
fi
export CT_ENV=${TARGET_ENV}
export NOMAD_VAR_env=${TARGET_ENV}
case ${CT_ENV} in
prd|PRD|production)
COLOR="1;31" # Red
;;
stg|STG|stage|staging)
COLOR="1;33" # Yellow/Orange
;;
qa|qal|QA|QAL)
COLOR="1;35" # Purple
;;
dev|DEV|devel)
COLOR="1;36" # Cyan
;;
*)
COLOR="1;32" # Green
;;
esac
auth_env
export PS1="[${CT_DOMAIN} \[\e[${COLOR}m\](${CT_ENV})\[\e[m\] \W]\$ "
}
# Check if we have a valid token for vault
check_vault_token(){
vault read auth/token/lookup-self > /dev/null 2>&1
if [ $? == 0 ]; then
echo 1
else
echo 0
fi
}
# Check if we have a valid token for consul
check_consul_token(){
CONSUL_TOKEN_VALID=0
if [ -n "${CONSUL_HTTP_TOKEN}" ]; then
consul acl token read -self > /dev/null 2>&1
if [ $? == 0 ]; then
echo 1
else
echo 0
fi
else
echo 0
fi
}
# Check if we have a valid token for nomad
check_nomad_token(){
if [ -n "${NOMAD_TOKEN}" ]; then
nomad acl token self > /dev/null 2>&1
if [ $? == 0 ]; then
echo 1
else
echo 0
fi
else
echo 0
fi
}
# Auth on vault, consul and nomad on the current env
auth_env(){
if [ -z "${CT_DOMAIN}" ]; then
echo "Unknown environment"
kill -INT $$
fi
if [ "$(check_vault_token)" != "1" ]; then
echo "Vous n'êtes pas encore connecté sur vault. Saisissez votre mot de passe de domaine"
vault login -field=token_accessor -method=ldap username=${ME} || kill -INT $$
else
echo "Le token vault actuel est valide"
vault token renew > /dev/null 2>&1
fi
VAULT_TOKEN_INFO=$(vault read -format=json auth/token/lookup-self)
if [ "$(echo $VAULT_TOKEN_INFO | jq '.data.policies | any(. == "admin-policy")')" == "true" ]; then
NOMAD_ROLE=admin
CONSUL_ROLE=admin
else
NOMAD_ROLE=user
CONSUL_ROLE=user
fi
# Root CA
vault read -field certificate pki/root/cert/ca > ~/.ctctl/${CT_DOMAIN}/root_ca.crt
# Consul certificate
# Get/renew cert if required.
# Note 1: as the template is using pkiCert, the cert won't be renewed, unless necessary
# Note 2: don't pass CONSUL_CLIENT_CERT CONSUL_CLIENT_KEY and CONSUL_CACERT because they would prevent consul-template
# to get/renew the cert if they are absent, or expired
env -u CONSUL_CLIENT_CERT -u CONSUL_CLIENT_KEY -u CONSUL_CACERT consul-template -config ~/.ctctl/${CT_DOMAIN}/consul/consul-template.hcl -once
# Get/renew cert for Nomad now
consul-template -config ~/.ctctl/${CT_DOMAIN}/nomad/consul-template.hcl -once
# Check if we have a valid nomad token already
if [ "$(check_nomad_token)" != "1" ]; then
echo "Obtention d'un token pour Nomad"
export NOMAD_TOKEN=$(vault read -field=secret_id nomad/creds/${NOMAD_ROLE})
else
echo "Le token Nomad actuel est valide"
fi
# Check if we have a valid consul token already
if [ "$(check_consul_token)" != "1" ]; then
echo "Obtention d'un token pour Consul"
export CONSUL_HTTP_TOKEN=$(vault read -field=token consul/creds/${CONSUL_ROLE})
else
echo "Le token Consul actuel est valide"
fi
# Now setup loki
LOKI_PASSWORD=$(vault kv get -field pwd $(get_conf "vault_kv_mount")/admin/loki 2>&1)
if [ $? == 0 ]; then
export LOKI_PASSWORD
export LOKI_ADDR=https://$(get_conf "tools_vhost")/loki
export LOKI_USERNAME=loki
else
unset LOKI_PASSWORD
fi
}
# Logout from the current env
logout_env(){
if [ -z "${CT_DOMAIN}" ]; then
echo "Unknown environment"
kill -INT $$
fi
echo Loging out of ${CT_DOMAIN} environment
vault token revoke -self
for VAR in $(printenv | perl -ne 'print if /^(CONSUL|VAULT|NOMAD|LOKI).*/' | cut -d= -f1); do
unset $VAR
done
unset CT_DOMAIN
unset ME
rm -f ~/.vault-token
rm -f ~/.bashrc.d/ctctl
}
# List available env
ls_env(){
find ~/.ctctl/ -name bashrc | xargs dirname | xargs basename -a
}
# Load policies for vault, Consul and Nomad
load_policies(){
if [ "$(check_env)" = "0" ]; then
echo "Not currently in a valid env. Run ctctl (with no argument) and select your env first"
kill -INT $$
fi
if [ -d "./vault/policies" ]; then
if [ "$(check_vault_token)" != "1" ]; then
echo "No valid vault token. You have to authenticate first"
kill -INT $$
fi
for PFILE in $(ls ./vault/policies/*.hcl 2>/dev/null); do
PNAME=$(basename ${PFILE} .hcl)$(get_conf "env_suffix")
echo "Loading vault policy ${PNAME}"
replace_conf_var ${PFILE} | vault policy write ${PNAME} -
done
fi
if [ -d "./consul/policies" ]; then
if [ "$(check_consul_token)" != "1" ]; then
echo "No valid consul token. You have to authenticate first"
kill -INT $$
fi
CONSUL_CUR_POLICIES=$(consul acl policy list -format=json)
for PFILE in $(ls ./consul/policies/*.hcl 2>/dev/null); do
PNAME=$(basename ${PFILE} .hcl)$(get_conf "env_suffix")
# Consul do not use the same command to create a new policy and to update an existing one
# so we need to detect if the policy already exists
if [ "$(echo ${CONSUL_CUR_POLICIES} | jq -r '.[] | select(.Name=='\"${PNAME}\"') | .Name')" == "${PNAME}" ]; then
echo "Updating consul policy ${PNAME}"
replace_conf_var ${PFILE} | consul acl policy update -name=${PNAME} -rules=-
else
echo "Adding new consul policy ${PNAME}"
replace_conf_var ${PFILE} | consul acl policy create -name=${PNAME} -rules=-
fi
done
fi
if [ -d "./nomad/policies" ]; then
if [ "$(check_nomad_token)" != "1" ]; then
echo "No valid nomad token. You have to authenticate first"
kill -INT $$
fi
for PFILE in $(ls ./nomad/policies/*.hcl 2>/dev/null); do
PNAME=$(basename ${PFILE} .hcl)$(get_conf "env_suffix")
echo "Loading Nomad policy ${PNAME}"
replace_conf_var ${PFILE} | nomad acl policy apply ${PNAME} -
done
fi
}
# Load consul services
load_consul_services(){
if [ -d "./consul/services" ]; then
if [ "$(check_consul_token)" != "1" ]; then
echo "No valid consul token. You have to authenticate first"
kill -INT $$
fi
for FILE in $(ls ./consul/services/*.hcl 2>/dev/null); do
echo "Registering service from ${FILE}"
TEMP=$(mktemp).hcl
replace_conf_var ${FILE} > ${TEMP}
consul services register ${TEMP}
rm -f ${TEMP}
done
fi
}
# Load consul config
load_consul_conf(){
if [ -d "./consul/config" ]; then
if [ "$(check_consul_token)" != "1" ]; then
echo "No valid consul token. You have to authenticate first"
kill -INT $$
fi
# Note : service-defaults should be loaded before the others
# but that should be the case
for FILE in $(ls ./consul/config/*.hcl 2>/dev/null); do
echo "Loading consul conf from ${FILE}"
TEMP=$(mktemp)
replace_conf_var ${FILE} > ${TEMP}
consul config write ${TEMP}
rm -f ${TEMP}
done
fi
}
# Build Docker images
build_images(){
IMAGE=$1
FORCE=$2
NO_CACHE=$3
export DOCKER_BUILDKIT=1
export EHT_MAVEN_PWD=$(vault kv get -field=pwd $(get_conf "vault_kv_mount")/admin/maven)
for DOCKER_IMAGE in $(
(for JOB in $(find . -maxdepth 1 \( -name \*.nomad -o -name \*.nomad.hcl \)); do
nomad run -output $JOB | jq '.Job.TaskGroups' | jq '.[] | .Tasks' | jq -r '.[] | .Config.image' 2>/dev/null
done) | perl -ne 'print if /^oci\.ehtrace\.com.*/' | sort -u); do
if [ "x$FORCE" != "x" ] || ! docker manifest inspect ${DOCKER_IMAGE} > /dev/null 2>&1; then
echo "Building image ${DOCKER_IMAGE}"
DIR=${DOCKER_IMAGE#oci.ehtrace.com/}
DIR=${DIR%:*}
if [ "x${IMAGE}" != "x" -a "${DIR}" != "${IMAGE}" ]; then
echo "Skipping ${DIR}"
else
export DOCKER_IMAGE=${DOCKER_IMAGE}
LATEST=$(echo ${DOCKER_IMAGE} | sed 's/:.*/:latest/')
if [ "${NO_CACHE}" != "" ]; then
NO_CACHE="--no-cache"
else
NO_CACHE=""
fi
docker build ${NO_CACHE} -t ${DOCKER_IMAGE} -t ${LATEST} --secret id=EHT_MAVEN_PWD --progress=plain images/$DIR &&
docker push ${DOCKER_IMAGE}
docker push ${LATEST}
fi
else
echo "Image ${DOCKER_IMAGE} already available"
fi
done
unset DOCKER_BUILDKIT
unset EHT_MAVEN_PWD
}
# Run all executable in the prep.d directory
handle_prep_scripts(){
if [ -d prep.d ]; then
for H in $(find prep.d -type f -o -type l | sort); do
if [ -x "${H}" ]; then
echo "Running script ${H}"
$H $1
else
echo "Skiping $H (not executable)"
fi
done
fi
}
# Render templates using levant
render_templates(){
MERGED_CONF=$(mktemp tmp.XXXXXXXX.yml)
get_merged_conf > ${MERGED_CONF}
handle_prep_scripts ${MERGED_CONF}
for TEMPLATE in $(find . -type f -name \*.tpl ! -path "*templates/*"); do
DIR=$(dirname ${TEMPLATE})
FILE=$(basename ${TEMPLATE} .tpl)
DEST=${DIR}/${FILE}
echo "Rendering ${TEMPLATE} into ${DEST}"
levant render -var-file ${MERGED_CONF} -log-level=WARN ${TEMPLATE} > ${DEST}
nomad fmt ${DEST}
done
rm -f ${MERGED_CONF}
}
# Print Consul and Nomad tokens (not vault, for security reasons)
print_tokens(){
if [ "$(check_nomad_token)" == "1" ]; then
echo "Nomad token: ${NOMAD_TOKEN}"
else
echo "No valid Nomad token, you should auth with ctctl auth"
fi
if [ "$(check_consul_token)" == "1" ]; then
echo "Consul token: ${CONSUL_HTTP_TOKEN}"
else
echo "No valid Consul token, you should auth with ctctl auth"
fi
}
# Handle CSI volumes definition
handle_volumes(){
if [ -d ./volumes ]; then
for FILE in $(ls ./volumes/*.hcl 2>/dev/null); do
echo "Handling volume definition ${FILE}"
# Linstor volumes are just registered, while the other are created
if [[ "$FILE" =~ ^linstor-.* ]]; then
replace_conf_var ${FILE} | nomad volume register -
else
replace_conf_var ${FILE} | nomad volume create -
fi
done
fi
}
# Follow current jobs logs
job_logs(){
# Remove the first arg passed to ctctl, which is logs
shift
local SELECTOR
local LOGCLI_CMD
LOGCLI_CMD="logcli query --include-label=job --include-label=group --include-label=task"
echo -n "$*" | grep -qP '\{.+\}' >/dev/null 2>&1
# If a logcli filter was given, use it. Else, build one for jobs in the current dir
if [ $? == 0 ]; then
echo "Running ${LOGCLI_CMD} $@"
${LOGCLI_CMD} $@
else
# Build a job name selection string like job1|job2|job3 etc.
for JOB in $(find . -maxdepth 1 \( -name \*.nomad -o -name \*.nomad.hcl \)); do
SELECTOR=$SELECTOR"|"$(nomad run -output $JOB | jq -r '.Job.Name')
done
# We need to remove the leading |
# Exclude connect-proxy logs as it's often not wanted
SELECTOR='{job=~"'$(echo -n ${SELECTOR} | sed -e 's/^|//')'", task!~"connect-proxy-.+|tls-proxy|metrics-proxy"}'
echo "Running ${LOGCLI_CMD} $@ ${SELECTOR}"
${LOGCLI_CMD} $@ "${SELECTOR}"
fi
}
### Helpers ###
# Merge the configuration files for the current env and return the result (as string)
get_merged_conf() {
CONF_FILES=""
if [ -e "./vars/defaults.yml" ]; then
CONF_FILES="./vars/defaults.yml"
fi
if [ -e "jobs/common/vars/${CT_ENV}.yml" ]; then
CONF_FILES="${CONF_FILES} jobs/common/vars/${CT_ENV}.yml"
fi
if [ -e "../common/vars/${CT_ENV}.yml" ]; then
CONF_FILES="${CONF_FILES} ../common/vars/${CT_ENV}.yml"
fi
if [ -e "./vars/${CT_ENV}.yml" ]; then
CONF_FILES="${CONF_FILES} ./vars/${CT_ENV}.yml"
fi
if [ "${CONF_FILES}" != "" ]; then
echo "---"
yq ea '. as $item ireduce ({}; . * $item | ... comments="")' $CONF_FILES
else
echo -n ""
fi
}
# Replace ${local.conf.foo} or ${foo} with the value of foo from the various merged configuration files
# This is used to have policies (vault, consul, nomad) and config (consul intentions etc.) with variables
replace_conf_var() {
MERGED_CONF=$(mktemp)
get_merged_conf > $MERGED_CONF
RES=$(cat $1 | \
# Replace ${local.conf.foo} or ${foo} with the value of foo from the various merged configuration files \
# This is used to have policies (vault, consul, nomad) and config (consul intentions etc.) with variables \
perl -pe 'sub replace($) { my $val = shift; chomp(my $res = qx(yq .$val '$MERGED_CONF')); return $res; }; s!\$\{(local\.conf\.)?([^\}]+)\}! replace($2) !ge' | \
# Replace $(foo) with the output of foo command, mainly used to fetch secrets from vault \
perl -pe 'sub replace($) { my $val = shift; chomp(my $res = qx($val)); return $res; }; s!\$\(([^\)]+)\)! replace($1) !ge'
)
rm -f $MERGED_CONF
echo "${RES}"
}
# Get a value from the conf
get_conf(){
get_merged_conf | yq ".$1"
}
case $1 in
current)
current_env
;;
auth)
auth_env
;;
disconnect)
logout_env
;;
ls|list)
ls_env
;;
prep)
render_templates
load_policies
load_consul_services
load_consul_conf
build_images
;;
volumes)
handle_volumes
;;
build)
build_images "$2" "force"
;;
build-no-cache)
build_images "$2" "force" "no-cache"
;;
tokens)
print_tokens
;;
logs)
job_logs "$@"
;;
conf)
get_merged_conf
;;
*)
switch_env "$@"
;;
esac

227
install.sh Executable file
View File

@ -0,0 +1,227 @@
#!/usr/bin/env bash
BIN_DIR=~/bin
DEFAULT_ME=${ME:-$(whoami | sed -r 's/\@.*//')}
DEFAULT_DOM=${CT_DOMAIN:-ct.$(hostname -f | sed -r 's/^[^\.]+\.(.*)/\1/')}
DEFAULT_VALID_ENV=${CT_VALID_ENV:-default}
read -p "Saisissez votre nom d'utilisateur [${DEFAULT_ME}] " INSTALL_ME
INSTALL_ME=${INSTALL_ME:-${DEFAULT_ME}}
read -p "Saisissez le domaine utilisé pour les containers [${DEFAULT_DOM}] " INSTALL_CT_DOMAIN
INSTALL_CT_DOMAIN=${INSTALL_CT_DOMAIN:-${DEFAULT_DOM}}
read -p "Saisissez la liste des environements valides (poc,dev,stg,prd etc.) [${DEFAULT_VALID_ENV}] " INSTALL_VALID_ENV
INSTALL_VALID_ENV=${INSTALL_VALID_ENV:-${DEFAULT_VALID_ENV}}
function get_gh_release() {
echo $(curl --silent "https://api.github.com/repos/$1/releases/latest" | \
jq -r .tag_name | perl -pe 's/^v//')
}
# Detect OS
SYSTEM="$(uname -s)"
case "${SYSTEM}" in
Linux*) MACHINE=linux;;
Darwin*) MACHINE=darwin;;
*) MACHINE=unknown;;
esac
if [ "${MACHINE}" = "unknown" ]; then
echo "Système non supporté"
exit 1
fi
# Check that we have the required utilities
for TOOL in jq openssl curl unzip; do
if ! command -v $TOOL > /dev/null 2>&1; then
echo "$TOOL not found."
exit 1
fi
done
[ -d ${BIN_DIR} ] || mkdir -p ${BIN_DIR}
# Install hashicorp binaries
for UTIL in vault consul consul-template nomad levant; do
LAST_VER=$(get_gh_release "hashicorp/${UTIL}")
echo La dernière version de ${UTIL} est v${LAST_VER}
if [ -x "${BIN_DIR}/${UTIL}" ]; then
CUR_VER=$(${BIN_DIR}/${UTIL} --version | perl -ne "/^${UTIL} v(\d+(\.\d+)*)/i && print \"\$1\"")
echo ${UTIL} est installé en version v${CUR_VER}
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo Installation de ${UTIL} v${LAST_VER}
curl -L -O https://releases.hashicorp.com/${UTIL}/${LAST_VER}/${UTIL}_${LAST_VER}_${MACHINE}_amd64.zip
unzip -o -d ~/bin/ ${UTIL}_${LAST_VER}_${MACHINE}_amd64.zip
rm -f ${UTIL}_${LAST_VER}_${MACHINE}_amd64.zip
else
echo "La dernière version (v${CUR_VER}) de ${UTIL} est déjà installée"
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 | perl -ne "/version (\d+(\.\d+)*)/i && print \"\$1\"")
echo ${UTIL} est installé en version v${CUR_VER}
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo Installation de ${UTIL} v${LAST_VER}
curl -L -O https://github.com/grafana/loki/releases/download/v${LAST_VER}/logcli-${MACHINE}-amd64.zip
unzip -o -d ~/bin/ ${UTIL}-${MACHINE}-amd64.zip
rm -f ${UTIL}-${MACHINE}-amd64.zip
mv -f ~/bin/logcli-${MACHINE}-amd64 ~/bin/logcli
else
echo "La dernière version (v${CUR_VER}) de ${UTIL} est déjà installée"
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 | perl -ne "/version v(\d+(\.\d+)*)/i && print \"\$1\"")
echo ${UTIL} est installé en version v${CUR_VER}
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo Installation de ${UTIL} v${LAST_VER}
curl -L -o ${BIN_DIR}/yq https://github.com/mikefarah/yq/releases/download/v${LAST_VER}/yq_${MACHINE}_amd64
chmod +x ${BIN_DIR}/yq
else
echo "La dernière version (v${CUR_VER}) de ${UTIL} est déjà installée"
fi
done
# Install p2cli
for UTIL in p2cli; do
LAST_VER=$(get_gh_release "mdouchement/p2cli")
if [ -x "${BIN_DIR}/${UTIL}" ]; then
CUR_VER=$(${BIN_DIR}/${UTIL} --version 2>&1 | perl -ne "/version (\d+(\.\d+)*)/i && print \"\$1\"")
echo ${UTIL} est installé en version v${CUR_VER}
fi
if [ ! -x "${BIN_DIR}/${UTIL}" ] || ! echo -e "${LAST_VER}\n${CUR_VER}" | sort --version-sort --check > /dev/null 2>&1; then
echo Installation de ${UTIL} v${LAST_VER}
curl -L -o ${BIN_DIR}/p2cli https://github.com/mdouchement/p2cli/releases/download/v${LAST_VER}/p2cli-${MACHINE}-amd64
chmod +x ${BIN_DIR}/p2cli
else
echo "La dernière version (v${CUR_VER}) de ${UTIL} est déjà installée"
fi
done
echo "Vérification du login sur vault"
export VAULT_ADDR=https://active.vault.service.${INSTALL_CT_DOMAIN}:8200
vault read auth/token/lookup-self > /dev/null 2>&1
if [ $? != 0 ]; then
echo "Vous n'êtes pas encore connecté sur vault. Saisissez votre mot de passe de domaine"
vault login -method=ldap username=${INSTALL_ME}
fi
mkdir -p ~/.bashrc.d
mkdir -p ~/.ctctl/${INSTALL_CT_DOMAIN}
mkdir -p ~/.ctctl/bin
source ~/.bashrc
PREV_IFS=$IFS
DIR_IN_PATH=0
export IFS=":"
for P in $PATH; do
[ "$P" = "~/bin" -o "$P" = "$(realpath ~/bin)" ] && DIR_IN_PATH=1
done
export IFS=$PREV_IFS
echo "Configuration de l'environnement général"
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/*
cat <<_EOF > ~/.ctctl/${INSTALL_CT_DOMAIN}/bashrc
export ME=${INSTALL_ME}
export CT_DOMAIN=${INSTALL_CT_DOMAIN}
export CT_VALID_ENV=${INSTALL_VALID_ENV}
_EOF
cat << '_EOF' > ~/.bashrc.d/hashistack
complete -C ~/bin/vault vault
complete -C ~/bin/nomad nomad
complete -C ~/bin/consul consul
eval "$(logcli --completion-script-bash)"
alias ctctl='source ~/.ctctl/bin/ctctl'
source ~/.local/share/bash-completion/completions/ctctl
_EOF
[ "${DIR_IN_PATH}" = "0" ] && cat <<_EOF >> ~/.bashrc.d/ctctl
export PATH=$(realpath ~/bin):$PATH
_EOF
source ~/.bashrc.d/ctctl
echo "Configuration de l'environnement pour Vault"
cat <<_EOF >> ~/.ctctl/${INSTALL_CT_DOMAIN}/bashrc
export VAULT_ADDR=https://active.vault.service.${INSTALL_CT_DOMAIN}:8200
_EOF
echo "Configuration de l'environnement pour Nomad"
cat <<_EOF >> ~/.ctctl/${INSTALL_CT_DOMAIN}/bashrc
export NOMAD_ADDR=https://nomad.service.${INSTALL_CT_DOMAIN}:4646
export NOMAD_CACERT=~/.ctctl/${INSTALL_CT_DOMAIN}/nomad/ca.crt
export NOMAD_CLIENT_CERT=~/.ctctl/${INSTALL_CT_DOMAIN}/nomad/cli.crt
export NOMAD_CLIENT_KEY=~/.ctctl/${INSTALL_CT_DOMAIN}/nomad/cli.key
_EOF
echo "Configuration de l'environnement pour Consul"
cat <<_EOF >> ~/.ctctl/${INSTALL_CT_DOMAIN}/bashrc
export CONSUL_HTTP_ADDR=https://consul.service.${INSTALL_CT_DOMAIN}:8501
export CONSUL_CACERT=~/.ctctl/${INSTALL_CT_DOMAIN}/consul/ca.crt
export CONSUL_CLIENT_CERT=~/.ctctl/${INSTALL_CT_DOMAIN}/consul/cli.crt
export CONSUL_CLIENT_KEY=~/.ctctl/${INSTALL_CT_DOMAIN}/consul/cli.key
_EOF
# Install the certificate renewer scripts
for UTIL in nomad consul; do
mkdir -p ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}
# Create the files so realpath do not 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_CT_DOMAIN}/${UTIL}/${FILE}
done
cat <<_EOF > ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/bundle.pem.tpl
{{ with pkiCert "pki/${UTIL}/issue/${UTIL}-user" "common_name=${INSTALL_ME}.${UTIL}.${INSTALL_CT_DOMAIN}" "ttl=8760h" }}
{{ .CA }}
{{ .Cert }}
{{ .Key }}
{{ .CA | writeToFile "$(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/ca.crt)" "" "" "0644" }}
{{ .Cert | writeToFile "$(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/cli.crt)" "" "" "0644" }}
{{ .Key | writeToFile "$(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/cli.key)" "" "" "0600" }}
{{ end }}
_EOF
cat <<_EOF > ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/consul-template.hcl
template {
source = "$(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/bundle.pem.tpl)"
destination = "$(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/bundle.pem)"
perms = 0640
exec {
command = "openssl pkcs12 -export -out $(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/cli.p12) -in $(realpath ~/.ctctl/${INSTALL_CT_DOMAIN}/${UTIL}/cli.crt) -inkey $(realpath ~/.ctctl/${INSTALL_CT_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_CT_DOMAIN}
echo
echo Then authenticate using
echo ctctl auth
echo
echo ----------------------------------------------------------

68
vault/policies/admin.hcl Normal file
View File

@ -0,0 +1,68 @@
# Read system health check
path "sys/health" {
capabilities = ["read", "sudo"]
}
path "sys/metrics" {
capabilities = ["read", "list"]
}
# Create and manage ACL policies broadly across Vault
# List existing policies
path "sys/policies/acl" {
capabilities = ["list"]
}
# Create and manage ACL policies
path "sys/policies/acl/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Enable and manage authentication methods broadly across Vault
# Manage auth methods broadly across Vault
path "auth/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Create, update, and delete auth methods
path "sys/auth/*" {
capabilities = ["create", "update", "delete", "sudo"]
}
# List auth methods
path "sys/auth" {
capabilities = ["read"]
}
# Enable and manage the key/value secrets engine at `secret/` path
# List, create, update, and delete key/value secrets
path "kv/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo", "patch"]
}
# Same for PKI
path "/pki/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "/consul/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "/nomad/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage secrets engines
path "sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List existing secrets engines.
path "sys/mounts" {
capabilities = ["read"]
}

View File

@ -0,0 +1,3 @@
path "sys/storage/raft/snapshot" {
capabilities = ["read"]
}

View File

@ -0,0 +1,3 @@
path "pki/consul/cert/ca" {
capabilities = ["read"]
}

View File

@ -0,0 +1,40 @@
path "/sys/mounts" {
capabilities = [ "read" ]
}
path "/sys/mounts/pki/root" {
capabilities = [ "read" ]
}
path "/sys/mounts/pki/connect" {
capabilities = [ "read" ]
}
path "/sys/mounts/pki/connect/tune" {
capabilities = ["update", "read", "create"]
}
path "/pki/root/" {
capabilities = [ "read" ]
}
path "/pki/root/root/sign-intermediate" {
capabilities = [ "update" ]
}
path "/pki/connect/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
path "/pki/consul/issue/consul-server" {
capabilities = [ "update" ]
}
path "auth/token/renew-self" {
capabilities = [ "update" ]
}
path "auth/token/lookup-self" {
capabilities = [ "read" ]
}

View File

@ -0,0 +1,3 @@
path "pki/consul/issue/consul-user" {
capabilities = ["update"]
}

101
vault/policies/default.hcl Normal file
View File

@ -0,0 +1,101 @@
# Allow tokens to look up their own properties
path "auth/token/lookup-self" {
capabilities = ["read"]
}
# Allow tokens to renew themselves
path "auth/token/renew-self" {
capabilities = ["update"]
}
# Allow tokens to revoke themselves
path "auth/token/revoke-self" {
capabilities = ["update"]
}
# Allow a token to look up its own capabilities on a path
path "sys/capabilities-self" {
capabilities = ["update"]
}
# Allow a token to look up its own entity by id or name
path "identity/entity/id/{{identity.entity.id}}" {
capabilities = ["read"]
}
path "identity/entity/name/{{identity.entity.name}}" {
capabilities = ["read"]
}
# Allow a token to look up its resultant ACL from all policies. This is useful
# for UIs. It is an internal path because the format may change at any time
# based on how the internal ACL features and capabilities change.
path "sys/internal/ui/resultant-acl" {
capabilities = ["read"]
}
# Allow a token to renew a lease via lease_id in the request body; old path for
# old clients, new path for newer
path "sys/renew" {
capabilities = ["update"]
}
path "sys/leases/renew" {
capabilities = ["update"]
}
# Allow looking up lease properties. This requires knowing the lease ID ahead
# of time and does not divulge any sensitive information.
path "sys/leases/lookup" {
capabilities = ["update"]
}
# Allow a token to manage its own cubbyhole
path "cubbyhole/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Allow a token to wrap arbitrary values in a response-wrapping token
path "sys/wrapping/wrap" {
capabilities = ["update"]
}
# Allow a token to look up the creation time and TTL of a given
# response-wrapping token
path "sys/wrapping/lookup" {
capabilities = ["update"]
}
# Allow a token to unwrap a response-wrapping token. This is a convenience to
# avoid client token swapping since this is also part of the response wrapping
# policy.
path "sys/wrapping/unwrap" {
capabilities = ["update"]
}
# Allow general purpose tools
path "sys/tools/hash" {
capabilities = ["update"]
}
path "sys/tools/hash/*" {
capabilities = ["update"]
}
# Allow checking the status of a Control Group request if the user has the
# accessor
path "sys/control-group/request" {
capabilities = ["update"]
}
# Allow a token to make requests to the Authorization Endpoint for OIDC providers.
path "identity/oidc/provider/+/authorize" {
capabilities = ["read", "update"]
}
# Anyone can read the various CA certificates
path "/pki/+/cert/ca" {
capabilities = ["read"]
}
# Same for CRL
path "/pki/+/cert/crl" {
capabilities = ["read"]
}

View File

@ -0,0 +1,3 @@
path "pki/monitoring/issue/metrics" {
capabilities = ["update"]
}

View File

@ -0,0 +1,4 @@
# Read system health check
path "sys/health" {
capabilities = ["read"]
}

View File

@ -0,0 +1,8 @@
# Obtain client cert for Nomad
path "pki/nomad/issue/nomad-client" {
capabilities = ["update"]
}
# Obtain client cert for Consul
path "pki/consul/issue/nomad-client" {
capabilities = ["update"]
}

View File

@ -0,0 +1,43 @@
# Allow creating tokens under "nomad-cluster" token role. The token role name
# should be updated if "nomad-cluster" is not used.
path "auth/token/create/nomad-cluster" {
capabilities = ["update"]
}
# Allow looking up "nomad-cluster" token role. The token role name should be
# updated if "nomad-cluster" is not used.
path "auth/token/roles/nomad-cluster" {
capabilities = ["read"]
}
# Allow looking up the token passed to Nomad to validate the token has the
# proper capabilities. This is provided by the "default" policy.
path "auth/token/lookup-self" {
capabilities = ["read"]
}
# Allow looking up incoming tokens to validate they have permissions to access
# the tokens they are requesting. This is only required if
# `allow_unauthenticated` is set to false.
path "auth/token/lookup" {
capabilities = ["update"]
}
# Allow revoking tokens that should no longer exist. This allows revoking
# tokens for dead tasks.
path "auth/token/revoke-accessor" {
capabilities = ["update"]
}
# Allow checking the capabilities of our own token. This is used to validate the
# token upon startup. Note this requires update permissions because the Vault API
# is a POST
path "sys/capabilities-self" {
capabilities = ["update"]
}
# Allow our own token to be renewed.
path "auth/token/renew-self" {
capabilities = ["update"]
}

View File

@ -0,0 +1,3 @@
path "nomad/config/access" {
capabilities = ["create","update"]
}

View File

@ -0,0 +1,7 @@
path "pki/nomad/issue/nomad-server" {
capabilities = ["update"]
}
# Obtain client cert for Consul
path "pki/consul/issue/nomad-client" {
capabilities = ["update"]
}

View File

@ -0,0 +1,3 @@
path "pki/nomad/issue/nomad-user" {
capabilities = ["update"]
}

6
vault/policies/user.hcl Normal file
View File

@ -0,0 +1,6 @@
path "consul/creds/user" {
capabilities = ["read"]
}
path "nomad/creds/user" {
capabilities = ["read"]
}