Ajoute bootstrap.sh, miroir du depot prive
Ce depot est public pour que la ligne d enrolement tienne en une commande. Le script ne contient aucun secret: le jeton client arrive par l environnement.
This commit is contained in:
+230
@@ -0,0 +1,230 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export LC_ALL=C
|
||||
|
||||
################################################################################
|
||||
# FAIT Zabbix - Enrolement d un noeud de supervision
|
||||
#
|
||||
# curl -fsSL https://.../bootstrap.sh | sudo FAIT_CLIENT=acme FAIT_TOKEN=xxx bash
|
||||
#
|
||||
# La meme ligne vaut pour toutes les machines d un meme client : rien n est a
|
||||
# personnaliser par machine.
|
||||
#
|
||||
# FAIT_TOKEN sur la ligne de commande ci-dessus finit dans l argv de sudo,
|
||||
# donc dans /proc/<pid>/cmdline, lisible par tout utilisateur local le temps
|
||||
# que la commande tourne. Pour l eviter, ecrire le jeton dans un fichier et
|
||||
# passer FAIT_TOKEN_FILE a la place :
|
||||
#
|
||||
# curl -fsSL https://.../bootstrap.sh | sudo FAIT_CLIENT=acme FAIT_TOKEN_FILE=/root/jeton bash
|
||||
#
|
||||
# FAIT_TOKEN reste accepte pour compatibilite, mais FAIT_TOKEN_FILE est la
|
||||
# forme recommandee des que le jeton n est pas jetable.
|
||||
#
|
||||
# Le noeud ne clone plus le depot. Il recoit un paquet Debian signe, et se met
|
||||
# a jour tout seul ensuite via fait-zabbix-update.timer.
|
||||
################################################################################
|
||||
|
||||
FAIT_CLIENT="${FAIT_CLIENT:-}"
|
||||
FAIT_TOKEN="${FAIT_TOKEN:-}"
|
||||
FAIT_TOKEN_FILE="${FAIT_TOKEN_FILE:-}"
|
||||
|
||||
ZABBIX_MAJOR="${ZABBIX_MAJOR:-7.0}"
|
||||
ZBX_SERVER="${ZBX_SERVER:-sup.fabout.it}"
|
||||
ZBX_SERVER_ACTIVE="${ZBX_SERVER_ACTIVE:-${ZBX_SERVER}}"
|
||||
ZBX_HOSTNAME="${ZBX_HOSTNAME:-}"
|
||||
ZBX_BIND_IP="${ZBX_BIND_IP:-}"
|
||||
|
||||
REPO_HOST="${FAIT_REPO_HOST:-repo.fabout.it}"
|
||||
AUTH_FILE=/etc/apt/auth.conf.d/fait-zabbix.conf
|
||||
KEYRING=/etc/apt/keyrings/fait-supervision.asc
|
||||
SOURCE_LIST=/etc/apt/sources.list.d/fait-zabbix.list
|
||||
CLIENT_FILE=/etc/fait-zabbix/client
|
||||
# Lu par update.sh : si FAIT_REPO_HOST a surcharge le defaut ici, l updater
|
||||
# doit interroger le meme hote, sinon le fichier d authentification (dont la
|
||||
# ligne "machine" vise REPO_HOST) ne correspond plus a l URL interrogee et
|
||||
# les requetes partent sans identifiants.
|
||||
REPO_HOST_FILE=/etc/fait-zabbix/repo-host
|
||||
|
||||
log() { echo "INFO: $*" >&2; }
|
||||
warn() { echo "WARN: $*" >&2; }
|
||||
err() { echo "ERROR: $*" >&2; exit 1; }
|
||||
|
||||
# Les parametres passent avant le controle de root : signaler une variable
|
||||
# oubliee est plus utile que reclamer un sudo quand les deux manquent, et
|
||||
# evite de relancer en root juste pour decouvrir la vraie erreur.
|
||||
[[ -n "${FAIT_CLIENT}" ]] || err "FAIT_CLIENT est obligatoire : le nom du client, tel qu il figure dans le manifeste."
|
||||
|
||||
# FAIT_TOKEN_FILE evite que le jeton apparaisse dans /proc/<pid>/cmdline : on
|
||||
# le lit ici, avant le controle d absence, pour que les deux formes soient
|
||||
# equivalentes au reste du script.
|
||||
if [[ -n "${FAIT_TOKEN_FILE}" ]]; then
|
||||
[[ -r "${FAIT_TOKEN_FILE}" ]] || err "FAIT_TOKEN_FILE illisible : ${FAIT_TOKEN_FILE}"
|
||||
FAIT_TOKEN="$(tr -d ' \t\r\n' < "${FAIT_TOKEN_FILE}")"
|
||||
fi
|
||||
[[ -n "${FAIT_TOKEN}" ]] || err "FAIT_TOKEN (ou FAIT_TOKEN_FILE) est obligatoire : le jeton de lecture du client."
|
||||
[[ "${EUID}" -eq 0 ]] || err "A lancer en root (sudo)."
|
||||
|
||||
[[ -r /etc/os-release ]] || err "/etc/os-release introuvable, distribution non supportee."
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/os-release
|
||||
|
||||
# --- prerequis ----------------------------------------------------------------
|
||||
ensure_prereqs() {
|
||||
local manquants=()
|
||||
# shellcheck disable=SC2043
|
||||
# La boucle ne porte qu un seul outil aujourd hui, mais reste une boucle :
|
||||
# c est la ou un futur prerequis obligatoire s ajouterait, sans reprendre
|
||||
# toute la fonction.
|
||||
for c in curl; do command -v "$c" >/dev/null 2>&1 || manquants+=("$c"); done
|
||||
if [[ ${#manquants[@]} -gt 0 ]] || ! dpkg -s ca-certificates >/dev/null 2>&1; then
|
||||
log "Installation des prerequis : ${manquants[*]:-} ca-certificates"
|
||||
apt-get update -y >/dev/null 2>&1 || true
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||
${manquants[@]+"${manquants[@]}"} ca-certificates >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# --- depot Zabbix officiel ----------------------------------------------------
|
||||
# zabbix-agent2 est une dependance stricte du paquet : sans ce depot, apt
|
||||
# refuserait la transaction entiere.
|
||||
ajouter_depot_zabbix() {
|
||||
if command -v zabbix_agent2 >/dev/null 2>&1; then
|
||||
log "zabbix-agent2 deja installe."
|
||||
return 0
|
||||
fi
|
||||
local dist relver url tmp_deb
|
||||
dist="${ID}"; [[ "${dist}" == "ubuntu" ]] || dist="debian"
|
||||
# Zabbix nomme ses artefacts Ubuntu avec la version complete (ubuntu22.04),
|
||||
# mais Debian avec le seul majeur (debian12) : un relver tronque a la
|
||||
# majeure donnerait ubuntu22, qui n existe pas au depot Zabbix.
|
||||
if [[ "${dist}" == "ubuntu" ]]; then
|
||||
relver="${VERSION_ID}"
|
||||
else
|
||||
relver="${VERSION_ID%%.*}"
|
||||
fi
|
||||
url="https://repo.zabbix.com/zabbix/${ZABBIX_MAJOR}/${dist}/pool/main/z/zabbix-release/zabbix-release_latest+${dist}${relver}_all.deb"
|
||||
log "Ajout du depot Zabbix ${ZABBIX_MAJOR} : ${url}"
|
||||
# Pas de --remove-on-error : absent avant curl 7.83, donc de Debian 11 et
|
||||
# Ubuntu 22.04. On telecharge dans un fichier temporaire et on ne l installe
|
||||
# que si le telechargement a reussi ; un transfert tronque ne passe jamais
|
||||
# a dpkg.
|
||||
tmp_deb="$(mktemp --suffix=.deb)"
|
||||
if ! curl -fsSL -o "${tmp_deb}" "${url}"; then
|
||||
rm -f "${tmp_deb}"
|
||||
err "Telechargement zabbix-release echoue."
|
||||
fi
|
||||
DEBIAN_FRONTEND=noninteractive dpkg -i "${tmp_deb}" >/dev/null
|
||||
rm -f "${tmp_deb}"
|
||||
}
|
||||
|
||||
# --- identifiants du client ---------------------------------------------------
|
||||
poser_identifiants() {
|
||||
install -d -m 0755 /etc/apt/auth.conf.d
|
||||
# Cree en 0600 AVANT toute ecriture : l ecrire puis le restreindre laisserait
|
||||
# le jeton lisible par tous dans l intervalle.
|
||||
install -m 0600 /dev/null "${AUTH_FILE}"
|
||||
cat > "${AUTH_FILE}" <<EOF
|
||||
machine ${REPO_HOST}
|
||||
login ${FAIT_CLIENT}
|
||||
password ${FAIT_TOKEN}
|
||||
EOF
|
||||
install -d -m 0755 /etc/fait-zabbix
|
||||
printf '%s\n' "${FAIT_CLIENT}" > "${CLIENT_FILE}"
|
||||
chmod 0644 "${CLIENT_FILE}"
|
||||
printf '%s\n' "${REPO_HOST}" > "${REPO_HOST_FILE}"
|
||||
chmod 0644 "${REPO_HOST_FILE}"
|
||||
log "Identifiants poses pour le client ${FAIT_CLIENT}."
|
||||
}
|
||||
|
||||
# --- cle de signature ---------------------------------------------------------
|
||||
# L organisation etant privee, la cle n est pas servie anonymement : elle est
|
||||
# recuperee avec les identifiants poses juste avant, jamais passes en argument.
|
||||
# Pas de --remove-on-error (absent avant curl 7.83, donc de Debian 11 et
|
||||
# Ubuntu 22.04) : on telecharge vers un fichier temporaire et on ne le
|
||||
# promeut en cle qu apres coup, ce qui protege pareillement contre un
|
||||
# transfert tronque qui passerait quand meme le controle head -1 ci-dessous.
|
||||
poser_cle() {
|
||||
install -d -m 0755 /etc/apt/keyrings
|
||||
local tmp_cle
|
||||
tmp_cle="$(mktemp)"
|
||||
if ! curl -fsSL --netrc-file "${AUTH_FILE}" \
|
||||
"https://${REPO_HOST}/repository.key" -o "${tmp_cle}"; then
|
||||
rm -f "${tmp_cle}"
|
||||
err "Recuperation de la cle de signature echouee."
|
||||
fi
|
||||
head -1 "${tmp_cle}" | grep -q "BEGIN PGP PUBLIC KEY BLOCK" || {
|
||||
rm -f "${tmp_cle}"
|
||||
err "Le fichier recupere n est pas une cle PGP."
|
||||
}
|
||||
install -m 0644 "${tmp_cle}" "${KEYRING}"
|
||||
rm -f "${tmp_cle}"
|
||||
log "Cle de signature en place."
|
||||
}
|
||||
|
||||
poser_source() {
|
||||
cat > "${SOURCE_LIST}" <<EOF
|
||||
deb [signed-by=${KEYRING}] https://${REPO_HOST} stable main
|
||||
EOF
|
||||
chmod 0644 "${SOURCE_LIST}"
|
||||
}
|
||||
|
||||
# --- conf agent ---------------------------------------------------------------
|
||||
render_conf() {
|
||||
local dest=/etc/zabbix/zabbix_agent2.conf host bind
|
||||
host="${ZBX_HOSTNAME:-$(hostname -f 2>/dev/null || hostname)}"
|
||||
bind="${ZBX_BIND_IP:-$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')}"
|
||||
[[ -n "${bind}" ]] || bind="0.0.0.0"
|
||||
|
||||
[[ -f "${dest}" ]] || { warn "Conf agent absente, elle sera celle du paquet zabbix-agent2."; return 0; }
|
||||
|
||||
local bak; bak="${dest}.bak.$(date +%Y%m%d-%H%M%S 2>/dev/null || echo "$$")"
|
||||
# shellcheck disable=SC2015
|
||||
# log() est un echo qui ne rend jamais un code non nul : le A && B || C
|
||||
# ci-dessous ne peut pas executer C apres un A reussi.
|
||||
cp -a "${dest}" "${bak}" \
|
||||
&& log "Conf existante sauvegardee : ${bak}" \
|
||||
|| warn "Echec de la sauvegarde de ${dest} ; la conf va etre reecrite sans copie."
|
||||
|
||||
sed -i -e "s|^SourceIP=.*|SourceIP=${bind}|" \
|
||||
-e "s|^ListenIP=.*|ListenIP=${bind}|" \
|
||||
-e "s|^Hostname=.*|Hostname=${host}|" \
|
||||
-e "s|^Server=.*|Server=${ZBX_SERVER}|" \
|
||||
-e "s|^ServerActive=.*|ServerActive=${ZBX_SERVER_ACTIVE}|" \
|
||||
"${dest}"
|
||||
log "Conf agent ajustee (Hostname=${host}, Server=${ZBX_SERVER})."
|
||||
}
|
||||
|
||||
ensure_docker_access() {
|
||||
command -v docker >/dev/null 2>&1 || return 0
|
||||
getent group docker >/dev/null 2>&1 || return 0
|
||||
id zabbix >/dev/null 2>&1 || return 0
|
||||
id -nG zabbix 2>/dev/null | tr ' ' '\n' | grep -qx docker && return 0
|
||||
log "Ajout de l utilisateur zabbix au groupe docker."
|
||||
usermod -aG docker zabbix || warn "Echec de l ajout au groupe docker."
|
||||
}
|
||||
|
||||
main() {
|
||||
ensure_prereqs
|
||||
ajouter_depot_zabbix
|
||||
poser_identifiants
|
||||
poser_cle
|
||||
poser_source
|
||||
log "Installation de fait-zabbix..."
|
||||
apt-get update -y >/dev/null
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y fait-zabbix
|
||||
render_conf
|
||||
ensure_docker_access
|
||||
systemctl restart zabbix-agent2 || true
|
||||
|
||||
# Le paquet vient d etre installe a la version la plus recente du depot ;
|
||||
# le manifeste peut en vouloir une autre, ou geler ce client. On converge
|
||||
# donc une fois, tout de suite, plutot que d attendre le premier reveil du
|
||||
# timer et de laisser tourner une version non assignee pendant dix minutes.
|
||||
if [[ -x /usr/lib/fait-zabbix/update.sh ]]; then
|
||||
/usr/lib/fait-zabbix/update.sh || warn "La convergence initiale a echoue ; le timer reessaiera."
|
||||
fi
|
||||
|
||||
log "Enrolement termine. La machine converge desormais seule vers le manifeste."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user