#!/usr/bin/env bash # UFW для HAProxy: SSH и stats из SSH_ALLOWED, 80/443 для всех. # Dry-run по умолчанию; --apply для включения. # # cp haproxy-ufw.env.example /etc/haproxy/security/haproxy-ufw.env # ./haproxy-ufw-apply.sh # ./haproxy-ufw-apply.sh --apply set -Eeuo pipefail ENV_FILE="${HAPROXY_UFW_ENV:-/etc/haproxy/security/haproxy-ufw.env}" APPLY=0 die() { echo "error: $*" >&2; exit 1; } log() { echo "[*] $*"; } usage() { cat <<'EOF' Usage: haproxy-ufw-apply.sh [--apply] [--env-file PATH] --apply выполнить ufw enable/reset (иначе только показ команд) --env-file путь к env (default: /etc/haproxy/security/haproxy-ufw.env) EOF } while [[ $# -gt 0 ]]; do case "$1" in --apply) APPLY=1; shift ;; --env-file) ENV_FILE=$2; shift 2 ;; -h | --help) usage; exit 0 ;; *) die "unknown option: $1" ;; esac done [[ -f $ENV_FILE ]] || die "missing env: $ENV_FILE (copy from haproxy-ufw.env.example)" # shellcheck source=/dev/null source "$ENV_FILE" SSH_ALLOWED=${SSH_ALLOWED:-} INBOUND_TCP=${INBOUND_TCP:-80 443} STATS_TCP=${STATS_TCP:-8404} UFW_IPV6=${UFW_IPV6:-no} [[ -n $SSH_ALLOWED ]] || die "SSH_ALLOWED is empty — lockout risk" command -v ufw >/dev/null 2>&1 || die "ufw not installed (apt install ufw)" run() { log "$*" [[ $APPLY -eq 1 ]] && "$@" } if [[ $APPLY -eq 0 ]]; then echo "=== DRY-RUN (pass --apply to execute) ===" fi if [[ $APPLY -eq 1 ]]; then sed -i "s/^IPV6=.*/IPV6=${UFW_IPV6}/" /etc/default/ufw 2>/dev/null || true fi run ufw --force reset run ufw default deny incoming run ufw default allow outgoing for cidr in $SSH_ALLOWED; do run ufw allow from "$cidr" to any port 22 proto tcp comment 'admin ssh' for port in $STATS_TCP; do run ufw allow from "$cidr" to any port "$port" proto tcp comment 'haproxy stats' done done for port in $INBOUND_TCP; do run ufw allow "$port/tcp" comment "haproxy service $port" done if [[ $APPLY -eq 1 ]]; then ufw --force enable ufw status verbose log "done" else echo "=== end dry-run ===" fi