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:
@@ -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=
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user