hardening: angie config layout (_on/targets/modules) + sane root config + enable/disable helpers
This commit is contained in:
parent
247d33ae8a
commit
0116ac60b3
@ -2,7 +2,7 @@
|
|||||||
# 50-hardening — system defaults. Each sub-step y/N, all idempotent.
|
# 50-hardening — system defaults. Each sub-step y/N, all idempotent.
|
||||||
|
|
||||||
step_name="hardening"
|
step_name="hardening"
|
||||||
step_desc="ssh(ufw-safe), ufw, updates, unattended, tz, hostname, swap, locale, fail2ban"
|
step_desc="ssh, ufw, updates, unattended, tz, hostname, swap, locale, fail2ban, angie config"
|
||||||
step_run="run_hardening"
|
step_run="run_hardening"
|
||||||
|
|
||||||
run_hardening() {
|
run_hardening() {
|
||||||
@ -14,6 +14,7 @@ run_hardening() {
|
|||||||
_h_swap
|
_h_swap
|
||||||
_h_locale
|
_h_locale
|
||||||
_h_fail2ban
|
_h_fail2ban
|
||||||
|
_h_angie_config
|
||||||
ok "hardening pass complete"
|
ok "hardening pass complete"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,3 +187,184 @@ EOF
|
|||||||
fi
|
fi
|
||||||
ok "fail2ban installed + sshd jail enabled"
|
ok "fail2ban installed + sshd jail enabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── angie config: _on/ targets/ modules/ + sane root config ────────────────
|
||||||
|
_h_angie_config() {
|
||||||
|
if ! command -v angie >/dev/null 2>&1; then
|
||||||
|
echo " skip angie config (angie not installed — run the angie step first)"; return
|
||||||
|
fi
|
||||||
|
if ! yn "Set up Angie config layout (/etc/angie/_on targets modules) + sane root config?" y; then
|
||||||
|
echo " skip angie config"; return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local d=/etc/angie
|
||||||
|
sudo_ install -d -m 0755 "$d/_on" "$d/targets" "$d/modules" "$d/modules/http"
|
||||||
|
|
||||||
|
# ── extract packaging-specific values from the stock angie.conf ──
|
||||||
|
# Angie packages set user/pid/error_log differently per distro; preserve them.
|
||||||
|
local oldcfg="$d/angie.conf" angie_user angie_pid angie_err angie_modules=""
|
||||||
|
if [[ -f "$oldcfg" ]]; then
|
||||||
|
angie_user=$(grep -E '^\s*user\s+' "$oldcfg" | head -1 | awk '{print $2}' | tr -d ';')
|
||||||
|
angie_pid=$(grep -E '^\s*pid\s+' "$oldcfg" | head -1 | awk '{print $2}' | tr -d ';')
|
||||||
|
angie_err=$(grep -E '^\s*error_log\s+' "$oldcfg" | head -1 | awk '{print $2}' | tr -d ';')
|
||||||
|
# collect any load_module lines (dynamic modules)
|
||||||
|
angie_modules=$(grep -E '^\s*load_module\s+' "$oldcfg" || true)
|
||||||
|
fi
|
||||||
|
# sane defaults if not found
|
||||||
|
[[ -z "$angie_user" ]] && angie_user=$({ [[ "$DISTRO" == "arch" ]] && echo http || echo angie; })
|
||||||
|
[[ -z "$angie_pid" ]] && angie_pid=/run/angie.pid
|
||||||
|
[[ -z "$angie_err" ]] && angie_err=/var/log/angie/error.log
|
||||||
|
|
||||||
|
# backup the original once
|
||||||
|
if [[ -f "$oldcfg" && ! -f "$oldcfg.orig.bootstrap" ]]; then
|
||||||
|
sudo_ cp -a "$oldcfg" "$oldcfg.orig.bootstrap"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── write our root angie.conf (once — guarded, won't clobber later edits) ──
|
||||||
|
if grep -q '# managed by bootstrap' "$oldcfg" 2>/dev/null; then
|
||||||
|
ok "$oldcfg already bootstrap-managed — leaving it (keeps your edits)"
|
||||||
|
else
|
||||||
|
sudo_ tee "$oldcfg" >/dev/null <<EOF
|
||||||
|
# angie.conf — managed by bootstrap. Original backup: angie.conf.orig.bootstrap
|
||||||
|
# Edit freely; re-running the hardening step will NOT overwrite (it writes once).
|
||||||
|
|
||||||
|
user $angie_user;
|
||||||
|
worker_processes auto;
|
||||||
|
pid $angie_pid;
|
||||||
|
error_log $angie_err warn;
|
||||||
|
|
||||||
|
# dynamic modules carried over from the original package config (if any)
|
||||||
|
$angie_modules
|
||||||
|
# top-level context snippets (stream{}, env, etc.)
|
||||||
|
include /etc/angie/modules/*.conf;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/angie/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
|
||||||
|
'\$status \$body_bytes_sent "\$http_referer" "\$http_user_agent"';
|
||||||
|
access_log /var/log/angie/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
types_hash_max_size 2048;
|
||||||
|
|
||||||
|
server_tokens off;
|
||||||
|
client_max_body_size 16m;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 5;
|
||||||
|
gzip_min_length 256;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript
|
||||||
|
text/xml application/xml application/xml+rss text/javascript;
|
||||||
|
|
||||||
|
# http-level snippets: upstreams, maps, real_ip, proxy defaults
|
||||||
|
include /etc/angie/modules/http/*.conf;
|
||||||
|
|
||||||
|
# enabled hosts (symlinks from targets/*). _on/*.conf only — targets/ is staging.
|
||||||
|
include /etc/angie/_on/*.conf;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── http-level common snippet (real_ip + proxy defaults) ──
|
||||||
|
if [[ ! -f "$d/modules/http/00-common.conf" ]]; then
|
||||||
|
sudo_ tee "$d/modules/http/00-common.conf" >/dev/null <<'EOF'
|
||||||
|
# real_ip — trust private ranges + (commented Cloudflare). Uncomment/edit for your upstream.
|
||||||
|
set_real_ip_from 10.0.0.0/8;
|
||||||
|
set_real_ip_from 172.16.0.0/12;
|
||||||
|
set_real_ip_from 192.168.0.0/16;
|
||||||
|
set_real_ip_from 169.254.0.0/16;
|
||||||
|
# set_real_ip_from 173.245.48.0/20; # Cloudflare, see https://www.cloudflare.com/ips/
|
||||||
|
real_ip_header X-Forwarded-For;
|
||||||
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
# proxy defaults (inherited by every server/location unless overridden)
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── default catch-all server: unmatched Host -> drop ──
|
||||||
|
if [[ ! -f "$d/_on/00-default.conf" ]]; then
|
||||||
|
sudo_ tee "$d/_on/00-default.conf" >/dev/null <<'EOF'
|
||||||
|
# default_server: drop requests that match no enabled host (drive-by scanners, bare-IP)
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
listen 443 default_server;
|
||||||
|
listen [::]:443 default_server;
|
||||||
|
server_name _;
|
||||||
|
return 444;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── angie-enable / angie-disable helpers ──
|
||||||
|
_angie_helpers
|
||||||
|
|
||||||
|
# validate + (best-effort) reload
|
||||||
|
if sudo_ angie -t 2>&1; then
|
||||||
|
ok "angie config valid"
|
||||||
|
if command -v systemctl >/dev/null 2>&1 && systemctl is-active angie >/dev/null 2>&1; then
|
||||||
|
sudo_ systemctl reload angie 2>/dev/null && ok "angie reloaded"
|
||||||
|
else
|
||||||
|
echo " start angie when ready: sudo systemctl enable --now angie"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
err "angie -t failed — review $d/angie.conf (backup at $oldcfg.orig.bootstrap)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok "angie layout ready: $d/{angie.conf,_on/,targets/,modules/,modules/http/}"
|
||||||
|
echo " enable a site: angie-enable <name> (after writing $d/targets/<name>.conf)"
|
||||||
|
echo " disable a site: angie-disable <name>"
|
||||||
|
|
||||||
|
# ufw already opened 80/443 in _h_ufw
|
||||||
|
}
|
||||||
|
|
||||||
|
_angie_helpers() {
|
||||||
|
sudo_ tee /usr/local/bin/angie-enable >/dev/null <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# angie-enable <name> — symlink targets/<name>.conf into _on/ and validate.
|
||||||
|
set -euo pipefail
|
||||||
|
name="${1:-}"
|
||||||
|
[ -n "$name" ] || { echo "usage: angie-enable <name>" >&2; exit 2; }
|
||||||
|
target="/etc/angie/targets/${name}.conf"
|
||||||
|
link="/etc/angie/_on/${name}.conf"
|
||||||
|
[ -f "$target" ] || { echo "no such target: $target" >&2; exit 1; }
|
||||||
|
ln -sfn "../targets/${name}.conf" "$link"
|
||||||
|
echo "enabled: $name -> $link"
|
||||||
|
if command -v angie >/dev/null 2>&1; then
|
||||||
|
sudo angie -t || { echo "config invalid — review before reload" >&2; exit 1; }
|
||||||
|
sudo systemctl reload angie && echo "reloaded"
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
sudo_ tee /usr/local/bin/angie-disable >/dev/null <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# angie-disable <name> — remove the _on/<name>.conf symlink and reload.
|
||||||
|
set -euo pipefail
|
||||||
|
name="${1:-}"
|
||||||
|
[ -n "$name" ] || { echo "usage: angie-disable <name>" >&2; exit 2; }
|
||||||
|
link="/etc/angie/_on/${name}.conf"
|
||||||
|
[ -L "$link" ] || [ -e "$link" ] || { echo "$name not enabled ($link missing)" >&2; exit 1; }
|
||||||
|
rm -f "$link"
|
||||||
|
echo "disabled: $name"
|
||||||
|
if command -v angie >/dev/null 2>&1; then
|
||||||
|
sudo angie -t || true
|
||||||
|
sudo systemctl reload angie && echo "reloaded"
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
sudo_ chmod +x /usr/local/bin/angie-enable /usr/local/bin/angie-disable
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user