xpeditis2.0/infra/prod/scripts/00-bootstrap-common.sh
2026-09-07 21:40:50 +02:00

228 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# 00 - Durcissement commun aux deux noeuds (app-01 et db-01)
# =============================================================================
# A executer EN PREMIER sur chaque serveur, en sudo :
# scp infra/prod/scripts/00-bootstrap-common.sh deploy@<ip>:/tmp/
# ssh deploy@<ip> 'sudo bash /tmp/00-bootstrap-common.sh <role>'
#
# <role> = app | data
#
# Idempotent : peut etre relance sans risque.
set -euo pipefail
ROLE="${1:-}"
if [[ "$ROLE" != "app" && "$ROLE" != "data" ]]; then
echo "Usage: $0 <app|data>" >&2
exit 1
fi
if [[ "$EUID" -ne 0 ]]; then
echo "Ce script doit tourner en root (sudo)." >&2
exit 1
fi
log() { printf '\n>>> %s\n' "$*"; }
# --- 1. Paquets de base ------------------------------------------------------
log "Mise a jour du systeme"
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get upgrade -y -qq
apt-get install -y -qq \
ufw fail2ban unattended-upgrades apt-listchanges \
chrony auditd audispd-plugins \
curl gnupg ca-certificates jq git rsync htop ncdu \
needrestart
# --- 2. Mises a jour de securite automatiques --------------------------------
log "Activation des mises a jour de securite automatiques"
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'CONF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
CONF
cat > /etc/apt/apt.conf.d/50unattended-upgrades <<'CONF'
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Redemarrage automatique la nuit SI un paquet noyau l'exige.
// Fenetre choisie hors des heures ouvrees des transitaires europeens.
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
Unattended-Upgrade::Automatic-Reboot-Time "04:30";
Unattended-Upgrade::Mail "";
CONF
systemctl enable --now unattended-upgrades
# --- 3. SSH ------------------------------------------------------------------
log "Durcissement SSH"
cat > /etc/ssh/sshd_config.d/99-xpeditis-hardening.conf <<'CONF'
# Authentification par cle uniquement.
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PermitEmptyPasswords no
PubkeyAuthentication yes
AuthenticationMethods publickey
# Reduction de surface.
X11Forwarding no
AllowAgentForwarding no
PermitTunnel no
GatewayPorts no
# Anti brute-force / sessions fantomes.
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2
# Cryptographie moderne uniquement.
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
Macs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
AllowUsers deploy
CONF
# Retire les cles d'hote faibles si presentes.
rm -f /etc/ssh/ssh_host_dsa_key* /etc/ssh/ssh_host_ecdsa_key* || true
sshd -t
systemctl restart ssh 2>/dev/null || systemctl restart sshd
# --- 4. fail2ban -------------------------------------------------------------
log "Configuration fail2ban"
cat > /etc/fail2ban/jail.d/xpeditis.local <<'CONF'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 4
backend = systemd
# Ne jamais se bannir soi-meme depuis le reseau prive.
ignoreip = 127.0.0.1/8 ::1 10.10.0.0/16
[sshd]
enabled = true
mode = aggressive
maxretry = 3
bantime = 24h
CONF
systemctl enable --now fail2ban
systemctl restart fail2ban
# --- 5. Parametres noyau -----------------------------------------------------
log "Durcissement sysctl"
cat > /etc/sysctl.d/99-xpeditis-hardening.conf <<'CONF'
# Reseau
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.tcp_syncookies = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_source_route = 0
# Memoire / noyau
kernel.randomize_va_space = 2
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.yama.ptrace_scope = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.suid_dumpable = 0
# Capacite : k3s et PostgreSQL ouvrent beaucoup de descripteurs.
fs.file-max = 2097152
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 524288
CONF
sysctl --system >/dev/null
# --- 6. Journalisation -------------------------------------------------------
log "Limitation des journaux systemd (evite de saturer le disque)"
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-xpeditis.conf <<'CONF'
[Journal]
SystemMaxUse=2G
SystemMaxFileSize=200M
MaxRetentionSec=30day
Compress=yes
CONF
systemctl restart systemd-journald
# --- 7. Horloge --------------------------------------------------------------
log "Synchronisation horaire (obligatoire : JWT, TLS, audit_logs)"
timedatectl set-timezone Europe/Paris
systemctl enable --now chrony
# --- 8. Audit ----------------------------------------------------------------
log "Regles auditd minimales"
cat > /etc/audit/rules.d/99-xpeditis.rules <<'CONF'
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /var/log/auth.log -p wa -k authlog
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k rootcmd
CONF
augenrules --load >/dev/null 2>&1 || true
systemctl enable --now auditd
# --- 9. Pare-feu local -------------------------------------------------------
# Le firewall Hetzner Cloud ne filtre QUE les interfaces publiques. UFW prend
# en charge le reseau prive, ou transite le trafic PostgreSQL/Redis.
log "Configuration UFW (role: $ROLE)"
ufw --force reset >/dev/null
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp comment 'SSH'
if [[ "$ROLE" == "app" ]]; then
ufw allow 80/tcp comment 'HTTP (redirection + ACME)'
ufw allow 443/tcp comment 'HTTPS'
ufw allow 6443/tcp comment 'API k3s'
# Reseau prive : le noeud app doit joindre db-01, pas l'inverse.
ufw allow from 10.10.0.0/16 to any port 10250 proto tcp comment 'kubelet metrics'
else
# Seul app-01 (IP privee) peut atteindre PostgreSQL et Redis.
APP_PRIVATE_IP="${APP_PRIVATE_IP:-10.10.1.10}"
ufw allow from "${APP_PRIVATE_IP}" to any port 5432 proto tcp comment 'PostgreSQL <- app-01'
ufw allow from "${APP_PRIVATE_IP}" to any port 6379 proto tcp comment 'Redis <- app-01'
fi
ufw --force enable
ufw status verbose
# --- 10. Verifications finales ----------------------------------------------
log "Verifications"
echo " SSH root login : $(sshd -T 2>/dev/null | grep -i '^permitrootlogin' || echo '?')"
echo " Password auth : $(sshd -T 2>/dev/null | grep -i '^passwordauthentication' || echo '?')"
echo " fail2ban : $(systemctl is-active fail2ban)"
echo " unattended-upgr. : $(systemctl is-active unattended-upgrades)"
echo " auditd : $(systemctl is-active auditd)"
echo " chrony : $(systemctl is-active chrony)"
log "Durcissement commun termine pour le role '$ROLE'."
echo "Etape suivante :"
if [[ "$ROLE" == "app" ]]; then
echo " sudo bash 02-setup-k3s-server.sh"
else
echo " sudo bash 01-setup-data-node.sh"
fi