1009 lines
33 KiB
Bash
1009 lines
33 KiB
Bash
check_deb_status() {
|
|
local type="$1" params="$2"
|
|
case "$type" in
|
|
"pkg") dpkg -s "$params" >/dev/null 2>&1 ;;
|
|
"sys")
|
|
func="check_deb_${type}_${params}"
|
|
if declare -F "$func" >/dev/null; then
|
|
"$func"
|
|
else
|
|
return 1
|
|
fi
|
|
esac
|
|
}
|
|
|
|
update_cron_marker(){
|
|
# ------------------------------------------------------------------
|
|
# Installation du cron
|
|
# ------------------------------------------------------------------
|
|
local marker="# $1"
|
|
|
|
(
|
|
crontab -l 2>/dev/null | sed "/^${marker//\//\\/}$/,/^${marker//\//\\/}$/d"
|
|
echo "$marker"
|
|
echo "$2"
|
|
echo "$marker"
|
|
) | crontab -
|
|
|
|
msg_success "Tâche cron installée avec succès."
|
|
}
|
|
|
|
do_deb_install_action() {
|
|
local type="$1" params="$2" func
|
|
case "$type" in
|
|
"pkg") $SUDO apt-get install -y "$params" ;;
|
|
"sys")
|
|
func="do_deb_${type}_${params}"
|
|
if declare -F "$func" >/dev/null; then
|
|
"$func"
|
|
else
|
|
msg_error "la fonction do_deb_${type}_${params} n'est pas définie...(skip)"
|
|
fi
|
|
esac
|
|
}
|
|
|
|
check_deb_sys_ipv6(){
|
|
if [[ $(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null) -eq 1 ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
|
|
check_deb_sys_locale_install() {
|
|
# On cherche spécifiquement les lignes dé commentées pour fr_FR ET en_US
|
|
if grep -q "^fr_FR.UTF-8" /etc/locale.gen && grep -q "^en_US.UTF-8" /etc/locale.gen; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_zabbix(){
|
|
if dpkg -s zabbix-agent2 >/dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_zabbix_conf(){
|
|
if dpkg -s zabbix-agent2 >/dev/null 2>&1; then
|
|
return 1
|
|
else
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_msmtp(){
|
|
return 1
|
|
}
|
|
|
|
check_deb_sys_ntp_setup() {
|
|
return 1
|
|
}
|
|
|
|
check_deb_sys_mail(){
|
|
if grep -q "ADMIN_MAIL=" /etc/environment 2>/dev/null; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_fail2ban() {
|
|
# Si le paquet n'est PAS installé, on ne propose pas la config
|
|
if ! dpkg -s fail2ban >/dev/null 2>&1; then
|
|
return 0 # Masquer (on attend l'étape 1)
|
|
fi
|
|
|
|
# Si le paquet est là, on affiche la config tant que jail.local n'existe pas
|
|
if [[ ! -f /etc/fail2ban/jail.local ]]; then
|
|
return 1 # AFFICHER
|
|
else
|
|
return 0 # MASQUER (Déjà configuré)
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_apparmor(){
|
|
if is_sys_lxc; then
|
|
! systemctl is-enabled apparmor >/dev/null 2>&1 #Container
|
|
else
|
|
[[ $($SUDO cat /sys/module/apparmor/parameters/enabled 2>/dev/null) == "Y" ]] #VM
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_ufw() {
|
|
if ! dpkg -s ufw >/dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_gen_ssh_key(){
|
|
if [[ -f "$RSA_KEY_FILE" ]]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
check_deb_sys_deploy_ssh_key(){
|
|
if [[ -f "$RSA_KEY_FILE" ]]; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
check_deb_sys_motd(){
|
|
if find /etc/update-motd.d/ -type f -perm /111 | grep -q .; then
|
|
return 1
|
|
else
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_clone_ssh_key(){
|
|
if [[ -f "$RSA_KEY_FILE" ]]; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
check_deb_sys_cert_install(){
|
|
local marker="# $CONFIG_DEB_INSTALL_DEFAULT_CA_CRON"
|
|
if crontab -l 2>/dev/null | grep -q "$marker"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_deb_sys_script_update(){
|
|
local marker="# $CONFIG_DEB_INSTALL_CRON_UPDATE"
|
|
if crontab -l 2>/dev/null | grep -q "$marker"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_script_update(){
|
|
|
|
local full_command script_path
|
|
|
|
WELCOME_SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd)"
|
|
|
|
script_path="${WELCOME_SCRIPT_PATH}/script/update.sh"
|
|
|
|
chmod +x "$script_path"
|
|
|
|
full_command="${WELCOME_SCRIPT_PATH}/script/update.sh >> /var/log/script-update.log 2>&1"
|
|
|
|
## All days at 3AM
|
|
update_cron_marker "$CONFIG_DEB_INSTALL_CRON_UPDATE" "0 3 * * * $full_command"
|
|
}
|
|
|
|
do_deb_sys_locale_install(){
|
|
msg_info "installation du package si besoin"
|
|
apt install locales
|
|
msg_info "activation des locales Fr et En"
|
|
sed -i '/fr_FR.UTF-8/s/^# //' /etc/locale.gen
|
|
sed -i '/en_US.UTF-8/s/^# //' /etc/locale.gen
|
|
msg_info "génération des locales Fr et En"
|
|
locale-gen en_US.UTF-8
|
|
locale-gen fr_FR.UTF-8
|
|
msg_success "opération terminée"
|
|
}
|
|
|
|
do_deb_sys_motd(){
|
|
$SUDO chmod -x /etc/update-motd.d/*
|
|
msg_success "Les fichiers dans /etc/update-motd.d/ ne sont plus executable"
|
|
msg_success "Ils ne seront donc plus lancé à la connexion"
|
|
}
|
|
|
|
do_deb_sys_gen_ssh_key() {
|
|
if [[ -f "$RSA_KEY_FILE" ]]; then
|
|
msg_success "Une clé SSH existe déjà : $RSA_KEY_FILE"
|
|
# On affiche l'empreinte pour info
|
|
ssh-keygen -l -f "$RSA_KEY_FILE"
|
|
else
|
|
msg_info "Génération d'une nouvelle clé RSA (4096 bits)..."
|
|
mkdir -p "$HOME/.ssh"
|
|
chmod 700 "$HOME/.ssh"
|
|
|
|
# -t rsa : type RSA
|
|
# -b 4096 : taille robuste
|
|
# -N "" : pas de mot de passe (passphrase vide pour l'auto)
|
|
# -f : chemin du fichier
|
|
ssh-keygen -t rsa -b 4096 -N "" -f "$RSA_KEY_FILE"
|
|
|
|
msg_success "Clé générée avec succès."
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_deploy_ssh_key() {
|
|
local remote_user remote_host remote_port
|
|
|
|
msg_info "Déploiement de la clé sur un serveur distant"
|
|
|
|
# 1. Vérification locale
|
|
if [[ ! -f "$HOME/.ssh/id_rsa.pub" ]]; then
|
|
msg_error "Erreur : Aucune clé publique trouvée. Générez-en une d'abord."
|
|
return
|
|
fi
|
|
|
|
# 2. Saisie des infos distantes
|
|
read -rp "Utilisateur distant (ex: root) : " remote_user
|
|
read -rp "IP ou Hostname distant : " remote_host
|
|
read -rp "Port SSH (par défaut 22) : " remote_port
|
|
remote_port=${remote_port:-22}
|
|
|
|
msg_info "Tentative de déploiement sur ${remote_user}@${remote_host}..."
|
|
|
|
# 3. Déploiement intelligent
|
|
# ssh-copy-id vérifie tout seul si la clé existe déjà sur le serveur !
|
|
if ssh-copy-id -p "$remote_port" "${remote_user}@${remote_host}"; then
|
|
msg_success "La clé a été installée (ou était déjà présente)."
|
|
msg_info "Test de connexion : ssh -p $remote_port ${remote_user}@${remote_host}"
|
|
else
|
|
msg_error "Le déploiement a échoué. Vérifiez vos accès ou le mot de passe."
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_clone_ssh_key() {
|
|
local remote_user remote_host remote_port
|
|
local ssh_dir="$HOME/.ssh"
|
|
local key_file="$ssh_dir/id_rsa"
|
|
|
|
msg_info "Clonage de l'identité SSH vers un hôte distant"
|
|
|
|
# 1. Vérification locale
|
|
if [[ ! -f "$key_file" ]]; then
|
|
msg_error "Erreur : Aucune clé locale ($key_file) à copier."
|
|
return
|
|
fi
|
|
|
|
# 2. Saisie des infos
|
|
read -rp "Utilisateur distant : " remote_user
|
|
read -rp "IP/Hostname distant : " remote_host
|
|
read -rp "Port SSH (22) : " remote_port
|
|
remote_port=${remote_port:-22}
|
|
|
|
# 3. Confirmation (car c'est sensible)
|
|
msg_warning "Ceci va copier votre clé PRIVÉE sur $remote_host."
|
|
read -rp "Êtes-vous sûr ? (o/N) : " confirm
|
|
[[ "$confirm" != "o" && "$confirm" != "O" ]] && return
|
|
|
|
# 4. Envoi et configuration des droits en une seule commande
|
|
# On utilise tar pour conserver les droits et créer le dossier si besoin
|
|
msg_info "Transfert en cours..."
|
|
|
|
tar -C "$ssh_dir" -cf - id_rsa id_rsa.pub | ssh -p "$remote_port" "${remote_user}@${remote_host}" "
|
|
mkdir -p ~/.ssh && \
|
|
tar -C ~/.ssh -xf - && \
|
|
chmod 700 ~/.ssh && \
|
|
chmod 600 ~/.ssh/id_rsa && \
|
|
chmod 644 ~/.ssh/id_rsa.pub && \
|
|
echo 'Clés copiées et permissions réglées.'
|
|
"
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
msg_success "Identité clonée avec succès sur ${remote_host}."
|
|
else
|
|
msg_error "Le transfert a échoué."
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_ntp() {
|
|
msg_info "Configuration de l'heure (Paris) et du NTP..."
|
|
|
|
# 1. On règle sur Paris au lieu de UTC
|
|
$SUDO timedatectl set-timezone Europe/Paris
|
|
msg_info "Fuseau horaire réglé sur Europe/Paris."
|
|
|
|
# 2. Configuration NTP (On ajoute des serveurs français pour la précision)
|
|
$SUDO tee /etc/systemd/timesyncd.conf <<EOF >/dev/null
|
|
[Time]
|
|
NTP=0.fr.pool.ntp.org 1.fr.pool.ntp.org pool.ntp.org
|
|
FallbackNTP=8.8.8.8 1.1.1.1
|
|
EOF
|
|
|
|
$SUDO timedatectl set-ntp true
|
|
$SUDO systemctl restart systemd-timesyncd
|
|
|
|
msg_success "Heure locale réglée : $(date)"
|
|
}
|
|
|
|
do_deb_sys_ufw() {
|
|
local ports_to_allow=() input_port="" current_ssh_port current_rules
|
|
|
|
msg_info "Configuration interactive du Firewall UFW"
|
|
|
|
# 1. On montre l'existant SANS y toucher
|
|
current_rules=$($SUDO ufw status | grep -v "(v6)" | grep "ALLOW" | awk '{print $1}' | cut -d'/' -f1 | tr '\n' ' ')
|
|
if [[ -n "$current_rules" ]]; then
|
|
msg_warning "Ports actuellement ouverts : ${COLOR_WHITE}${current_rules}${NONE}"
|
|
msg_warning "Toutes les autres règles existantes seront supprimées"
|
|
msg_warning "Veuillez saisir tous les ports à ouvrir"
|
|
msg_warning "Même si il étaient déjà ouvert avant.\n"
|
|
fi
|
|
|
|
msg_info "Liste des ports tcp sortant ouvert"
|
|
sudo ss -tlnwp | grep -v -E '(127\.0\.0\.1|::1)' | awk '
|
|
BEGIN {print "State", "Local_Address:Port", "Process"}
|
|
NR==1 {next}
|
|
{
|
|
split($4, a, ":");
|
|
port=a[length(a)]
|
|
}
|
|
!seen[port]++ {print $1, $2, $5}' | column -t
|
|
|
|
# 2. Boucle de saisie (on remplit uniquement le tableau en mémoire)
|
|
while true; do
|
|
read -rp "Entrez un port à ouvrir (ou 'f' pour terminer) : " input_port
|
|
[[ "$input_port" == "f" ]] && break
|
|
|
|
if [[ ! "$input_port" =~ ^[0-9]+$ ]]; then
|
|
msg_error "Port invalide."
|
|
continue
|
|
fi
|
|
|
|
if [[ " ${ports_to_allow[@]} " =~ " ${input_port} " ]]; then
|
|
msg_warning "Déjà dans la liste."
|
|
else
|
|
ports_to_allow+=("$input_port")
|
|
msg_success "Port $input_port ajouté à la file d'attente."
|
|
fi
|
|
done
|
|
|
|
# 3. Vérification de sécurité SSH (Toujours en mémoire)
|
|
current_ssh_port=$(ss -tlnp | grep sshd | awk '{print $4}' | awk -F':' '{print $NF}' | head -n1)
|
|
current_ssh_port=${current_ssh_port:-22}
|
|
if [[ ! " ${ports_to_allow[@]} " =~ " ${current_ssh_port} " ]]; then
|
|
msg_warning "ATTENTION : Votre port SSH ($current_ssh_port) n'est pas inclus !"
|
|
read -rp "L'ajouter ? (O/n) : " add_ssh
|
|
[[ "$add_ssh" != "n" ]] && ports_to_allow+=("$current_ssh_port")
|
|
fi
|
|
|
|
# 4. LE MOMENT CRITIQUE : Confirmation avant application
|
|
echo -e "\n${COLOR_YELLOW}RÉCAPITULATIF :${NONE}"
|
|
echo -e "Les ports suivants vont être ouverts : ${COLOR_LIGHT_BLUE}${ports_to_allow[*]}${NONE}"
|
|
msg_error "Toutes les autres règles existantes seront supprimées."
|
|
|
|
read -rp "Appliquer ces changements maintenant ? (o/N) : " confirm
|
|
if [[ "$confirm" != "o" && "$confirm" != "O" ]]; then
|
|
msg_info "Action annulée. Le firewall n'a pas été modifié."
|
|
return
|
|
fi
|
|
|
|
# 5. APPLICATION RÉELLE (Seulement si confirmé)
|
|
msg_info "Application des modifications..."
|
|
|
|
# On reset seulement maintenant
|
|
$SUDO ufw --force reset >/dev/null
|
|
$SUDO ufw default deny incoming
|
|
$SUDO ufw default allow outgoing
|
|
|
|
for port in "${ports_to_allow[@]}"; do
|
|
$SUDO ufw allow "$port"/tcp >/dev/null
|
|
done
|
|
|
|
$SUDO sed -i 's/IPV6=yes/IPV6=no/' /etc/default/ufw
|
|
|
|
if $SUDO ufw --force enable; then
|
|
msg_success "Firewall mis à jour et activé."
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_fail2ban() {
|
|
msg_info "Configuration de Fail2Ban..."
|
|
# On crée la configuration personnalisée
|
|
$SUDO tee /etc/fail2ban/jail.local <<EOF
|
|
[sshd]
|
|
enabled = true
|
|
port = ssh
|
|
filter = sshd
|
|
backend = systemd
|
|
maxretry = 5
|
|
bantime = 1h
|
|
allowipv6 = auto
|
|
EOF
|
|
$SUDO systemctl restart fail2ban
|
|
msg_success "Fail2Ban configuré et redémarré."
|
|
}
|
|
|
|
do_deb_sys_apparmor(){
|
|
if is_sys_lxc; then
|
|
msg_info "Détection d'un conteneur LXC..."
|
|
#$SUDO systemctl enable --now apparmor
|
|
msg_success "AppArmor activé (Niveau conteneur)."
|
|
msg_info "Note: La sécurité réelle est gérée par l'hôte Proxmox."
|
|
else
|
|
msg_info "Configuration AppArmor (Machine Physique/VM)..."
|
|
$SUDO systemctl enable --now apparmor
|
|
if [[ $($SUDO cat /sys/module/apparmor/parameters/enabled 2>/dev/null) != "Y" ]]; then
|
|
if [ -f /etc/default/grub ]; then
|
|
$SUDO sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="apparmor=1 security=apparmor /' /etc/default/grub
|
|
$SUDO update-grub
|
|
msg_warning "Activation GRUB faite. Reboot nécessaire."
|
|
fi
|
|
else
|
|
msg_success "AppArmor est déjà actif dans le Kernel."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_zabbix(){
|
|
local ip
|
|
|
|
# 1. Désinstallation de l'ancien agent s'il existe
|
|
if dpkg -s zabbix-agent >/dev/null 2>&1; then
|
|
msg_info "Ancien Zabbix Agent détecté, suppression..."
|
|
$SUDO systemctl stop zabbix-agent >/dev/null 2>&1
|
|
$SUDO apt-get purge -y zabbix-agent
|
|
$SUDO apt-get autoremove -y
|
|
fi
|
|
|
|
read -rp "IP Zabbix [${CONFIG_DEB_INSTALL_ZABBIX_SERVER_IP}]: " ip;
|
|
ip=${ip:-${CONFIG_DEB_INSTALL_ZABBIX_SERVER_IP}}
|
|
$SUDO apt-get install -y zabbix-agent2;
|
|
$SUDO sed -i "s/^Server=.*/Server=$ip/" /etc/zabbix/zabbix_agent2.conf
|
|
$SUDO sed -i "s/^ServerActive=.*/ServerActive=$ip/" /etc/zabbix/zabbix_agent2.conf
|
|
# OPTIONNEL : Force l'agent à envoyer son propre nom d'hôte système
|
|
$SUDO sed -i "s/^# HostnameItem=.*/HostnameItem=system.hostname/" /etc/zabbix/zabbix_agent2.conf
|
|
$SUDO sed -i "s/^Hostname=.*/# Hostname=Zabbix server/" /etc/zabbix/zabbix_agent2.conf
|
|
$SUDO systemctl enable zabbix-agent2
|
|
$SUDO systemctl restart zabbix-agent2
|
|
msg_success "Zabbix agent 2 configuré."
|
|
}
|
|
|
|
do_deb_sys_zabbix_conf(){
|
|
local ip
|
|
read -rp "IP Zabbix [${CONFIG_DEB_INSTALL_ZABBIX_SERVER_IP}]: " ip;
|
|
ip=${ip:-${CONFIG_DEB_INSTALL_ZABBIX_SERVER_IP}}
|
|
$SUDO sed -i "s/^Server=.*/Server=$ip/" /etc/zabbix/zabbix_agent2.conf
|
|
$SUDO sed -i "s/^ServerActive=.*/ServerActive=$ip/" /etc/zabbix/zabbix_agent2.conf
|
|
# OPTIONNEL : Force l'agent à envoyer son propre nom d'hôte système
|
|
$SUDO sed -i "s/^# HostnameItem=.*/HostnameItem=system.hostname/" /etc/zabbix/zabbix_agent2.conf
|
|
$SUDO sed -i "s/^Hostname=.*/# Hostname=Zabbix server/" /etc/zabbix/zabbix_agent2.conf
|
|
$SUDO systemctl enable zabbix-agent2
|
|
$SUDO systemctl restart zabbix-agent2
|
|
msg_success "Zabbix agent 2 configuré."
|
|
}
|
|
|
|
do_deb_sys_ipv6(){
|
|
# Application des paramètres sysctl
|
|
# On cible 'all', 'default' et 'lo' (loopback)
|
|
$SUDO sysctl -w net.ipv6.conf.all.disable_ipv6=1 >/dev/null
|
|
$SUDO sysctl -w net.ipv6.conf.default.disable_ipv6=1 >/dev/null
|
|
$SUDO sysctl -w net.ipv6.conf.lo.disable_ipv6=1 >/dev/null
|
|
|
|
# Rendre les changements persistants après redémarrage
|
|
$SUDO cat <<EOF > /etc/sysctl.d/99-disable-ipv6.conf
|
|
net.ipv6.conf.all.disable_ipv6 = 1
|
|
net.ipv6.conf.default.disable_ipv6 = 1
|
|
net.ipv6.conf.lo.disable_ipv6 = 1
|
|
EOF
|
|
|
|
msg_success "IPv6 désactivé avec succès"
|
|
}
|
|
|
|
do_deb_sys_mail(){
|
|
local m
|
|
read -rp "Mail admin [${CONFIG_DEB_INSTALL_SERVER_ADMIN_MAIL}]: " m;
|
|
m=${m:-$CONFIG_DEB_INSTALL_SERVER_ADMIN_MAIL}
|
|
echo "export ADMIN_MAIL=\"$m\"" | $SUDO tee -a /etc/environment > /dev/null
|
|
# shellcheck disable=SC2034
|
|
export ADMIN_MAIL=$m
|
|
# Reload env
|
|
source /etc/environment
|
|
msg_success "ADMIN_MAIL configuré avec $m"
|
|
}
|
|
|
|
do_deb_sys_static_ip() {
|
|
local interface
|
|
interface=$(ip -o link show | awk -F': ' '{print $2}' | grep -v 'lo' | head -n1)
|
|
|
|
echo -e "${COLOR_WHITE}Configuration de l'interface : ${COLOR_CYAN}$interface${NONE}"
|
|
read -rp "Entrez l'IP (ex: 192.168.1.50) : " new_ip
|
|
read -rp "Entrez la Passerelle (Gateway) : " new_gw
|
|
read -rp "Entrez le DNS Primaire (ex: 1.1.1.1) : " dns1
|
|
read -rp "Entrez le DNS Secondaire (ex: 8.8.8.8) : " dns2
|
|
|
|
# Validation minimale
|
|
if [[ -z "$new_ip" || -z "$new_gw" || -z "$dns1" ]]; then
|
|
msg_error "IP, Gateway ou DNS Primaire manquant. Annulation."
|
|
return 1
|
|
fi
|
|
|
|
# Si le DNS2 est vide, on peut mettre une valeur par défaut ou laisser vide
|
|
[[ -z "$dns2" ]] && dns2="8.8.4.4"
|
|
|
|
# --- CAS 1 : NETPLAN (Ubuntu / Debian récentes) ---
|
|
if [ -d "/etc/netplan" ]; then
|
|
msg_info "Configuration via Netplan..."
|
|
$SUDO bash -c "cat <<EOF > /etc/netplan/99-frogg-static.yaml
|
|
network:
|
|
version: 2
|
|
renderer: networkd
|
|
ethernets:
|
|
$interface:
|
|
addresses: [$new_ip/24]
|
|
routes: [{to: default, via: $new_gw}]
|
|
nameservers:
|
|
addresses: [$dns1, $dns2]
|
|
EOF"
|
|
$SUDO netplan apply
|
|
|
|
# --- CAS 2 : INTERFACES (Debian classique) ---
|
|
elif [ -f "/etc/network/interfaces" ]; then
|
|
msg_info "Configuration via /etc/network/interfaces..."
|
|
$SUDO bash -c "cat <<EOF > /etc/network/interfaces.d/$interface
|
|
auto $interface
|
|
iface $interface inet static
|
|
address $new_ip
|
|
netmask 255.255.255.0
|
|
gateway $new_gw
|
|
dns-nameservers $dns1 $dns2
|
|
EOF"
|
|
$SUDO systemctl restart networking
|
|
else
|
|
msg_error "Aucun gestionnaire réseau trouvé."
|
|
return 1
|
|
fi
|
|
|
|
msg_success "$interface > IP [$new_ip] Gateway[$new_gw] DNS[$dns1, $dns2]"
|
|
}
|
|
|
|
do_deb_sys_hostname() {
|
|
local old_h current_ip
|
|
old_h=$(hostname)
|
|
echo -e "${COLOR_WHITE}Nom actuel : ${COLOR_CYAN}$old_h${NONE}"
|
|
read -rp "Nouveau Hostname (FQDN recommandé, ex: machine.domaine.com) : " new_h
|
|
|
|
if [[ -n "$new_h" ]]; then
|
|
# 1. On définit le hostname dans le système
|
|
$SUDO hostnamectl set-hostname "$new_h"
|
|
|
|
# 2. On extrait le nom court
|
|
local short_h="${new_h%%.*}"
|
|
|
|
# 3. Mise à jour de /etc/hosts
|
|
# STRATÉGIE : On identifie la ligne qui contient l'ancien hostname
|
|
# et on la remplace intégralement par "IP FQDN NOM_COURT"
|
|
|
|
# On récupère l'IP associée à l'ancien hostname dans /etc/hosts
|
|
current_ip=$(grep -w "$old_h" /etc/hosts | awk '{print $1}' | head -n1)
|
|
|
|
if [[ -n "$current_ip" ]]; then
|
|
msg_info "Mise à jour de la ligne pour l'IP $current_ip..."
|
|
# On remplace toute la ligne qui commence par cette IP
|
|
$SUDO sed -i "s/^$current_ip.*/$current_ip\t$new_h $short_h/" /etc/hosts
|
|
else
|
|
# Si on ne trouve pas l'IP, on ajoute une ligne propre sur la loopback locale
|
|
msg_warning "IP non trouvée dans /etc/hosts, ajout sur 127.0.1.1"
|
|
echo -e "127.0.1.1\t$new_h $short_h" | $SUDO tee -a /etc/hosts > /dev/null
|
|
fi
|
|
|
|
msg_success "Hostname configuré : $new_h ($short_h)"
|
|
fi
|
|
}
|
|
|
|
do_deb_sys_msmtp() {
|
|
|
|
local m_host m_port m_user m_from m_pass default_from
|
|
|
|
msg_info "Installation et configuration de MSMTP..."
|
|
|
|
# Installation du paquet
|
|
$SUDO apt-get update -qq && $SUDO apt-get install -y msmtp msmtp-mta ca-certificates -qq
|
|
|
|
default_from="srv-$(hostname -s)${CONFIG_DEB_INSTALL_SERVER_SMTP_FROM}"
|
|
|
|
# Saisie des informations
|
|
read -rp "Serveur SMTP (host) [${CONFIG_DEB_INSTALL_SERVER_SMTP_HOST}]: " m_host
|
|
read -rp "Port (ex: 587 ou 465) [${CONFIG_DEB_INSTALL_SERVER_SMTP_PORT}]: " m_port
|
|
read -rp "Email expéditeur (from) [$default_from]: " m_from
|
|
read -rp "Utilisateur (user/login) [${CONFIG_DEB_INSTALL_SERVER_SMTP_LOGIN}]: " m_user
|
|
read -s -rp "Mot de passe : " m_pass
|
|
|
|
m_host=${m_host:-$CONFIG_DEB_INSTALL_SERVER_SMTP_HOST}
|
|
m_port=${m_port:-$CONFIG_DEB_INSTALL_SERVER_SMTP_PORT}
|
|
m_from=${m_from:-$default_from}
|
|
m_user=${m_user:-$CONFIG_DEB_INSTALL_SERVER_SMTP_LOGIN}
|
|
|
|
echo "" # Pour revenir à la ligne après le mot de passe masqué
|
|
|
|
# Construction du fichier msmtprc
|
|
$SUDO bash -c "cat <<EOF > /etc/msmtprc
|
|
# Configuration générée par Frogg Deploy
|
|
defaults
|
|
auth on
|
|
tls on
|
|
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
|
syslog LOG_MAIL
|
|
#logfile /var/log/msmtp.log
|
|
|
|
account default
|
|
host $m_host
|
|
port $m_port
|
|
from $m_from
|
|
user $m_user
|
|
password $m_pass
|
|
EOF"
|
|
|
|
# Sécurisation du fichier (Indispensable car contient un mot de passe)
|
|
$SUDO chmod 600 /etc/msmtprc
|
|
$SUDO chown root:root /etc/msmtprc
|
|
|
|
msg_success "MSMTP configuré. Test d'envoi recommandé : echo 'Test' | mail -s 'Test sujet' ton@mail.com"
|
|
}
|
|
|
|
do_deb_sys_cert_install_ca_server(){
|
|
local full_command="${WELCOME_SCRIPT_PATH}/script/ca_server_renew.sh"
|
|
|
|
msg_info "Renouvellement du certificat"
|
|
eval "$full_command"
|
|
|
|
msg_info "Ajout du renouvellement automatique du certificat"
|
|
update_cron_marker "$CONFIG_DEB_INSTALL_DEFAULT_CA_CRON" "0 0 1 * * $full_command >> /var/log/cert-renew.log 2>&1"
|
|
|
|
msg_success "Opération terminée"
|
|
}
|
|
|
|
do_deb_sys_cert_install(){
|
|
|
|
# cas du server CA
|
|
if [ "$(hostname)" = "$CONFIG_DEB_INSTALL_DEFAULT_CA_SERVER" ] || [ "$(hostname -f)" = "$CONFIG_DEB_INSTALL_DEFAULT_CA_SERVER" ]; then
|
|
msg_warning "server CA détecté, mise en place d'un renew spécifique..."
|
|
do_deb_sys_cert_install_ca_server
|
|
return 0
|
|
fi
|
|
|
|
local ca_ip wildcard_domain ca_url ca_fingerprint base_domain marker root_crt input_ip step_path \
|
|
system_target inter_target cert_group load_state unit svc_user current_group \
|
|
cert_dir cert_crt cert_key cert_key cert_pfx pfx_cmd pfx_input step_bin renew_cmd restart_cmd="" \
|
|
unit full_command cert_fullchain proxmox_cmd
|
|
|
|
# Fichiers de certificats
|
|
cert_dir="${CONFIG_DEB_INSTALL_DEFAULT_CA_INSTALL_PATH}"
|
|
cert_crt="${cert_dir}/${CONFIG_DEB_INSTALL_DEFAULT_CA_FILE_CRT}"
|
|
cert_key="${cert_dir}/${CONFIG_DEB_INSTALL_DEFAULT_CA_FILE_KEY}"
|
|
cert_pfx="${cert_dir}/${CONFIG_DEB_INSTALL_DEFAULT_CA_FILE_PFX}"
|
|
|
|
# Groupe utilisé pour l'accès aux certificats
|
|
cert_group="ssl-cert"
|
|
|
|
msg_info "=== Configuration Automatisée du Client PKI ==="
|
|
|
|
# 1. Saisie des informations de base
|
|
read -rp "IP du serveur CA [${CONFIG_DEB_INSTALL_DEFAULT_CA_SERVER}] : " input_ip
|
|
ca_ip=${input_ip:-${CONFIG_DEB_INSTALL_DEFAULT_CA_SERVER}}
|
|
|
|
read -rp "Domaine Wildcard [${CONFIG_DEB_INSTALL_DEFAULT_CA_WILDCARD}] : " INPUT_DOMAIN
|
|
wildcard_domain=${INPUT_DOMAIN:-${CONFIG_DEB_INSTALL_DEFAULT_CA_WILDCARD}}
|
|
|
|
msg_info "Configuration retenue : IP=$ca_ip | Domaine=$wildcard_domain"
|
|
|
|
ca_url="https://$ca_ip"
|
|
|
|
# ==================================================================
|
|
# [1/7] Récupération de l'empreinte via HTTPS
|
|
# ==================================================================
|
|
|
|
# 2. Récupération automatique de la Fingerprint via HTTPS
|
|
msg_warning "[1/7] Récupération de l'empreinte via HTTPS..."
|
|
# Cette commande récupère le certificat du serveur et calcule son empreinte SHA256
|
|
ca_fingerprint=$(openssl s_client -connect "${ca_ip}:443" </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout | cut -d'=' -f2 | tr -d ':')
|
|
|
|
if [ -z "$ca_fingerprint" ]; then
|
|
msg_error "Erreur : Impossible de contacter le serveur sur le port 443. Vérifie l'IP."
|
|
return 1
|
|
fi
|
|
msg_info "Empreinte détectée : ${GREEN}$ca_fingerprint${NONE}"
|
|
|
|
# ==================================================================
|
|
# [2/7] Installation du paquet Step CLI
|
|
# ==================================================================
|
|
|
|
msg_warning "[2/7] Installation du paquet Step CLI..."
|
|
|
|
# Installation de Step CLI (si besoin)
|
|
if ! command -v step &> /dev/null; then
|
|
|
|
if dpkg -i "${WELCOME_SCRIPT_PATH}/doc/${CONFIG_DEB_INSTALL_DEFAULT_CA_STEP}" > /dev/null 2>&1; then
|
|
msg_success "Installation du paquet ${CONFIG_DEB_INSTALL_DEFAULT_CA_STEP}"
|
|
else
|
|
msg_error "Échec de l'installation du paquet ${CONFIG_DEB_INSTALL_DEFAULT_CA_STEP}"
|
|
return 1
|
|
fi
|
|
else
|
|
msg_success "paquet Step CLI déjà installé"
|
|
fi
|
|
|
|
# ==================================================================
|
|
# [3/7] Liaison et génération du certificat
|
|
# ==================================================================
|
|
|
|
# Configuration et Certificat
|
|
msg_warning "[3/7] Liaison et génération du certificat..."
|
|
|
|
# 1. On force un environnement de travail propre
|
|
step_path="/tmp/step-config"
|
|
rm -rf "$step_path"
|
|
mkdir -p "$step_path"
|
|
|
|
# CRUCIAL : On dit à step d'utiliser ce dossier pour TOUTES ses opérations
|
|
export STEPPATH="$step_path"
|
|
|
|
# 2. Utilisation de la Fingerprint confirmée
|
|
#ca_fingerprint="4873b9eaeb8a7643475939b4035221bd1bc3acd0db00e94df5a76d771459f439"
|
|
root_ca_fingerprint=$(ssh "root@${ca_ip}" "step certificate fingerprint /var/lib/step-ca/.step/certs/root_ca.crt")
|
|
|
|
if [ -z "$root_ca_fingerprint" ]; then
|
|
msg_error " Impossible de récupérer le fingerprint."
|
|
return 1
|
|
else
|
|
msg_info "fingerprint récupéré : ${root_ca_fingerprint}"
|
|
fi
|
|
|
|
# 3. Liaison (Bootstrap)
|
|
step ca bootstrap --ca-url "$ca_url" --fingerprint "$root_ca_fingerprint" --force
|
|
|
|
# Chemin du certificat racine récupéré
|
|
root_crt="$step_path/certs/root_ca.crt"
|
|
|
|
# 4. Génération du Wildcard
|
|
mkdir -p "${CONFIG_DEB_INSTALL_DEFAULT_CA_INSTALL_PATH}"
|
|
base_domain="${wildcard_domain#*.}"
|
|
|
|
step ca certificate "$wildcard_domain" \
|
|
"${cert_crt}" \
|
|
"${cert_key}" \
|
|
--ca-url "$ca_url" \
|
|
--root "$root_crt" \
|
|
--san "$wildcard_domain" \
|
|
--san "$base_domain" \
|
|
--not-after=8760h \
|
|
--force
|
|
|
|
msg_success "Certificat généré avec succès dans ${CONFIG_DEB_INSTALL_DEFAULT_CA_INSTALL_PATH}/"
|
|
|
|
# ==================================================================
|
|
# [4/7] Installation automatique du Root CA
|
|
# ==================================================================
|
|
|
|
msg_warning "[4/7] Installation automatique du Root CA..."
|
|
|
|
# 1. Définition des chemins
|
|
# On s'assure de retrouver le fichier même si la variable a sauté
|
|
system_target="/usr/local/share/ca-certificates/step-ca-frogg.crt"
|
|
inter_target="/usr/local/share/ca-certificates/step-ca-intermediate-frogg.crt"
|
|
|
|
### --- SECTION INTERMEDIATE --- ###
|
|
|
|
if [ -f "$cert_crt" ]; then
|
|
# On extrait le DEUXIÈME certificat du fichier (l'intermédiaire)
|
|
# On utilise awk pour isoler le second bloc -----BEGIN...END-----
|
|
awk '/-----BEGIN CERTIFICATE-----/{i++} i==2' "$cert_crt" > "$inter_target"
|
|
|
|
if [ -s "$inter_target" ]; then
|
|
msg_success "Certificat intermédiaire extrait avec succès."
|
|
else
|
|
# Si awk échoue ou que le fichier est simple, on peut tenter un téléchargement direct
|
|
msg_warn "Extraction échouée, tentative de récupération via step..."
|
|
step ca root "$inter_target" --ca-url "$ca_url" --fingerprint "$ca_fingerprint" --force > /dev/null 2>&1
|
|
fi
|
|
else
|
|
msg_warn "${cert_crt} introuvable, impossible d'extraire l'intermédiaire pour le moment."
|
|
fi
|
|
|
|
### --- FIN SECTION INTERMEDIATE --- ###
|
|
|
|
if [ -f "$root_crt" ]; then
|
|
# 2. On nettoie le certificat (format PEM pur) pour éviter l'erreur 'rehash'
|
|
# Cela extrait uniquement le certificat et ignore le texte inutile
|
|
openssl x509 -in "$root_crt" -out "$system_target"
|
|
|
|
# 3. Mise à jour du magasin (sans --fresh pour éviter les warnings inutiles)
|
|
if update-ca-certificates > /dev/null 2>&1; then
|
|
msg_success "Le système fait maintenant confiance au Root CA Frogg."
|
|
else
|
|
msg_error "Échec lors de la mise à jour des certificats système."
|
|
fi
|
|
else
|
|
msg_error "Source introuvable dans $root_crt. Vérifie que l'étape 3 a réussi."
|
|
fi
|
|
|
|
# ---(Cron & Nettoyage final) ---
|
|
# C'est seulement MAINTENANT qu'on peut supprimer
|
|
rm -rf "${step_path}"
|
|
|
|
# ==================================================================
|
|
# [5/7] ATTRIBUTION DES DROITS
|
|
# ==================================================================
|
|
msg_warning "[5/7] Finalisation des droits et redémarrage des services..."
|
|
|
|
# Création du groupe si nécessaire
|
|
groupadd -f "$cert_group"
|
|
|
|
# Liste des services valides et actifs (utilisée aussi pour le cron)
|
|
local -a active_services=()
|
|
local -A processed_users=()
|
|
|
|
# Permissions de base (appliquées une seule fois)
|
|
chown root:"$cert_group" "$cert_key" "$cert_pfx" 2>/dev/null
|
|
chmod 640 "$cert_key" "$cert_pfx" 2>/dev/null
|
|
chmod 644 "$cert_crt" 2>/dev/null
|
|
|
|
# Groupe utilisé pour l'accès aux certificats
|
|
cert_group="ssl-cert"
|
|
|
|
# Parcours des services configurés pour ajouter l utilisateur au groupe ssl
|
|
for svc in $CONFIG_DEB_INSTALL_DEFAULT_CA_SERVICES; do
|
|
|
|
unit="${svc%.service}.service"
|
|
|
|
# Vérifie que l'unité existe réellement
|
|
load_state="$(systemctl show "$unit" --property=LoadState --value 2>/dev/null)"
|
|
[[ "$load_state" != "loaded" ]] && continue
|
|
|
|
# Vérifie que le service est actif
|
|
systemctl is-active --quiet "$unit" || continue
|
|
|
|
# Ajout à la liste des services à redémarrer
|
|
active_services+=("$unit")
|
|
|
|
# Récupération de l'utilisateur défini dans le service (plus fiable que pgrep/ps)
|
|
svc_user="$(systemctl show "$unit" --property=User --value 2>/dev/null)"
|
|
|
|
# Si User= n'est pas défini, systemd exécute le service en root
|
|
[[ -z "$svc_user" ]] && svc_user="root"
|
|
|
|
# Ignore root
|
|
[[ "$svc_user" == "root" ]] && continue
|
|
|
|
# Évite de traiter plusieurs fois le même utilisateur
|
|
[[ -n "${processed_users[$svc_user]}" ]] && continue
|
|
processed_users["$svc_user"]=1
|
|
|
|
msg_info "🔧 Configuration de $unit (Utilisateur : $svc_user)"
|
|
|
|
# Ajout de l'utilisateur au groupe ssl-cert
|
|
if usermod -aG "$cert_group" "$svc_user"; then
|
|
msg_success "Utilisateur $svc_user ajouté au groupe $cert_group."
|
|
else
|
|
msg_error "Impossible d'ajouter $svc_user au groupe $cert_group."
|
|
continue
|
|
fi
|
|
done
|
|
|
|
# Redémarrage immédiat des services pour prise en compte du nouveau groupe
|
|
for unit in "${active_services[@]}"; do
|
|
if systemctl restart "$unit"; then
|
|
msg_success "Service $unit redémarré avec succès."
|
|
else
|
|
msg_error "Impossible de redémarrer $unit."
|
|
fi
|
|
done
|
|
|
|
# ==================================================================
|
|
# [6/7] GÉNÉRATION PFX
|
|
# ==================================================================
|
|
msg_warning "[6/7] Génération du .pfx..."
|
|
|
|
# Détection du groupe actuel du dossier (normalement ssl-cert)
|
|
current_group="$(stat -c '%G' "$cert_dir")"
|
|
|
|
# ------------------------------------------------------------------
|
|
# Commande de génération du PFX
|
|
# IMPORTANT:
|
|
# - -legacy pour compatibilité maximale avec Jellyfin/.NET
|
|
# - -passout pass: pour mot de passe vide
|
|
# - exporte la chaîne complète via -certfile si fullchain.crt existe
|
|
# ------------------------------------------------------------------
|
|
pfx_input="$cert_crt"
|
|
cert_fullchain="${cert_dir}/fullchain.crt"
|
|
|
|
if [[ -f "$cert_fullchain" ]]; then
|
|
pfx_input="$cert_fullchain"
|
|
fi
|
|
|
|
pfx_cmd="openssl pkcs12 -export \
|
|
-out \"$cert_pfx\" \
|
|
-inkey \"$cert_key\" \
|
|
-in \"$pfx_input\" \
|
|
-passout pass: \
|
|
-keypbe AES-256-CBC -certpbe AES-256-CBC \
|
|
&& chown root:\"$current_group\" \"$cert_pfx\" \
|
|
&& chmod 640 \"$cert_pfx\""
|
|
|
|
if eval "$pfx_cmd"; then
|
|
|
|
# chown root:"$current_group" "$cert_key" "$cert_crt"
|
|
# chmod 640 "$cert_key"
|
|
# chmod 644 "$cert_crt"
|
|
msg_success "Fichier PFX généré avec succès."
|
|
else
|
|
msg_error "Échec de la génération du fichier PFX."
|
|
fi
|
|
|
|
# ==================================================================
|
|
# [7/7] PLANIFICATION
|
|
# ==================================================================
|
|
msg_warning "[7/7] Activation du renouvellement automatique..."
|
|
|
|
step_bin="$(command -v step)"
|
|
if [[ -z "$step_bin" ]]; then
|
|
msg_error "Le binaire 'step' est introuvable."
|
|
return 1
|
|
fi
|
|
|
|
# ------------------------------------------------------------------
|
|
# Commande de renouvellement
|
|
# ------------------------------------------------------------------
|
|
|
|
renew_cmd="$step_bin certificate renew \"$cert_crt\" \"$cert_key\" --force"
|
|
|
|
# ------------------------------------------------------------------
|
|
# Construction de la liste des services à redémarrer
|
|
# ------------------------------------------------------------------
|
|
|
|
if [[ ${#active_services[@]} -gt 0 ]]; then
|
|
restart_cmd="systemctl restart"
|
|
|
|
for unit in "${active_services[@]}"; do
|
|
restart_cmd+=" \"$unit\""
|
|
done
|
|
fi
|
|
|
|
# ------------------------------------------------------------------
|
|
# Commande complète du cron
|
|
# ------------------------------------------------------------------
|
|
|
|
# ajout du certificat à proxmox
|
|
proxmox_cmd='(command -v pvenode >/dev/null && pvenode cert set "'$cert_crt'" "'$cert_key'" --force 1 || true)'
|
|
if eval "$proxmox_cmd"; then
|
|
msg_info "Vérification proxmox effectuée"
|
|
fi
|
|
|
|
full_command="$renew_cmd >> /var/log/cert-renew.log 2>&1 \
|
|
&& $pfx_cmd \
|
|
&& chown root:\"$current_group\" \"$cert_key\" \"$cert_crt\" \
|
|
&& chmod 640 \"$cert_key\" \
|
|
&& chmod 644 \"$cert_crt\" \
|
|
&& $proxmox_cmd"
|
|
|
|
if [[ -n "$restart_cmd" ]]; then
|
|
full_command+=" && $restart_cmd"
|
|
msg_success "Creation de la commande Cron."
|
|
fi
|
|
|
|
# ------------------------------------------------------------------
|
|
# Installation du cron
|
|
# ------------------------------------------------------------------
|
|
|
|
update_cron_marker "$CONFIG_DEB_INSTALL_DEFAULT_CA_CRON" "0 0 1 * * $full_command"
|
|
|
|
# ------------------------------------------------------------------
|
|
# Redémarrage final (sécurité)
|
|
# ------------------------------------------------------------------
|
|
for unit in "${active_services[@]}"; do
|
|
if systemctl restart "$unit"; then
|
|
msg_success "Service $unit redémarré avec succès."
|
|
else
|
|
msg_error "Impossible de redémarrer $unit."
|
|
fi
|
|
done
|
|
|
|
msg_success "Infrastructure PKI prête. Groupe : $current_group"
|
|
|
|
msg_success " "
|
|
msg_success " ################################"
|
|
msg_success " # Tout est prêt et configuré ! # "
|
|
msg_success " ###########(${CONFIG_DEB_INSTALL_DEFAULT_CA_INSTALL_PATH}/)#"
|
|
msg_success " "
|
|
|
|
} |