From e0c40eaadade9e8ebc5e45ecab74f31c15192fe1 Mon Sep 17 00:00:00 2001 From: Yugonito Date: Tue, 25 Aug 2026 14:26:36 +0200 Subject: [PATCH] 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. --- README.md | 32 +++++++ bootstrap.sh | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 README.md create mode 100644 bootstrap.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..73a1b1f --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# fait-zabbix-public + +Ce dépôt ne contient qu'une chose : **`bootstrap.sh`**, le script qui enrôle une +machine dans la supervision Forget About IT. + +Il est public parce qu'il doit être récupérable sans identifiant — c'est ce qui +permet à la ligne d'enrôlement de tenir en une commande. Il ne contient **aucun +secret** par construction : le jeton du client lui arrive par l'environnement, +jamais par le fichier. + +## Enrôler une machine + +``` +curl -fsSL https://git.fabout.it/hcloez/fait-zabbix-public/raw/branch/main/bootstrap.sh \ + | sudo FAIT_CLIENT= FAIT_TOKEN= bash +``` + +La même ligne vaut pour toutes les machines d'un même client. + +Le jeton passe alors par la ligne de commande, donc visible dans `ps` le temps +de l'exécution. Sur une machine partagée, préférer : + +``` +sudo FAIT_CLIENT= FAIT_TOKEN_FILE=/chemin/du/jeton bash +``` + +## Ce dépôt est un miroir + +**Ne modifiez rien ici.** La source vit dans le dépôt privé `hcloez/fait-zabbix`, +et une action de CI recopie le script à chaque changement. Une modification faite +ici serait écrasée sans avertissement — et surtout, elle divergerait du paquet +que le script installe. diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100644 index 0000000..d7317de --- /dev/null +++ b/bootstrap.sh @@ -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//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//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}" < "${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}" </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 "$@"