#!/bin/bash # Copyright (C) 2026 Cédric Abonnel # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. set -u SCRIPT_NAME="$(basename "$0")" . /opt/monitoring/lib/monitoring-lib.sh || exit 3 # On s'assure d'avoir les permissions root if [ "${EUID}" -ne 0 ]; then echo "Ce script doit être exécuté en root." >&2 exit 1 fi extract_keys() { local file="$1" grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$file" | cut -d'=' -f1 | sort -u } check_config_drift() { local conf_dir="/opt/monitoring/conf" local base_conf local_conf local found_issue=false local reviewed_files=0 local files_requiring_action=0 log_info "audit_start" "Début de l'audit des configurations locales" while IFS= read -r base_conf; do reviewed_files=$((reviewed_files + 1)) local_conf="${base_conf%.conf}.local.conf" local file_name local_file_name file_name="$(basename "$base_conf")" local_file_name="$(basename "$local_conf")" if [ ! -f "$local_conf" ]; then cp "$base_conf" "$local_conf" || { log_error "audit_create_local_failed" \ "Impossible de créer ${local_file_name} à partir de ${file_name}" found_issue=true files_requiring_action=$((files_requiring_action + 1)) continue } chmod 600 "$local_conf" 2>/dev/null || true log_notice "audit_missing_local" \ "Le fichier ${local_file_name} n'existait pas ; il a été créé par copie de ${file_name}" continue fi local tmp_base tmp_local tmp_base="$(mktemp)" || fail_internal "mktemp a échoué" tmp_local="$(mktemp)" || fail_internal "mktemp a échoué" extract_keys "$base_conf" > "$tmp_base" extract_keys "$local_conf" > "$tmp_local" local missing obsolete missing="$(comm -23 "$tmp_base" "$tmp_local" | xargs)" obsolete="$(comm -13 "$tmp_base" "$tmp_local" | xargs)" if [ -n "$missing" ] || [ -n "$obsolete" ]; then found_issue=true files_requiring_action=$((files_requiring_action + 1)) log_warning "audit_file_requires_action" \ "Le fichier ${local_file_name} nécessite une vérification" if [ -n "$missing" ]; then log_warning "audit_keys_missing" \ "Dans ${local_file_name}, options disponibles dans ${file_name} mais absentes du local : ${missing}" fi if [ -n "$obsolete" ]; then log_info "audit_keys_obsolete" \ "Dans ${local_file_name}, options présentes uniquement dans le local et à vérifier ou supprimer : ${obsolete}" fi else log_info "audit_file_ok" \ "Le fichier ${local_file_name} contient les mêmes options que ${file_name}" fi rm -f "$tmp_base" "$tmp_local" done < <(find "$conf_dir" -maxdepth 1 -type f -name "*.conf" ! -name "*.local.conf" | sort) if [ "$found_issue" = false ]; then log_info "audit_success" \ "Toutes les configurations locales sont à jour (${reviewed_files} fichier(s) vérifié(s))" else log_warning "audit_requires_action" \ "Certaines configurations locales doivent être mises à jour (${files_requiring_action} fichier(s) à vérifier sur ${reviewed_files})" fi } main() { lock_or_exit "monitoring-audit" check_config_drift } main exit_with_status