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:
2026-09-20 19:46:33 +02:00
co-authored by Claude Opus 5
parent d06ecb2704
commit b912578f27
6 changed files with 722 additions and 28 deletions
+35
View File
@@ -185,3 +185,38 @@ CERT_DOMAIN=checkmk.example.local
CERT_DAYS=3650 CERT_DAYS=3650
CERT_COUNTRY=DE CERT_COUNTRY=DE
CERT_ORG="Beispiel GmbH" CERT_ORG="Beispiel GmbH"
# ---------------------------------------------------------------------
# Firewall: was von aussen erreichbar sein muss
#
# Diese Werte oeffnen nichts von selbst - sie sagen "cmk-manage.sh
# firewall", welche Ports dieser Aufbau braucht.
# ---------------------------------------------------------------------
# Rolle im verteilten Monitoring:
# single - eigenstaendige Site (Vorgabe)
# central - Zentrale; baut die Verbindungen selbst auf, braucht
# eingehend nichts zusaetzlich
# remote - Remote-Site; die Zentrale fragt hier Livestatus (6557) ab,
# dazu muss CMK_LIVESTATUS_TCP=on gesetzt sein
FW_ROLE=single
# Event Console: Syslog annehmen - off, udp, tcp oder beide (Port 514)
FW_EC_SYSLOG=off
# Event Console: SNMP-Traps annehmen (Port 162/udp)
FW_EC_SNMPTRAP=off
# Event Console: Status und Ereignisse ueber TCP (Port 6558)
FW_EC_TCP=off
# Laeuft auf diesem Host ein Checkmk-Agent, der im Pull-Betrieb
# abgefragt wird? (Port 6556/tcp)
FW_AGENT=off
# Weitere Ports, die mitgeprueft werden sollen - durch Komma getrennt,
# Beschreibung nach dem Gleichheitszeichen. Ohne Protokoll gilt tcp.
# Enthaelt eine Beschreibung Leerzeichen, gehoert der ganze Wert in
# Anfuehrungszeichen (das erledigt "cmk-manage.sh config set" selbst).
# FW_EXTRA_PORTS=3000/tcp=Grafana,5667/tcp=NSCA,514/udp=Syslog
FW_EXTRA_PORTS=
+110 -1
View File
@@ -557,6 +557,10 @@ Die wichtigsten Schalter:
| `BACKUP_DIR` | Ablage für **manuelle** Backups (Vorgabe `./backups`); geplante Jobs haben eigene Pfade | | `BACKUP_DIR` | Ablage für **manuelle** Backups (Vorgabe `./backups`); geplante Jobs haben eigene Pfade |
| `BACKUP_AUTO` | `on`/`off` – sollen die Backup-Jobs per cron laufen? | | `BACKUP_AUTO` | `on`/`off` – sollen die Backup-Jobs per cron laufen? |
| `CERT_DOMAIN`, `CERT_DAYS` | Vorgaben für selbstsignierte Zertifikate | | `CERT_DOMAIN`, `CERT_DAYS` | Vorgaben für selbstsignierte Zertifikate |
| `FW_ROLE` | `single`/`central`/`remote` – Rolle im verteilten Monitoring, steuert die Firewall-Prüfung |
| `FW_EC_SYSLOG`, `FW_EC_SNMPTRAP`, `FW_EC_TCP` | Event Console: Syslog (514), SNMP-Traps (162/udp), Status über TCP (6558) |
| `FW_AGENT` | läuft auf diesem Host ein Checkmk-Agent im Pull-Betrieb? (6556) |
| `FW_EXTRA_PORTS` | weitere Ports für die Prüfung, z. B. `3000/tcp=Grafana` |
### 7.1 Wer liest die `.env` – und warum gibt es sie zusätzlich zum Skript? ### 7.1 Wer liest die `.env` – und warum gibt es sie zusätzlich zum Skript?
@@ -1799,6 +1803,96 @@ mit aus.
## 13. Firewall ## 13. Firewall
RHEL und Rocky bringen firewalld ab Werk mit, und dort ist in der Regel nur
SSH freigegeben. Ein Stack, der sauber läuft, ist von außen trotzdem nicht
erreichbar – die Agents kommen nicht durch, und im Browser passiert nichts.
Deshalb prüft der Manager das auf Wunsch selbst:
```bash
./scripts/cmk-manage.sh firewall # Prüfbericht
./scripts/cmk-manage.sh firewall open # Kommandos nur anzeigen
sudo ./scripts/cmk-manage.sh firewall open --apply
sudo ./scripts/cmk-manage.sh firewall open --apply --source 10.0.0.0/24
```
Erkannt werden **firewalld**, **ufw**, **nftables** und **iptables** – in dieser
Reihenfolge, die erste aktive gewinnt. Bei firewalld werden alle *aktiven
Zonen* ausgewertet, nicht nur die Standardzone: hängen zwei Netzwerkkarten in
verschiedenen Zonen, zählt ein Port als offen, sobald ihn eine davon freigibt.
Neben einzelnen Ports werden auch Dienstnamen (`http`, `https`, `ssh`) und
Rich Rules berücksichtigt.
Welche Ports gebraucht werden, hängt an der Konfiguration. Ports werden
durchweg als `nummer/protokoll` geführt – Syslog und SNMP-Traps laufen über
UDP, und eine Freigabe für TCP nützt ihnen nichts.
**Immer:**
| Port | Zweck | Nötig |
|------|-------|-------|
| `80/tcp` | HTTP, Prüfung durch Let's Encrypt | nur mit `NPM_ENABLED=on` |
| `443/tcp` | HTTPS für Checkmk und weitere Dienste | nur mit `NPM_ENABLED=on` |
| `NPM_ADMIN_PORT/tcp` (81) | Adminoberfläche des Proxy Managers | nur aus dem Adminnetz |
| `5000/tcp` | Checkmk direkt | **nur** mit `NPM_ENABLED=off`, sonst geschlossen lassen |
| `8000/tcp` | Agent-Receiver (registrierte Agents) | immer |
**Verteiltes Monitoring** – über `FW_ROLE` gesteuert:
| Port | Zweck | Nötig |
|------|-------|-------|
| `6557/tcp` | Livestatus – die Zentrale fragt diese Site ab | bei `FW_ROLE=remote`, sonst nur mit `CMK_LIVESTATUS_TCP=on` |
| `443/tcp` | Konfigurationsabgleich und Automations-API der Zentrale | bei `FW_ROLE=remote` |
Die **Zentrale** (`FW_ROLE=central`) baut die Verbindungen selbst auf und
braucht eingehend nichts zusätzlich – dafür muss *ausgehend* 6557/tcp und
443/tcp zu den Remote-Sites erlaubt sein. Darauf weist der Bericht hin.
Ebenso auf den häufigsten Stolperstein: `FW_ROLE=remote` bei
`CMK_LIVESTATUS_TCP=off` – dann ist der Port zwar offen, aber es lauscht
niemand.
**Event Console und Agent** – jeweils eigener Schalter, weil das nicht jeder
Aufbau braucht:
| Port | Zweck | Schalter |
|------|-------|----------|
| `514/udp`, `514/tcp` | Syslog-Meldungen annehmen | `FW_EC_SYSLOG=off\|udp\|tcp\|beide` |
| `162/udp` | SNMP-Traps annehmen | `FW_EC_SNMPTRAP=on` |
| `6558/tcp` | Status und Ereignisse der Event Console über TCP | `FW_EC_TCP=on` |
| `6556/tcp` | Checkmk-Agent dieses Hosts (Pull-Betrieb) | `FW_AGENT=on` |
Alles Weitere – Grafana, NSCA, was sonst auf dem Rechner liegt – kommt in
`FW_EXTRA_PORTS`:
```bash
./scripts/cmk-manage.sh config set FW_EXTRA_PORTS "3000/tcp=Grafana,5667/tcp=NSCA"
```
Der Bericht markiert auch den umgekehrten Fall: Ist 5000 offen, obwohl der
Proxy Manager läuft, steht dort *„offen – sollte zu sein"*. Ohne Prüfbefund
endet `firewall` mit Rückgabewert 1, lässt sich also in eigenen Skripten
auswerten.
Portbereiche in bestehenden Regeln werden aufgelöst: Wer `6556-6558/tcp`
(firewalld, nftables) oder `6556:6558/tcp` (ufw, iptables) freigegeben hat,
bekommt alle drei Ports als offen gemeldet. Bei ufw zählt eine Regel ohne
Protokollangabe – `ufw allow 514` – für TCP **und** UDP, so wie ufw sie auch
anlegt.
`--source` begrenzt jede erzeugte Regel auf ein Quellnetz. Für 8000, 6557 und
514 ist das sinnvoll (nur die überwachten Hosts bzw. die Zentrale), für Port
80 nicht: Let's Encrypt prüft die Domain von außen, eine Begrenzung lässt die
Ausstellung scheitern. Darauf weist der Bericht hin.
> **Docker und ufw:** Veröffentlichte Container-Ports umgehen ufw sonst über die
> `DOCKER-USER`-Kette. Hier nicht – beide Container laufen im Host-Netz, es
> gelten die Hostregeln unverändert.
In der Oberfläche steckt derselbe Bericht unter **Firewall prüfen**, samt
Rückfrage, ob die fehlenden Freigaben gleich gesetzt werden sollen. Die
Schalter dazu liegen unter **Einstellungen → Firewall: was offen sein muss**.
### Von Hand
**firewalld (RHEL/Rocky/Alma):** **firewalld (RHEL/Rocky/Alma):**
```bash ```bash
@@ -1806,6 +1900,15 @@ sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-port=8000/tcp # Agent-Receiver sudo firewall-cmd --permanent --add-port=8000/tcp # Agent-Receiver
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept' sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept'
# Verteiltes Monitoring: Livestatus nur fuer die Zentrale
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.5/32 port port=6557 protocol=tcp accept'
# Event Console: Syslog und SNMP-Traps (UDP!)
sudo firewall-cmd --permanent --add-service=syslog # 514/udp
sudo firewall-cmd --permanent --add-service=snmptrap # 162/udp
sudo firewall-cmd --permanent --add-port=6558/tcp # Status ueber TCP
sudo firewall-cmd --reload sudo firewall-cmd --reload
# Bei abweichendem Admin-Port (z.B. 10443) stattdessen dessen Nummer freigeben - # Bei abweichendem Admin-Port (z.B. 10443) stattdessen dessen Nummer freigeben -
@@ -1819,6 +1922,9 @@ sudo ufw allow 80/tcp
sudo ufw allow 443/tcp sudo ufw allow 443/tcp
sudo ufw allow 8000/tcp sudo ufw allow 8000/tcp
sudo ufw allow from 10.0.0.0/24 to any port 81 proto tcp sudo ufw allow from 10.0.0.0/24 to any port 81 proto tcp
sudo ufw allow from 10.0.0.5 to any port 6557 proto tcp # Livestatus fuer die Zentrale
sudo ufw allow 514/udp # Event Console: Syslog
sudo ufw allow 162/udp # Event Console: SNMP-Traps
sudo ufw enable sudo ufw enable
``` ```
@@ -1845,14 +1951,16 @@ sudo ./scripts/cmk-manage.sh gui
│ │ │ │
│ status Status von Containern und Sites │ │ status Status von Containern und Sites │
│ stack Stack steuern (Start/Stop/Logs/Update) │ │ stack Stack steuern (Start/Stop/Logs/Update) │
│ backup Backup erstellen │ │ backup Backup erstellen / planen │
│ restore Backup wiederherstellen │ │ restore Backup wiederherstellen │
│ import Site von Direktinstallation importieren │ │ import Site von Direktinstallation importieren │
│ manage Backups verwalten (Liste/Details/Löschen) │ │ manage Backups verwalten (Liste/Details/Löschen) │
│ sites Sites im Container verwalten │ │ sites Sites im Container verwalten │
│ image Checkmk-Image beschaffen/auswählen │ │ image Checkmk-Image beschaffen/auswählen │
│ proxy Proxy-Hosts anlegen/verwalten (HTTPS) │
│ browser Terminal-Browser (Proxy Manager lokal) │ │ browser Terminal-Browser (Proxy Manager lokal) │
│ cert Selbstsigniertes Zertifikat erzeugen │ │ cert Selbstsigniertes Zertifikat erzeugen │
│ firewall Firewall prüfen (benötigte Ports) │
│ config Einstellungen (.env) - menügeführt │ │ config Einstellungen (.env) - menügeführt │
│ shell Root-Shell im Checkmk-Container │ │ shell Root-Shell im Checkmk-Container │
│ quit Beenden │ │ quit Beenden │
@@ -2024,6 +2132,7 @@ Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut.
| `npm-reset` | Datenbank beiseitelegen, damit das Konto neu entsteht | | `npm-reset` | Datenbank beiseitelegen, damit das Konto neu entsteht |
| `proxy status\|list\|certs\|add\|del` | Proxy-Hosts über die API anlegen und verwalten | | `proxy status\|list\|certs\|add\|del` | Proxy-Hosts über die API anlegen und verwalten |
| `cert …` | selbstsigniertes Zertifikat erzeugen | | `cert …` | selbstsigniertes Zertifikat erzeugen |
| `firewall [check\|open]` | prüfen, ob die benötigten Ports offen sind (firewalld, ufw, nftables, iptables) |
| `shell` | Root-Shell im Checkmk-Container | | `shell` | Root-Shell im Checkmk-Container |
| `omd …` | beliebiges `omd`-Kommando im Container | | `omd …` | beliebiges `omd`-Kommando im Container |
+107 -1
View File
@@ -560,6 +560,10 @@ The most important settings:
| `BACKUP_DIR` | location for **manual** backups (default `./backups`); scheduled jobs have their own paths | | `BACKUP_DIR` | location for **manual** backups (default `./backups`); scheduled jobs have their own paths |
| `BACKUP_AUTO` | `on`/`off` – should the backup jobs run via cron? | | `BACKUP_AUTO` | `on`/`off` – should the backup jobs run via cron? |
| `CERT_DOMAIN`, `CERT_DAYS` | defaults for self-signed certificates | | `CERT_DOMAIN`, `CERT_DAYS` | defaults for self-signed certificates |
| `FW_ROLE` | `single`/`central`/`remote` – role in distributed monitoring, drives the firewall check |
| `FW_EC_SYSLOG`, `FW_EC_SNMPTRAP`, `FW_EC_TCP` | Event Console: syslog (514), SNMP traps (162/udp), status over TCP (6558) |
| `FW_AGENT` | does a Checkmk agent run on this host in pull mode? (6556) |
| `FW_EXTRA_PORTS` | additional ports for the check, e.g. `3000/tcp=Grafana` |
### 7.1 Who reads `.env` – and why does it exist alongside the script? ### 7.1 Who reads `.env` – and why does it exist alongside the script?
@@ -1795,6 +1799,93 @@ for you.
## 13. Firewall ## 13. Firewall
RHEL and Rocky ship firewalld enabled, and it normally allows SSH only. A stack
that runs perfectly is still unreachable from outside – agents cannot get
through and the browser shows nothing. The manager therefore checks this for
you:
```bash
./scripts/cmk-manage.sh firewall # report
./scripts/cmk-manage.sh firewall open # only print the commands
sudo ./scripts/cmk-manage.sh firewall open --apply
sudo ./scripts/cmk-manage.sh firewall open --apply --source 10.0.0.0/24
```
**firewalld**, **ufw**, **nftables** and **iptables** are detected in that
order; the first active one wins. For firewalld all *active zones* are
evaluated, not just the default zone: if two interfaces sit in different zones,
a port counts as open as soon as one of them allows it. Besides individual
ports, service names (`http`, `https`, `ssh`) and rich rules are taken into
account.
Which ports are needed depends on the configuration. Ports are handled as
`number/protocol` throughout – syslog and SNMP traps use UDP, and a TCP rule
does nothing for them.
**Always:**
| Port | Purpose | Needed |
|------|---------|--------|
| `80/tcp` | HTTP, Let's Encrypt challenge | only with `NPM_ENABLED=on` |
| `443/tcp` | HTTPS for Checkmk and other services | only with `NPM_ENABLED=on` |
| `NPM_ADMIN_PORT/tcp` (81) | Proxy Manager admin UI | administration network only |
| `5000/tcp` | Checkmk directly | **only** with `NPM_ENABLED=off`, keep closed otherwise |
| `8000/tcp` | agent receiver (registered agents) | always |
**Distributed monitoring** – driven by `FW_ROLE`:
| Port | Purpose | Needed |
|------|---------|--------|
| `6557/tcp` | Livestatus – the central site queries this one | with `FW_ROLE=remote`, otherwise only with `CMK_LIVESTATUS_TCP=on` |
| `443/tcp` | configuration sync and automation API of the central site | with `FW_ROLE=remote` |
The **central site** (`FW_ROLE=central`) opens the connections itself and
needs nothing extra inbound – but *outbound* 6557/tcp and 443/tcp to the
remote sites must be allowed. The report points this out, as well as the most
common trap: `FW_ROLE=remote` together with `CMK_LIVESTATUS_TCP=off` – the
port is open but nothing listens on it.
**Event Console and agent** – each has its own switch, because not every setup
needs them:
| Port | Purpose | Switch |
|------|---------|--------|
| `514/udp`, `514/tcp` | accept syslog messages | `FW_EC_SYSLOG=off\|udp\|tcp\|beide` |
| `162/udp` | accept SNMP traps | `FW_EC_SNMPTRAP=on` |
| `6558/tcp` | Event Console status and events over TCP | `FW_EC_TCP=on` |
| `6556/tcp` | Checkmk agent of this host (pull mode) | `FW_AGENT=on` |
Anything else – Grafana, NSCA, whatever else lives on the machine – goes into
`FW_EXTRA_PORTS`:
```bash
./scripts/cmk-manage.sh config set FW_EXTRA_PORTS "3000/tcp=Grafana,5667/tcp=NSCA"
```
The report flags the reverse case too: if 5000 is open while the Proxy Manager
is running, it reads *"open – should be closed"*. When something is missing,
`firewall` exits with status 1, so you can evaluate it in your own scripts.
Port ranges in existing rules are resolved: if you allowed `6556-6558/tcp`
(firewalld, nftables) or `6556:6558/tcp` (ufw, iptables), all three ports are
reported as open. With ufw a rule without a protocol – `ufw allow 514` –
counts for TCP **and** UDP, which is exactly how ufw creates it.
`--source` restricts every generated rule to a source network. That makes
sense for 8000, 6557 and 514 (only the monitored hosts or the central site),
but not for port 80: Let's Encrypt probes the domain from the internet, and a
restriction makes issuance fail. The report points this out.
> **Docker and ufw:** published container ports normally bypass ufw through the
> `DOCKER-USER` chain. Not here – both containers run in the host network, so
> the host rules apply unchanged.
The GUI offers the same report under **Firewall prüfen**, including a prompt to
set the missing rules right away. The switches live under **Einstellungen →
Firewall: was offen sein muss**.
### By hand
**firewalld (RHEL/Rocky/Alma):** **firewalld (RHEL/Rocky/Alma):**
```bash ```bash
@@ -1802,6 +1893,15 @@ sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-port=8000/tcp # agent receiver sudo firewall-cmd --permanent --add-port=8000/tcp # agent receiver
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept' sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept'
# distributed monitoring: Livestatus for the central site only
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.5/32 port port=6557 protocol=tcp accept'
# Event Console: syslog and SNMP traps (UDP!)
sudo firewall-cmd --permanent --add-service=syslog # 514/udp
sudo firewall-cmd --permanent --add-service=snmptrap # 162/udp
sudo firewall-cmd --permanent --add-port=6558/tcp # status over TCP
sudo firewall-cmd --reload sudo firewall-cmd --reload
# With a different admin port (e.g. 10443) open that number instead - # With a different admin port (e.g. 10443) open that number instead -
@@ -1815,6 +1915,9 @@ sudo ufw allow 80/tcp
sudo ufw allow 443/tcp sudo ufw allow 443/tcp
sudo ufw allow 8000/tcp sudo ufw allow 8000/tcp
sudo ufw allow from 10.0.0.0/24 to any port 81 proto tcp sudo ufw allow from 10.0.0.0/24 to any port 81 proto tcp
sudo ufw allow from 10.0.0.5 to any port 6557 proto tcp # Livestatus for the central site
sudo ufw allow 514/udp # Event Console: syslog
sudo ufw allow 162/udp # Event Console: SNMP traps
sudo ufw enable sudo ufw enable
``` ```
@@ -1844,14 +1947,16 @@ The menu labels are German; the command table in
│ │ │ │
│ status Status von Containern und Sites │ │ status Status von Containern und Sites │
│ stack Stack steuern (Start/Stop/Logs/Update) │ │ stack Stack steuern (Start/Stop/Logs/Update) │
│ backup Backup erstellen │ │ backup Backup erstellen / planen │
│ restore Backup wiederherstellen │ │ restore Backup wiederherstellen │
│ import Site von Direktinstallation importieren │ │ import Site von Direktinstallation importieren │
│ manage Backups verwalten (Liste/Details/Löschen) │ │ manage Backups verwalten (Liste/Details/Löschen) │
│ sites Sites im Container verwalten │ │ sites Sites im Container verwalten │
│ image Checkmk-Image beschaffen/auswählen │ │ image Checkmk-Image beschaffen/auswählen │
│ proxy Proxy-Hosts anlegen/verwalten (HTTPS) │
│ browser Terminal-Browser (Proxy Manager lokal) │ │ browser Terminal-Browser (Proxy Manager lokal) │
│ cert Selbstsigniertes Zertifikat erzeugen │ │ cert Selbstsigniertes Zertifikat erzeugen │
│ firewall Firewall prüfen (benötigte Ports) │
│ config Einstellungen (.env) - menügeführt │ │ config Einstellungen (.env) - menügeführt │
│ shell Root-Shell im Checkmk-Container │ │ shell Root-Shell im Checkmk-Container │
│ quit Beenden │ │ quit Beenden │
@@ -2022,6 +2127,7 @@ A file chooser with directory navigation is built in.
| `npm-reset` | move the database aside so the account is recreated | | `npm-reset` | move the database aside so the account is recreated |
| `proxy status\|list\|certs\|add\|del` | create and manage proxy hosts through the API | | `proxy status\|list\|certs\|add\|del` | create and manage proxy hosts through the API |
| `cert …` | create a self-signed certificate | | `cert …` | create a self-signed certificate |
| `firewall [check\|open]` | check whether the required ports are open (firewalld, ufw, nftables, iptables) |
| `shell` | root shell in the Checkmk container | | `shell` | root shell in the Checkmk container |
| `omd …` | any `omd` command inside the container | | `omd …` | any `omd` command inside the container |
+19 -21
View File
@@ -312,29 +312,27 @@ fi
# Firewall-Hinweise # Firewall-Hinweise
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
print_firewall_hint() { print_firewall_hint() {
local be=""
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
cat <<'EOF' be=firewalld
elif command -v ufw >/dev/null 2>&1 \
Firewall (firewalld) - empfohlene Regeln: && ( set +o pipefail; ufw status 2>/dev/null | grep -qi '^Status: active' ); then
firewall-cmd --permanent --add-service=http be=ufw
firewall-cmd --permanent --add-service=https elif command -v nft >/dev/null 2>&1 && [ -n "$(nft list ruleset 2>/dev/null)" ]; then
firewall-cmd --permanent --add-port=8000/tcp # Agent-Receiver be=nftables
# Admin-Oberflaeche des Proxy Managers nur aus dem Admin-Netz:
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept'
# Checkmk-Port 5000 NICHT nach aussen oeffnen (nur ueber den Proxy)
firewall-cmd --reload
EOF
elif command -v ufw >/dev/null 2>&1; then
cat <<'EOF'
Firewall (ufw) - empfohlene Regeln:
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8000/tcp # Agent-Receiver
ufw allow from 10.0.0.0/24 to any port 81 proto tcp # Proxy-Manager-Admin
# Port 5000 (Checkmk direkt) bleibt zu - Zugriff nur ueber den Proxy
EOF
fi fi
[ -n "$be" ] || return 0
cat <<EOF
Firewall: ${be} ist aktiv. Auf RHEL ist ab Werk nur SSH freigegeben - dann
kommen weder Browser noch Agents durch. Welche Ports dieser Stack braucht und
ob sie offen sind, sagt:
$PROJECT_DIR/scripts/cmk-manage.sh firewall
sudo $PROJECT_DIR/scripts/cmk-manage.sh firewall open --apply
Port 5000 (Checkmk direkt) bleibt dabei zu, solange der Proxy Manager laeuft.
EOF
} }
print_firewall_hint print_firewall_hint
+445 -1
View File
@@ -51,6 +51,9 @@ KOMMANDOS - Stack
pull Images aktualisieren pull Images aktualisieren
status Status von Containern und Sites anzeigen status Status von Containern und Sites anzeigen
logs [-f] [DIENST] Logs 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 selftest Skripte auf bekannte Fallstricke pruefen
tui-check Testzeilen fuer die Rahmendarstellung ausgeben tui-check Testzeilen fuer die Rahmendarstellung ausgeben
(hilft bei q/x/l/m statt Linien, etwa in PuTTY) (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_DAYS|int|Gueltigkeit in Tagen||
cert|CERT_COUNTRY|text|Laenderkuerzel|| cert|CERT_COUNTRY|text|Laenderkuerzel||
cert|CERT_ORG|text|Organisation|| 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 EOF
} }
@@ -2976,6 +2985,7 @@ browser|Terminal-Browser
paths|Verzeichnisse paths|Verzeichnisse
cert|Selbstsignierte Zertifikate cert|Selbstsignierte Zertifikate
backup|Backup-Automatik backup|Backup-Automatik
firewall|Firewall: was offen sein muss
EOF EOF
} }
@@ -3025,6 +3035,23 @@ settings_validate_key() {
*[!a-zA-Z0-9_]*) echo "Ein Site-Name darf nur Buchstaben, Ziffern und _ enthalten."; return 1 ;; *[!a-zA-Z0-9_]*) echo "Ein Site-Name darf nur Buchstaben, Ziffern und _ enthalten."; return 1 ;;
esac esac
[ "${#val}" -le 16 ] || { echo "Ein Site-Name darf hoechstens 16 Zeichen lang sein."; return 1; } ;; [ "${#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) CMK_IMAGE|NPM_IMAGE|BROWSH_IMAGE|CARBONYL_IMAGE)
if [ -n "$val" ] && image_is_short_name "$val"; then if [ -n "$val" ] && image_is_short_name "$val"; then
echo "Bitte vollqualifiziert angeben (z.B. docker.io/...) - Podman 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[*]}}" 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() { gui_main() {
ui_require ui_require
while :; do while :; do
@@ -5110,6 +5174,7 @@ Backups : $BACKUP_DIR" \
proxy "Proxy-Hosts anlegen/verwalten (HTTPS fuer Checkmk)" \ proxy "Proxy-Hosts anlegen/verwalten (HTTPS fuer Checkmk)" \
browser "Terminal-Browser (Proxy Manager lokal bedienen)" \ browser "Terminal-Browser (Proxy Manager lokal bedienen)" \
cert "Selbstsigniertes Zertifikat erzeugen" \ cert "Selbstsigniertes Zertifikat erzeugen" \
firewall "Firewall pruefen (welche Ports muessen offen sein)" \
config "Einstellungen (.env) - menuegefuehrt" \ config "Einstellungen (.env) - menuegefuehrt" \
shell "Root-Shell im Checkmk-Container" \ shell "Root-Shell im Checkmk-Container" \
quit "Beenden")" || break quit "Beenden")" || break
@@ -5124,7 +5189,8 @@ Backups : $BACKUP_DIR" \
image) gui_image_menu || true ;; image) gui_image_menu || true ;;
proxy) gui_proxy_menu || true ;; proxy) gui_proxy_menu || true ;;
browser) gui_browser_menu || true ;; browser) gui_browser_menu || true ;;
cert) gui_cert || true ;; cert) gui_cert || true ;;
firewall) gui_firewall || true ;;
config) gui_settings_menu || true ;; config) gui_settings_menu || true ;;
shell) gui_need_container || continue shell) gui_need_container || continue
gui_run_interactive cmd_shell ;; gui_run_interactive cmd_shell ;;
@@ -5205,6 +5271,383 @@ ${C_BLD}Auswertung${C_RST}
EOF 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 # Selbstpruefung
# #
@@ -5393,6 +5836,7 @@ main() {
config) cmd_config "$@" || true ;; config) cmd_config "$@" || true ;;
selftest) cmd_selftest ;; selftest) cmd_selftest ;;
tui-check) cmd_tui_check ;; tui-check) cmd_tui_check ;;
firewall) cmd_firewall "$@" ;;
help|-h|--help) usage ;; help|-h|--help) usage ;;
*) err "Unbekanntes Kommando: $cmd"; echo; usage; exit 1 ;; *) err "Unbekanntes Kommando: $cmd"; echo; usage; exit 1 ;;
esac esac
+6 -4
View File
@@ -73,14 +73,16 @@ env_set() {
*$'\n'*) die "Ungueltiger Wert fuer '$key' (mehrzeilig)." ;; *$'\n'*) die "Ungueltiger Wert fuer '$key' (mehrzeilig)." ;;
esac esac
[ -n "$val" ] || [ -n "$allow_empty" ] || die "Leerer Wert fuer '$key' - abgebrochen." [ -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
*" "*) case "$val" in \"*\") : ;; *) val="\"$val\"" ;; esac ;; *" "*) case "$val" in \"*\") : ;; *) quoted="\"$val\"" ;; esac ;;
esac esac
if grep -qE "^[#[:space:]]*${key}=" "$f"; then 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 else
printf '%s=%s\n' "$key" "$val" >>"$f" printf '%s=%s\n' "$key" "$quoted" >>"$f"
fi fi
export "$key=$val" export "$key=$val"
} }