Firewall-Pruefung: welche Ports offen sein muessen - und welche nicht
Auf RHEL ist firewalld ab Werk aktiv und gibt in aller Regel nur SSH
frei. Der Stack laeuft dann sauber, ist aber von aussen nicht zu
erreichen: die Agents kommen nicht durch den Receiver auf 8000, und im
Browser passiert nichts. Das war bisher nur eine Handvoll statischer
Beispielzeilen in der README und in install.sh.
Neu ist "cmk-manage.sh firewall". Erkannt werden firewalld, ufw,
nftables und iptables; welche Ports noetig sind, ergibt sich aus der
Konfiguration statt aus einer festen Liste:
- ohne Proxy Manager wird 5000 zum Pflichtport, mit ihm soll es zu
bleiben - offenes 5000 wird deshalb ausdruecklich angemerkt
- der Admin-Port kommt aus NPM_ADMIN_PORT, nicht fest aus 81
- FW_ROLE unterscheidet single/central/remote: eine Remote-Site
braucht 6557 eingehend, die Zentrale baut die Verbindungen selbst
auf und braucht dafuer nichts. Steht FW_ROLE=remote bei
CMK_LIVESTATUS_TCP=off, ist der Port zwar offen, es lauscht aber
niemand - auch darauf weist der Bericht hin.
- Event Console ueber FW_EC_SYSLOG / FW_EC_SNMPTRAP / FW_EC_TCP,
Agent dieses Hosts ueber FW_AGENT, alles Weitere (Grafana, NSCA)
ueber FW_EXTRA_PORTS
Syslog und SNMP-Traps laufen ueber UDP, eine TCP-Freigabe nuetzt ihnen
nichts. Ports werden deshalb durchweg als nummer/protokoll gefuehrt -
beim Pruefen wie beim Erzeugen der Regeln. Bestehende Regeln werden
entsprechend gelesen: Portbereiche (6556-6558 bzw. 6556:6558) werden
aufgeloest, firewalld-Dienstnamen und Rich Rules zaehlen mit, bei
firewalld alle aktiven Zonen statt nur der Standardzone, und eine
ufw-Regel ohne Protokoll zaehlt fuer TCP und UDP - so wie ufw sie
anlegt.
"firewall open" zeigt die passenden Kommandos, --apply setzt sie nach
Rueckfrage, --source begrenzt sie auf ein Quellnetz (fuer Port 80 mit
Warnung, weil Lets Encrypt von aussen prueft). Ohne Befund ist der
Rueckgabewert 1, damit sich das auswerten laesst. In der Oberflaeche
steckt derselbe Bericht unter "Firewall pruefen".
Nebenbei: env_set hat Werte mit Leerzeichen samt Anfuehrungszeichen in
die laufende Umgebung exportiert. In der Datei gehoeren sie hin, im
Wert nicht - das fiel erst mit den Beschreibungen in FW_EXTRA_PORTS auf.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+445
-1
@@ -51,6 +51,9 @@ KOMMANDOS - Stack
|
||||
pull Images aktualisieren
|
||||
status Status von Containern und Sites anzeigen
|
||||
logs [-f] [DIENST] Logs anzeigen
|
||||
firewall [check|open [--apply] [--source CIDR]]
|
||||
Firewall pruefen: welche Ports der Stack braucht und
|
||||
ob sie offen sind (firewalld, ufw, nftables, iptables)
|
||||
selftest Skripte auf bekannte Fallstricke pruefen
|
||||
tui-check Testzeilen fuer die Rahmendarstellung ausgeben
|
||||
(hilft bei q/x/l/m statt Linien, etwa in PuTTY)
|
||||
@@ -2963,6 +2966,12 @@ cert|CERT_DOMAIN|text|FQDN fuer selbstsignierte Zertifikate||
|
||||
cert|CERT_DAYS|int|Gueltigkeit in Tagen||
|
||||
cert|CERT_COUNTRY|text|Laenderkuerzel||
|
||||
cert|CERT_ORG|text|Organisation||
|
||||
firewall|FW_ROLE|choice|Rolle im verteilten Monitoring|single:central:remote|
|
||||
firewall|FW_EC_SYSLOG|choice|Event Console: Syslog annehmen (514)|off:udp:tcp:beide|
|
||||
firewall|FW_EC_SNMPTRAP|choice|Event Console: SNMP-Traps (162/udp)|off:on|
|
||||
firewall|FW_EC_TCP|choice|Event Console: Status ueber TCP (6558)|off:on|
|
||||
firewall|FW_AGENT|choice|Checkmk-Agent auf diesem Host (6556)|off:on|
|
||||
firewall|FW_EXTRA_PORTS|text|Weitere Ports (3000/tcp=Grafana,...)||1
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -2976,6 +2985,7 @@ browser|Terminal-Browser
|
||||
paths|Verzeichnisse
|
||||
cert|Selbstsignierte Zertifikate
|
||||
backup|Backup-Automatik
|
||||
firewall|Firewall: was offen sein muss
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -3025,6 +3035,23 @@ settings_validate_key() {
|
||||
*[!a-zA-Z0-9_]*) echo "Ein Site-Name darf nur Buchstaben, Ziffern und _ enthalten."; return 1 ;;
|
||||
esac
|
||||
[ "${#val}" -le 16 ] || { echo "Ein Site-Name darf hoechstens 16 Zeichen lang sein."; return 1; } ;;
|
||||
FW_EXTRA_PORTS)
|
||||
[ -z "$val" ] && return 0
|
||||
local e pp
|
||||
while IFS= read -r e; do
|
||||
e="$(printf '%s' "$e" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
|
||||
[ -n "$e" ] || continue
|
||||
pp="${e%%=*}"
|
||||
case "$pp" in
|
||||
[0-9]*/tcp|[0-9]*/udp|[0-9]*) : ;;
|
||||
*) echo "'$pp' ist kein Port. Erwartet wird 3000/tcp=Grafana,5667/tcp=NSCA"
|
||||
return 1 ;;
|
||||
esac
|
||||
case "${pp%/*}" in
|
||||
*[!0-9]*) echo "'$pp' ist keine Portnummer."; return 1 ;;
|
||||
esac
|
||||
done < <(printf '%s\n' "$val" | tr ',' '\n')
|
||||
;;
|
||||
CMK_IMAGE|NPM_IMAGE|BROWSH_IMAGE|CARBONYL_IMAGE)
|
||||
if [ -n "$val" ] && image_is_short_name "$val"; then
|
||||
echo "Bitte vollqualifiziert angeben (z.B. docker.io/...) - Podman
|
||||
@@ -5091,6 +5118,43 @@ gui_cert() {
|
||||
ui_run "Zertifikat erzeugen" bash -c "cd '$PROJECT_DIR' && '$SELF' cert --domain '$domain' --days '$days' ${a[*]+${a[*]}}"
|
||||
}
|
||||
|
||||
gui_firewall() {
|
||||
local tmp rc=0
|
||||
tmp="$(mktemp)"
|
||||
cmd_firewall check >"$tmp" 2>&1 || rc=$?
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
ui_text "Firewall - alles offen, was gebraucht wird" "$tmp"
|
||||
rm -f "$tmp"; return 0
|
||||
fi
|
||||
ui_text "Firewall - es fehlen Freigaben" "$tmp"
|
||||
rm -f "$tmp"
|
||||
|
||||
ui_yesno "Firewall" "Es fehlen Freigaben.
|
||||
|
||||
Sollen die benoetigten Ports jetzt geoeffnet werden?
|
||||
Die Regeln werden dauerhaft gesetzt." || return 0
|
||||
|
||||
local src=""
|
||||
if ui_yesno "Firewall" "Nur fuer ein bestimmtes Quellnetz freigeben?
|
||||
|
||||
Ja = nur dieses Netz darf zugreifen
|
||||
Nein = Freigabe fuer alle Quellen"; then
|
||||
src="$(ui_input "Firewall" "Quellnetz in CIDR-Schreibweise:" "$(primary_ip | sed 's/\.[0-9]*$/.0\/24/')")" || src=""
|
||||
fi
|
||||
|
||||
local -a a=(firewall open --apply --yes)
|
||||
if [ -n "$src" ]; then a+=(--source "$src"); fi
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
ui_run "Firewall freigeben" "$SELF" "${a[@]}" || true
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
gui_run_interactive sudo -- "$SELF" "${a[@]}"
|
||||
else
|
||||
ui_msg "Firewall" "Dafuer werden root-Rechte benoetigt.
|
||||
Bitte als root erneut aufrufen."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
gui_main() {
|
||||
ui_require
|
||||
while :; do
|
||||
@@ -5110,6 +5174,7 @@ Backups : $BACKUP_DIR" \
|
||||
proxy "Proxy-Hosts anlegen/verwalten (HTTPS fuer Checkmk)" \
|
||||
browser "Terminal-Browser (Proxy Manager lokal bedienen)" \
|
||||
cert "Selbstsigniertes Zertifikat erzeugen" \
|
||||
firewall "Firewall pruefen (welche Ports muessen offen sein)" \
|
||||
config "Einstellungen (.env) - menuegefuehrt" \
|
||||
shell "Root-Shell im Checkmk-Container" \
|
||||
quit "Beenden")" || break
|
||||
@@ -5124,7 +5189,8 @@ Backups : $BACKUP_DIR" \
|
||||
image) gui_image_menu || true ;;
|
||||
proxy) gui_proxy_menu || true ;;
|
||||
browser) gui_browser_menu || true ;;
|
||||
cert) gui_cert || true ;;
|
||||
cert) gui_cert || true ;;
|
||||
firewall) gui_firewall || true ;;
|
||||
config) gui_settings_menu || true ;;
|
||||
shell) gui_need_container || continue
|
||||
gui_run_interactive cmd_shell ;;
|
||||
@@ -5205,6 +5271,383 @@ ${C_BLD}Auswertung${C_RST}
|
||||
EOF
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# Firewall
|
||||
#
|
||||
# RHEL und Rocky haben firewalld ab Werk aktiv, und dort ist in aller
|
||||
# Regel nur SSH freigegeben. Der Agent-Receiver auf 8000 und HTTPS auf
|
||||
# 443 waeren damit dicht - die Agents kaemen nicht durch, ohne dass es
|
||||
# am Stack selbst laege.
|
||||
#
|
||||
# Geprueft werden firewalld, ufw, nftables und iptables. Welche Ports
|
||||
# noetig sind, haengt von der Konfiguration ab: ohne Proxy Manager
|
||||
# braucht der externe Proxy Zugriff auf 5000, als Remote-Site einer
|
||||
# verteilten Ueberwachung kommt Livestatus dazu, mit Event Console
|
||||
# Syslog und SNMP-Traps - und die laufen ueber UDP. Ports werden
|
||||
# deshalb durchweg als "nummer/protokoll" gefuehrt.
|
||||
# =====================================================================
|
||||
|
||||
fw_lc() { printf '%s' "${1:-}" | tr 'A-Z' 'a-z'; }
|
||||
|
||||
fw_on() { # Wert -> 0, wenn eingeschaltet
|
||||
case "$(fw_lc "${1:-}")" in on|true|1|yes|ja) return 0 ;; esac
|
||||
return 1
|
||||
}
|
||||
|
||||
fw_detect() {
|
||||
if command -v firewall-cmd >/dev/null 2>&1 \
|
||||
&& firewall-cmd --state >/dev/null 2>&1; then
|
||||
printf 'firewalld\n'; return 0
|
||||
fi
|
||||
if command -v ufw >/dev/null 2>&1 \
|
||||
&& ( set +o pipefail; ufw status 2>/dev/null | grep -qi '^Status: active' ); then
|
||||
printf 'ufw\n'; return 0
|
||||
fi
|
||||
if command -v nft >/dev/null 2>&1 && [ -n "$(nft list ruleset 2>/dev/null)" ]; then
|
||||
printf 'nftables\n'; return 0
|
||||
fi
|
||||
if command -v iptables >/dev/null 2>&1 \
|
||||
&& [ "$(iptables -S 2>/dev/null | wc -l)" -gt 3 ]; then
|
||||
printf 'iptables\n'; return 0
|
||||
fi
|
||||
printf 'keine\n'
|
||||
}
|
||||
|
||||
# firewalld kennt Zonen. Hat der Rechner mehrere Netzwerkkarten, haengen
|
||||
# sie oft in verschiedenen Zonen - dann sagt die Standardzone allein
|
||||
# nichts darueber aus, ob ein Port erreichbar ist.
|
||||
fw_zones() {
|
||||
local z
|
||||
z="$(firewall-cmd --get-active-zones 2>/dev/null | grep -v '^[[:space:]]' || true)"
|
||||
if [ -z "$z" ]; then z="$(firewall-cmd --get-default-zone 2>/dev/null || true)"; fi
|
||||
printf '%s\n' "$z" | sed '/^$/d'
|
||||
}
|
||||
|
||||
# Dienstnamen von firewalld auf port/protokoll abbilden
|
||||
fw_service_port() {
|
||||
case "$1" in
|
||||
ssh) printf '22/tcp\n' ;;
|
||||
http) printf '80/tcp\n' ;;
|
||||
https) printf '443/tcp\n' ;;
|
||||
cockpit) printf '9090/tcp\n' ;;
|
||||
syslog) printf '514/udp\n514/tcp\n' ;;
|
||||
syslog-tls) printf '6514/tcp\n' ;;
|
||||
snmptrap) printf '162/udp\n' ;;
|
||||
snmp) printf '161/udp\n' ;;
|
||||
*) : ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Welche Ports braucht der Stack in dieser Konfiguration?
|
||||
# port/proto|zweck|noetig (noetig: ja | nein | admin)
|
||||
# ---------------------------------------------------------------------
|
||||
fw_required_ports() {
|
||||
local role; role="$(fw_lc "${FW_ROLE:-single}")"
|
||||
case "$role" in central|remote) : ;; *) role=single ;; esac
|
||||
|
||||
if npm_enabled; then
|
||||
printf '80/tcp|HTTP und Lets-Encrypt-Pruefung|ja\n'
|
||||
printf '443/tcp|HTTPS (Checkmk, Zentrale, weitere Dienste)|ja\n'
|
||||
printf '%s/tcp|Adminoberflaeche des Proxy Managers|admin\n' "${NPM_ADMIN_PORT:-81}"
|
||||
printf '5000/tcp|Checkmk direkt - gehoert hinter den Proxy|nein\n'
|
||||
else
|
||||
printf '5000/tcp|Checkmk direkt - Ziel des externen Proxys|ja\n'
|
||||
fi
|
||||
|
||||
printf '8000/tcp|Agent-Receiver (registrierte Agents)|ja\n'
|
||||
|
||||
# --- Verteilte Ueberwachung ---------------------------------------
|
||||
# Als Remote-Site fragt die Zentrale Livestatus ab. Die Zentrale
|
||||
# selbst baut nur Verbindungen auf und braucht dafuer nichts offen.
|
||||
if [ "$role" = remote ]; then
|
||||
printf '6557/tcp|Livestatus - die Zentrale fragt diese Site ab|ja\n'
|
||||
elif fw_on "${CMK_LIVESTATUS_TCP:-off}"; then
|
||||
printf '6557/tcp|Livestatus ueber TCP|ja\n'
|
||||
else
|
||||
printf '6557/tcp|Livestatus - aus (CMK_LIVESTATUS_TCP=off)|nein\n'
|
||||
fi
|
||||
|
||||
# --- Event Console -------------------------------------------------
|
||||
case "$(fw_lc "${FW_EC_SYSLOG:-off}")" in
|
||||
udp) printf '514/udp|Event Console: Syslog|ja\n' ;;
|
||||
tcp) printf '514/tcp|Event Console: Syslog ueber TCP|ja\n' ;;
|
||||
beide|both|on)
|
||||
printf '514/udp|Event Console: Syslog|ja\n'
|
||||
printf '514/tcp|Event Console: Syslog ueber TCP|ja\n' ;;
|
||||
esac
|
||||
if fw_on "${FW_EC_SNMPTRAP:-off}"; then
|
||||
printf '162/udp|Event Console: SNMP-Traps|ja\n'
|
||||
fi
|
||||
if fw_on "${FW_EC_TCP:-off}"; then
|
||||
printf '6558/tcp|Event Console: Status und Ereignisse ueber TCP|ja\n'
|
||||
fi
|
||||
|
||||
# --- Agent auf diesem Host ----------------------------------------
|
||||
if fw_on "${FW_AGENT:-off}"; then
|
||||
printf '6556/tcp|Checkmk-Agent dieses Hosts (Pull-Betrieb)|ja\n'
|
||||
fi
|
||||
|
||||
# --- Frei eingetragene Ports ---------------------------------------
|
||||
# Form: 3000/tcp=Grafana,5667/tcp=NSCA
|
||||
local e pp d
|
||||
while IFS= read -r e; do
|
||||
e="$(printf '%s' "$e" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
|
||||
[ -n "$e" ] || continue
|
||||
pp="${e%%=*}"; d="${e#*=}"
|
||||
if [ "$d" = "$e" ] || [ -z "$d" ]; then d="zusaetzlich freigegeben"; fi
|
||||
case "$pp" in */tcp|*/udp) : ;; *) pp="$pp/tcp" ;; esac
|
||||
printf '%s|%s|ja\n' "$pp" "$d"
|
||||
done < <(printf '%s\n' "${FW_EXTRA_PORTS:-}" | tr ',' '\n')
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Offene Ports der erkannten Firewall einsammeln, "nummer/proto" je Zeile.
|
||||
# Bereiche (6000-6010 bzw. 6000:6010) bleiben stehen und werden beim
|
||||
# Vergleich aufgeloest.
|
||||
# ---------------------------------------------------------------------
|
||||
fw_open_ports() { # backend
|
||||
case "$1" in
|
||||
firewalld)
|
||||
{ local zone svc
|
||||
while IFS= read -r zone; do
|
||||
[ -n "$zone" ] || continue
|
||||
firewall-cmd --zone="$zone" --list-ports 2>/dev/null | tr ' ' '\n'
|
||||
firewall-cmd --zone="$zone" --list-services 2>/dev/null | tr ' ' '\n' \
|
||||
| while IFS= read -r svc; do
|
||||
if [ -n "$svc" ]; then fw_service_port "$svc"; fi
|
||||
done
|
||||
firewall-cmd --zone="$zone" --list-rich-rules 2>/dev/null \
|
||||
| sed -n 's/.*port port="\([0-9:-]*\)" protocol="\([a-z]*\)".*/\1\/\2/p'
|
||||
done < <(fw_zones)
|
||||
} | sed '/^$/d' | sort -u ;;
|
||||
ufw)
|
||||
local spec ports proto pp
|
||||
ufw status 2>/dev/null | awk 'NR>3 {print $1}' \
|
||||
| while IFS= read -r spec; do
|
||||
case "$spec" in *[0-9]*) : ;; *) continue ;; esac
|
||||
proto=""; ports="$spec"
|
||||
case "$spec" in
|
||||
*/tcp|*/udp) proto="${spec##*/}"; ports="${spec%/*}" ;;
|
||||
esac
|
||||
for pp in $(printf '%s' "$ports" | tr ',' ' '); do
|
||||
case "$pp" in *[!0-9:-]*) continue ;; esac
|
||||
if [ -n "$proto" ]; then
|
||||
printf '%s/%s\n' "$pp" "$proto"
|
||||
else
|
||||
printf '%s/tcp\n%s/udp\n' "$pp" "$pp"
|
||||
fi
|
||||
done
|
||||
done | sort -u ;;
|
||||
nftables)
|
||||
local proto rest pp
|
||||
nft list ruleset 2>/dev/null \
|
||||
| grep -oE '(tcp|udp) dport[[:space:]]*(\{[^}]*\}|[0-9]+(-[0-9]+)?)' \
|
||||
| sed 's/dport//; s/[{}]//g' \
|
||||
| while read -r proto rest; do
|
||||
for pp in $(printf '%s' "$rest" | tr ',' ' '); do
|
||||
printf '%s/%s\n' "$pp" "$proto"
|
||||
done
|
||||
done | sort -u ;;
|
||||
iptables)
|
||||
local line proto ports pp
|
||||
iptables -S 2>/dev/null | grep -E ' -j (ACCEPT|accept)$' \
|
||||
| while IFS= read -r line; do
|
||||
proto="$(printf '%s' "$line" | sed -n 's/.* -p \([a-z0-9]*\).*/\1/p')"
|
||||
case "$proto" in tcp|udp) : ;; *) continue ;; esac
|
||||
ports="$(printf '%s' "$line" \
|
||||
| grep -oE '\-\-(dport|dports) [0-9,:]+' \
|
||||
| sed 's/--dports\? //')"
|
||||
[ -n "$ports" ] || continue
|
||||
for pp in $(printf '%s' "$ports" | tr ',' ' '); do
|
||||
printf '%s/%s\n' "$pp" "$proto"
|
||||
done
|
||||
done | sort -u ;;
|
||||
*) : ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Steht port/proto in der Liste der offenen? Bereiche werden aufgeloest.
|
||||
fw_port_open() { # port proto (Liste in _FW_OPEN, eine je Zeile)
|
||||
local port="$1" proto="$2" e ep epr lo hi
|
||||
while IFS= read -r e; do
|
||||
[ -n "$e" ] || continue
|
||||
ep="${e%/*}"; epr="${e##*/}"
|
||||
[ "$epr" = "$proto" ] || continue
|
||||
case "$ep" in
|
||||
*[-:]*)
|
||||
lo="${ep%%[-:]*}"; hi="${ep##*[-:]}"
|
||||
case "$lo$hi" in *[!0-9]*) continue ;; esac
|
||||
if [ "$port" -ge "$lo" ] && [ "$port" -le "$hi" ]; then return 0; fi ;;
|
||||
*) if [ "$ep" = "$port" ]; then return 0; fi ;;
|
||||
esac
|
||||
done <<<"${_FW_OPEN:-}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Vorschlaege zum Oeffnen
|
||||
fw_open_cmds() { # backend port proto [quelle]
|
||||
local be="$1" port="$2" proto="$3" src="${4:-}" z
|
||||
case "$be" in
|
||||
firewalld)
|
||||
z="$(fw_zones | head -n1)"
|
||||
if [ -n "$src" ]; then
|
||||
printf "firewall-cmd --permanent --zone=%s --add-rich-rule='rule family=ipv4 source address=%s port port=%s protocol=%s accept'\n" \
|
||||
"${z:-public}" "$src" "$port" "$proto"
|
||||
else
|
||||
printf 'firewall-cmd --permanent --zone=%s --add-port=%s/%s\n' "${z:-public}" "$port" "$proto"
|
||||
fi ;;
|
||||
ufw)
|
||||
if [ -n "$src" ]; then
|
||||
printf 'ufw allow from %s to any port %s proto %s\n' "$src" "$port" "$proto"
|
||||
else
|
||||
printf 'ufw allow %s/%s\n' "$port" "$proto"
|
||||
fi ;;
|
||||
nftables)
|
||||
if [ -n "$src" ]; then
|
||||
printf 'nft add rule inet filter input ip saddr %s %s dport %s accept\n' "$src" "$proto" "$port"
|
||||
else
|
||||
printf 'nft add rule inet filter input %s dport %s accept\n' "$proto" "$port"
|
||||
fi ;;
|
||||
iptables)
|
||||
if [ -n "$src" ]; then
|
||||
printf 'iptables -I INPUT -s %s -p %s --dport %s -j ACCEPT\n' "$src" "$proto" "$port"
|
||||
else
|
||||
printf 'iptables -I INPUT -p %s --dport %s -j ACCEPT\n' "$proto" "$port"
|
||||
fi ;;
|
||||
esac
|
||||
}
|
||||
|
||||
cmd_firewall() {
|
||||
local sub="${1:-check}"; [ $# -gt 0 ] && shift || true
|
||||
case "$sub" in check|open) : ;; *) die "Unbekannt: firewall $sub (check|open)" ;; esac
|
||||
local apply="" src=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--apply) apply=1; shift ;;
|
||||
--yes|-y) ASSUME_YES=1; shift ;;
|
||||
--source) src="$2"; shift 2 ;;
|
||||
*) die "Unbekannte Option fuer 'firewall': $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
local be role; be="$(fw_detect)"
|
||||
role="$(fw_lc "${FW_ROLE:-single}")"
|
||||
case "$role" in central|remote) : ;; *) role=single ;; esac
|
||||
|
||||
printf '\n%sFirewall%s\n' "$C_BLD" "$C_RST"
|
||||
case "$be" in
|
||||
keine)
|
||||
test_result warn "Keine aktive Firewall erkannt"
|
||||
printf ' Entweder ist keine eingerichtet, oder die Pruefung braucht
|
||||
root-Rechte. Mit sudo erneut aufrufen.\n' ;;
|
||||
*) test_result ok "Erkannt: $be"
|
||||
if [ "$be" = firewalld ]; then
|
||||
printf ' Aktive Zonen: %s\n' "$(fw_zones | tr '\n' ' ' | sed 's/ $//')"
|
||||
fi ;;
|
||||
esac
|
||||
case "$role" in
|
||||
central) printf ' Rolle: Zentrale einer verteilten Ueberwachung\n' ;;
|
||||
remote) printf ' Rolle: Remote-Site einer verteilten Ueberwachung\n' ;;
|
||||
esac
|
||||
|
||||
_FW_OPEN=""
|
||||
if [ "$be" != keine ]; then
|
||||
_FW_OPEN="$(fw_open_ports "$be")"
|
||||
printf ' Offene Ports: %s\n' "$(printf '%s' "$_FW_OPEN" | tr '\n' ' ' | sed 's/ $//')"
|
||||
fi
|
||||
|
||||
printf '\n%sWas dieser Stack braucht%s\n' "$C_BLD" "$C_RST"
|
||||
printf ' %-10s %-48s %-7s %s\n' "PORT" "ZWECK" "NOETIG" "ZUSTAND"
|
||||
|
||||
local spec zweck need zustand port proto ist fehlend=0
|
||||
local -a todo=()
|
||||
while IFS='|' read -r spec zweck need; do
|
||||
[ -n "$spec" ] || continue
|
||||
port="${spec%/*}"; proto="${spec##*/}"
|
||||
ist=nein
|
||||
if [ "$be" != keine ] && fw_port_open "$port" "$proto"; then ist=ja; fi
|
||||
|
||||
case "$need:$ist" in
|
||||
ja:ja) zustand="${C_GRN}offen${C_RST}" ;;
|
||||
ja:nein) zustand="${C_RED}GESCHLOSSEN${C_RST}"; fehlend=$((fehlend+1)); todo+=("$spec") ;;
|
||||
admin:ja) zustand="offen - besser auf das Adminnetz begrenzen" ;;
|
||||
admin:nein) zustand="geschlossen" ;;
|
||||
nein:ja) zustand="${C_YEL}offen - sollte zu sein${C_RST}" ;;
|
||||
nein:nein) zustand="zu (richtig)" ;;
|
||||
esac
|
||||
if [ "$be" = keine ]; then zustand="nicht pruefbar"; fi
|
||||
printf ' %-10s %-48s %-7s %b\n' "$spec" "$zweck" "$need" "$zustand"
|
||||
done < <(fw_required_ports)
|
||||
|
||||
# Hinweise, die sich aus der Konfiguration ergeben
|
||||
local -a hinweise=()
|
||||
if [ "$role" = remote ] && ! fw_on "${CMK_LIVESTATUS_TCP:-off}"; then
|
||||
hinweise+=("Rolle 'remote', aber CMK_LIVESTATUS_TCP=off - dann lauscht auf 6557 nichts.
|
||||
Einschalten mit: $SELF config set CMK_LIVESTATUS_TCP on (danach 'up')")
|
||||
fi
|
||||
if [ "$role" = central ]; then
|
||||
hinweise+=("Als Zentrale baut diese Site die Verbindungen selbst auf: nach aussen
|
||||
muessen 6557/tcp und 443/tcp zu den Remote-Sites erlaubt sein. Eingehend
|
||||
braucht die Zentrale dafuer nichts - ausser dem, was oben steht.")
|
||||
fi
|
||||
if [ "${#hinweise[@]}" -gt 0 ]; then
|
||||
printf '\n%sHinweise%s\n' "$C_BLD" "$C_RST"
|
||||
local h; for h in "${hinweise[@]}"; do printf ' %s\n' "$h"; done
|
||||
fi
|
||||
|
||||
if [ "$be" = keine ]; then echo; return 0; fi
|
||||
|
||||
echo
|
||||
if [ "$fehlend" -eq 0 ]; then
|
||||
ok "Alle benoetigten Ports sind offen."
|
||||
echo; return 0
|
||||
fi
|
||||
|
||||
err "$fehlend benoetigte(r) Port(s) sind geschlossen."
|
||||
printf '\n%sZum Oeffnen%s\n' "$C_BLD" "$C_RST"
|
||||
local t
|
||||
for t in "${todo[@]}"; do
|
||||
printf ' %s\n' "$(fw_open_cmds "$be" "${t%/*}" "${t##*/}" "$src")"
|
||||
done
|
||||
case "$be" in
|
||||
firewalld) printf ' firewall-cmd --reload\n' ;;
|
||||
iptables) printf ' # dauerhaft machen: iptables-save bzw. das Paket iptables-persistent\n' ;;
|
||||
nftables) printf ' # dauerhaft machen: in /etc/nftables.conf uebernehmen\n' ;;
|
||||
esac
|
||||
if [ -n "$src" ]; then
|
||||
case " ${todo[*]} " in
|
||||
*" 80/tcp "*|*" 443/tcp "*)
|
||||
printf '\n Achtung: Lets Encrypt prueft die Domain von aussen ueber Port 80.
|
||||
Wird 80 auf ein Quellnetz begrenzt, schlaegt die Ausstellung fehl.\n' ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -n "$apply" ]; then
|
||||
echo
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
die "Dafuer werden root-Rechte benoetigt - bitte mit sudo erneut aufrufen."
|
||||
fi
|
||||
confirm "Diese Regeln jetzt setzen?" || die "Abgebrochen."
|
||||
local c
|
||||
for t in "${todo[@]}"; do
|
||||
c="$(fw_open_cmds "$be" "${t%/*}" "${t##*/}" "$src")"
|
||||
log "$c"
|
||||
eval "$c" || warn "Fehlgeschlagen: $c"
|
||||
done
|
||||
if [ "$be" = firewalld ]; then
|
||||
firewall-cmd --reload >/dev/null 2>&1 && ok "firewalld neu geladen." \
|
||||
|| warn "Neuladen fehlgeschlagen."
|
||||
fi
|
||||
ok "Regeln gesetzt."
|
||||
else
|
||||
printf '\n Automatisch setzen: %s firewall open --apply\n' "$SELF"
|
||||
printf ' Nur fuer ein Netz : %s firewall open --apply --source 10.0.0.0/24\n' "$SELF"
|
||||
fi
|
||||
echo
|
||||
return 1
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# Selbstpruefung
|
||||
#
|
||||
@@ -5393,6 +5836,7 @@ main() {
|
||||
config) cmd_config "$@" || true ;;
|
||||
selftest) cmd_selftest ;;
|
||||
tui-check) cmd_tui_check ;;
|
||||
firewall) cmd_firewall "$@" ;;
|
||||
help|-h|--help) usage ;;
|
||||
*) err "Unbekanntes Kommando: $cmd"; echo; usage; exit 1 ;;
|
||||
esac
|
||||
|
||||
@@ -73,14 +73,16 @@ env_set() {
|
||||
*$'\n'*) die "Ungueltiger Wert fuer '$key' (mehrzeilig)." ;;
|
||||
esac
|
||||
[ -n "$val" ] || [ -n "$allow_empty" ] || die "Leerer Wert fuer '$key' - abgebrochen."
|
||||
# Werte mit Leerzeichen in Anfuehrungszeichen setzen
|
||||
# Werte mit Leerzeichen gehoeren in der Datei in Anfuehrungszeichen -
|
||||
# in der Umgebung aber ohne, sonst stecken die Zeichen spaeter im Wert
|
||||
local quoted="$val"
|
||||
case "$val" in
|
||||
*" "*) case "$val" in \"*\") : ;; *) val="\"$val\"" ;; esac ;;
|
||||
*" "*) case "$val" in \"*\") : ;; *) quoted="\"$val\"" ;; esac ;;
|
||||
esac
|
||||
if grep -qE "^[#[:space:]]*${key}=" "$f"; then
|
||||
sed -i -E "s|^[#[:space:]]*${key}=.*|${key}=${val}|" "$f"
|
||||
sed -i -E "s|^[#[:space:]]*${key}=.*|${key}=${quoted}|" "$f"
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$val" >>"$f"
|
||||
printf '%s=%s\n' "$key" "$quoted" >>"$f"
|
||||
fi
|
||||
export "$key=$val"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user