Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
228 lines
7.5 KiB
Bash
Executable File
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
|