This commit is contained in:
root
2026-05-10 13:15:32 +02:00
commit d14abc7041
4 changed files with 885 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
hooks
chains

837
README.md Normal file
View File

@@ -0,0 +1,837 @@
# Firewall-oppsett for `/opt/firewall`
Dette repoet inneholder firewall-logikk for en Linux-host med `iptables`, Docker og eventuelt WireGuard.
Målet er at firewall-reglene skal være:
- lesbare
- flyttbare
- enkle å ta backup av
- mulige å versjonskontrollere med Git
- trygge å laste inn flere ganger
- adskilt fra systemets egne chains
- mulig å laste automatisk ved boot med systemd
Repoet ligger her:
```text
/opt/firewall
```
---
## 1. Hvorfor dette oppsettet finnes
Firewall-regler som skrives direkte i terminalen med `iptables`, finnes bare aktivt i kernel mens maskinen kjører.
Eksempel:
```bash
sudo iptables -A FORWARD -j ACCEPT
```
Dette er ikke nok som varig dokumentasjon eller drift.
Hvis maskinen rebooter, eller hvis reglene endres senere, er det lett å miste oversikt.
Derfor ligger firewall-logikken som filer i:
```text
/opt/firewall
```
Da kan reglene:
- leses
- endres
- kjøres på nytt
- legges i Git
- kopieres til en annen maskin
- lastes automatisk med systemd
---
## 2. Filstruktur
Dette oppsettet bruker denne strukturen:
```text
/opt/firewall
├── README.md
├── lib.sh
├── load-chains.sh
├── chains/
└── hooks/
```
Forklaring:
```text
/opt/firewall/README.md
```
Dokumentasjon for hvordan firewall-oppsettet fungerer.
```text
/opt/firewall/lib.sh
```
Felles hjelpefunksjoner som kan brukes av flere firewall-script.
Typiske funksjoner i `lib.sh` kan være:
- sjekke om en chain finnes
- lage en chain hvis den mangler
- flushe egne chains
- legge til regler uten duplikater
- koble chains sammen
```text
/opt/firewall/load-chains.sh
```
Hovedscriptet som laster firewall-reglene.
Dette er scriptet systemd bør kjøre ved boot.
```text
/opt/firewall/chains/
```
Mappe for egne chain-filer.
Eksempel:
```text
/opt/firewall/chains/wg-admin.sh
/opt/firewall/chains/wg-guest.sh
/opt/firewall/chains/docker-filter.sh
```
```text
/opt/firewall/hooks/
```
Mappe for scripts som kan brukes av andre tjenester, for eksempel WireGuard `PostUp`, `PostDown`, eller egne systemd-hooks.
---
## 3. Hovedprinsipp
Systemet har egne chains med store bokstaver:
```text
INPUT
OUTPUT
FORWARD
DOCKER
DOCKER-USER
```
Egne private chains bør bruke små bokstaver:
```text
custom-forward
wg-admin
wg-guest
docker-filter
```
Dette gjør det lett å se forskjell på:
- systemets egne chains
- Docker sine chains
- egne firewall-chains
---
## 4. Hvorfor bruke egne chains
Man bør ikke legge all logikk direkte i `FORWARD`.
Ryddigere prinsipp:
```text
FORWARD
-> custom-forward
-> wg-admin
-> wg-guest
```
For Docker:
```text
DOCKER-USER
-> docker-filter
```
Da kan egne chains ryddes og lastes inn på nytt uten å flushe hele systemets firewall.
Dette er spesielt viktig på maskiner som bruker:
- Docker
- WireGuard
- SSH
- Caddy
- Pi-hole
- andre nettverkstjenester
---
## 5. Idempotente regler
Firewall-script bør kunne kjøres flere ganger uten å lage duplikate regler.
Ikke gjør dette ukritisk:
```bash
iptables -A FORWARD -j custom-forward
```
Hvis scriptet kjøres fem ganger, får du fem like regler.
Bruk heller denne logikken:
```bash
iptables -C FORWARD -j custom-forward 2>/dev/null || iptables -A FORWARD -j custom-forward
```
Forklaring:
- `iptables -C` sjekker om regelen finnes
- hvis den ikke finnes, legges den inn med `iptables -A`
- da kan scriptet kjøres flere ganger trygt
---
## 6. Rolle til `lib.sh`
`lib.sh` bør inneholde felles funksjoner.
Eksempel på typiske funksjoner:
```bash
chain_exists() {
local chain="$1"
iptables -L "$chain" -n >/dev/null 2>&1
}
ensure_chain() {
local chain="$1"
if ! chain_exists "$chain"; then
iptables -N "$chain"
fi
}
flush_chain() {
local chain="$1"
if chain_exists "$chain"; then
iptables -F "$chain"
fi
}
ensure_rule() {
local chain="$1"
shift
if ! iptables -C "$chain" "$@" >/dev/null 2>&1; then
iptables -A "$chain" "$@"
fi
}
ensure_jump() {
local from_chain="$1"
local to_chain="$2"
shift 2
if ! iptables -C "$from_chain" "$@" -j "$to_chain" >/dev/null 2>&1; then
iptables -A "$from_chain" "$@" -j "$to_chain"
fi
}
```
Poenget med `lib.sh` er at chain-script slipper å gjenta samme hjelpefunksjoner.
---
## 7. Rolle til `load-chains.sh`
`load-chains.sh` er hovedscriptet.
Det bør gjøre omtrent dette:
1. sette trygg shell-modus
2. finne repo-path
3. source `/opt/firewall/lib.sh`
4. aktivere IPv4 forwarding hvis maskinen skal route trafikk
5. lage private chains
6. flushe bare egne private chains
7. koble egne chains inn i systemets chains
8. laste regler fra `/opt/firewall/chains/`
Eksempel på start:
```bash
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="/opt/firewall"
source "$BASE_DIR/lib.sh"
sysctl -w net.ipv4.ip_forward=1 >/dev/null
```
`load-chains.sh` bør være scriptet systemd kjører.
---
## 8. Eksempel på private chains
Vanlige private chains kan være:
```text
custom-forward
wg-admin
wg-guest
docker-filter
```
Eksempel på oppretting:
```bash
ensure_chain custom-forward
ensure_chain wg-admin
ensure_chain wg-guest
ensure_chain docker-filter
```
Eksempel på rydding:
```bash
flush_chain custom-forward
flush_chain wg-admin
flush_chain wg-guest
flush_chain docker-filter
```
Viktig:
Bare egne chains bør flushes.
Ikke flush disse ukritisk:
```text
INPUT
OUTPUT
FORWARD
DOCKER
DOCKER-USER
```
---
## 9. WireGuard-logikk
Eksempelnett:
```text
wg-admin: 10.10.10.0/24
wg-guest: 10.10.11.0/24
```
Typisk logikk:
```text
wg-admin:
- får full forward-tilgang
wg-guest:
- får begrenset tilgang
- kan eventuelt få DNS
- resten avvises
```
Eksempel:
```bash
ensure_jump custom-forward wg-admin -s 10.10.10.0/24
ensure_jump custom-forward wg-guest -s 10.10.11.0/24
ensure_rule wg-admin -j ACCEPT
ensure_rule wg-guest -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ensure_rule wg-guest -p udp -d 10.10.11.1 --dport 53 -j ACCEPT
ensure_rule wg-guest -p tcp -d 10.10.11.1 --dport 53 -j ACCEPT
ensure_rule wg-guest -j REJECT
```
Tilpass IP-adresser til eget oppsett.
---
## 10. Docker-logikk
Docker lager egne chains automatisk.
Vanlige Docker-chains:
```text
DOCKER
DOCKER-USER
DOCKER-ISOLATION-STAGE-1
DOCKER-ISOLATION-STAGE-2
```
Egne Docker-regler bør normalt kobles inn via:
```text
DOCKER-USER
```
Eksempel:
```bash
ensure_jump DOCKER-USER docker-filter
```
I `docker-filter` kan du legge egne regler.
Eksempel:
```bash
ensure_rule docker-filter -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
ensure_rule docker-filter -s 10.10.10.0/24 -j RETURN
ensure_rule docker-filter -j RETURN
```
`RETURN` betyr at trafikken går tilbake til Docker sin normale behandling.
---
## 11. Pi-hole og Docker
Hvis Pi-hole kjører i Docker bridge-nettverk, kan Pi-hole ofte se Docker gateway eller container-IP som klient, ikke ekte klient-IP.
For å se ekte klient-IP kan man vurdere:
- host network
- macvlan
- kjøre Pi-hole direkte på host
- bruke routing der klientens kilde-IP bevares
Dette README-et handler primært om firewall-logikken, ikke selve Pi-hole-oppsettet.
---
## 12. Manuell lasting av firewall
Kjør:
```bash
sudo /opt/firewall/load-chains.sh
```
Hvis scriptet ikke er kjørbart:
```bash
sudo chmod +x /opt/firewall/load-chains.sh
```
Kjør med debug:
```bash
sudo bash -x /opt/firewall/load-chains.sh
```
---
## 13. Se aktive regler
Vis regler som kommandoer:
```bash
sudo iptables -S
```
Vis regler med tellere:
```bash
sudo iptables -L -n -v
```
Vis NAT-regler:
```bash
sudo iptables -t nat -S
```
Vis Docker sin user-chain:
```bash
sudo iptables -S DOCKER-USER
```
---
## 14. Systemd-tjeneste
Systemd kan brukes til å laste firewall-reglene automatisk ved boot.
Tjenesten bør ligge her:
```text
/etc/systemd/system/custom-firewall.service
```
Innhold:
```ini
[Unit]
Description=Custom firewall rules from /opt/firewall
Documentation=file:/opt/firewall/README.md
Wants=network-online.target
After=network-online.target docker.service
[Service]
Type=oneshot
ExecStart=/opt/firewall/load-chains.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
```
---
## 15. Lage systemd-tjenesten manuelt
Lag filen:
```bash
sudo nano /etc/systemd/system/custom-firewall.service
```
Lim inn:
```ini
[Unit]
Description=Custom firewall rules from /opt/firewall
Documentation=file:/opt/firewall/README.md
Wants=network-online.target
After=network-online.target docker.service
[Service]
Type=oneshot
ExecStart=/opt/firewall/load-chains.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
```
Lagre filen.
Deretter:
```bash
sudo chmod +x /opt/firewall/load-chains.sh
sudo systemctl daemon-reload
sudo systemctl enable custom-firewall.service
sudo systemctl start custom-firewall.service
```
---
## 16. Forklaring av systemd-filen
```ini
Description=Custom firewall rules from /opt/firewall
```
Beskrivelse av tjenesten.
```ini
Documentation=file:/opt/firewall/README.md
```
Peker til denne dokumentasjonen.
```ini
Wants=network-online.target
After=network-online.target docker.service
```
Tjenesten starter etter at nettverk er oppe.
Hvis Docker finnes, starter firewall-oppsettet etter Docker. Dette er nyttig fordi Docker lager `DOCKER-USER`.
```ini
Type=oneshot
```
Scriptet kjøres én gang og avsluttes.
```ini
ExecStart=/opt/firewall/load-chains.sh
```
Dette scriptet laster firewall-reglene.
```ini
RemainAfterExit=yes
```
Systemd markerer tjenesten som aktiv etter at scriptet er ferdig.
Dette gir mening fordi reglene fortsatt ligger aktive i kernel.
```ini
WantedBy=multi-user.target
```
Gjør at tjenesten kan aktiveres ved vanlig boot.
---
## 17. Hvis firewall må starte før WireGuard
Hvis firewall-reglene må være klare før `wg0` starter, kan man legge til:
```ini
Before=wg-quick@wg0.service
```
Da blir unit-filen:
```ini
[Unit]
Description=Custom firewall rules from /opt/firewall
Documentation=file:/opt/firewall/README.md
Wants=network-online.target
After=network-online.target docker.service
Before=wg-quick@wg0.service
[Service]
Type=oneshot
ExecStart=/opt/firewall/load-chains.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
```
Ikke bruk `Before=wg-quick@wg0.service` hvis du ikke trenger det.
For mange oppsett holder det at firewall-reglene lastes etter nettverk og Docker.
---
## 18. Aktivere tjenesten
Etter at filen er laget:
```bash
sudo systemctl daemon-reload
sudo systemctl enable custom-firewall.service
sudo systemctl start custom-firewall.service
```
Sjekk status:
```bash
systemctl status custom-firewall.service
```
---
## 19. Etter endringer
Hvis du endrer script:
```bash
sudo systemctl restart custom-firewall.service
```
Hvis du endrer systemd-filen:
```bash
sudo systemctl daemon-reload
sudo systemctl restart custom-firewall.service
```
---
## 20. Stoppe tjenesten
```bash
sudo systemctl stop custom-firewall.service
```
Viktig:
Dette fjerner ikke nødvendigvis firewall-reglene fra kernel.
Siden tjenesten er `Type=oneshot`, betyr `stop` hovedsakelig at systemd ikke lenger markerer tjenesten som aktiv.
Hvis du vil fjerne regler, må du lage eget cleanup-script eller rydde egne chains manuelt.
Eksempel:
```bash
sudo iptables -F custom-forward
sudo iptables -F wg-admin
sudo iptables -F wg-guest
sudo iptables -F docker-filter
```
Ikke flush hele firewall-oppsettet ukritisk på en server du er koblet til over SSH.
---
## 21. Feilsøking
Sjekk status:
```bash
systemctl status custom-firewall.service
```
Se logger:
```bash
journalctl -u custom-firewall.service -xe
```
Se logger fra siste boot:
```bash
journalctl -b -u custom-firewall.service
```
Kjør script direkte:
```bash
sudo /opt/firewall/load-chains.sh
```
Kjør script med debug:
```bash
sudo bash -x /opt/firewall/load-chains.sh
```
Sjekk om en chain finnes:
```bash
sudo iptables -L custom-forward -n -v
```
Sjekk om en regel finnes:
```bash
sudo iptables -C FORWARD -j custom-forward
```
Sjekk Docker-chain:
```bash
sudo iptables -L DOCKER-USER -n -v
```
---
## 22. Backup
Ta backup av aktiv iptables-state:
```bash
sudo iptables-save > /opt/firewall/iptables-backup.rules
```
Men viktigste backup er selve repoet:
```text
/opt/firewall/README.md
/opt/firewall/lib.sh
/opt/firewall/load-chains.sh
/opt/firewall/chains/
/opt/firewall/hooks/
```
Hvis `/opt/firewall` ligger i Git, kan oppsettet flyttes og reproduseres.
---
## 23. Flytte til annen maskin
Kopier repoet til:
```text
/opt/firewall
```
Gjør scriptet kjørbart:
```bash
sudo chmod +x /opt/firewall/load-chains.sh
```
Lag systemd-tjenesten:
```bash
sudo nano /etc/systemd/system/custom-firewall.service
```
Lim inn:
```ini
[Unit]
Description=Custom firewall rules from /opt/firewall
Documentation=file:/opt/firewall/README.md
Wants=network-online.target
After=network-online.target docker.service
[Service]
Type=oneshot
ExecStart=/opt/firewall/load-chains.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
```
Aktiver:
```bash
sudo systemctl daemon-reload
sudo systemctl enable custom-firewall.service
sudo systemctl start custom-firewall.service
```
Sjekk:
```bash
systemctl status custom-firewall.service
sudo iptables -S
```
---
## 24. Viktige regler
Ikke flush hele `iptables` ukritisk.
Ikke slett Docker sine chains manuelt.
Ikke legg permanente regler bare manuelt i terminalen.
Ikke bland admin-nett, guest-nett og Docker-regler uten tydelige chains.
Bruk egne chains for egen logikk.
La `/opt/firewall/load-chains.sh` være kilden til sannheten.
La systemd laste firewall-reglene ved boot.

38
lib.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
IPTABLES=${IPTABLES:-/usr/sbin/iptables}
# ---------- filter/default table ----------
ipt() {
"$IPTABLES" "$@"
}
ensure_chain() {
local chain="$1"
ipt -N "$chain" 2>/dev/null || true
}
add_rule() {
local chain="$1"
shift
ipt -C "$chain" "$@" 2>/dev/null || ipt -A "$chain" "$@"
}
# ---------- nat table ----------
ipt_nat() {
"$IPTABLES" -t nat "$@"
}
ensure_nat_chain() {
local chain="$1"
ipt_nat -N "$chain" 2>/dev/null || true
}
add_nat_rule() {
local chain="$1"
shift
ipt_nat -C "$chain" "$@" 2>/dev/null || ipt_nat -A "$chain" "$@"
}

7
load-chains.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
for file in /opt/firewall/chains/*.sh; do
[ -e "$file" ] || continue
bash "$file"
done