netzwerksicherung hinzugefuegt
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
# README – Sicherung von WireGuard- und NetworkManager-Konfiguration
|
||||
|
||||
Dieses Skript sichert die Konfigurationen aus `/etc/wireguard` und `/etc/NetworkManager/system-connections` in zeitgestempelten Snapshots mit `rsync` und `--link-dest`.[cite:118][cite:131] Dadurch entsteht eine nachvollziehbare Historie, während unveränderte Dateien zwischen den Snapshots per Hardlink wiederverwendet werden.[cite:34][cite:92]
|
||||
|
||||
## Zweck
|
||||
|
||||
Das Skript ist für die Sicherung sensibler Netzwerk-Konfigurationen gedacht, insbesondere von WireGuard-Tunneln und persistenten NetworkManager-Profilen.[cite:131][cite:130] Diese Dateien können geheime Schlüssel, WLAN-Passwörter oder 802.1X-Zugangsdaten enthalten und sollten daher nur mit Root-Rechten gelesen und in einem geschützten Ziel gespeichert werden.[cite:120][cite:123]
|
||||
|
||||
## Gesicherte Quellen
|
||||
|
||||
| Quelle | Inhalt |
|
||||
|---|---|
|
||||
| `/etc/wireguard` | WireGuard-Konfigurationen wie `wg0.conf` mit Interface-, Peer- und Schlüsseldaten.[cite:131][cite:129] |
|
||||
| `/etc/NetworkManager/system-connections` | NetworkManager-Profile im Keyfile-Format, die je nach System WLAN-, VPN-, Ethernet- oder andere Verbindungsdaten enthalten können.[cite:118][cite:130] |
|
||||
|
||||
Hinweis: Unter Ubuntu 24.04 und neuer speichert NetworkManager eigene permanente Profile nicht mehr zwingend selbst in `/etc/NetworkManager/system-connections`, liest dort aber weiterhin administrativ angelegte Dateien ein.[cite:127] Für viele manuell verwaltete oder ältere Profile bleibt dieses Verzeichnis dennoch relevant.[cite:127][cite:124]
|
||||
|
||||
## Sicherheitsaspekte
|
||||
|
||||
Die Dateien in `/etc/NetworkManager/system-connections` müssen restriktive Rechte haben; zu offene Berechtigungen können dazu führen, dass NetworkManager sie ignoriert.[cite:120][cite:122] Auch WireGuard-Konfigurationen enthalten geheime Schlüssel und sollten nur für Root lesbar sein.[cite:123][cite:131]
|
||||
|
||||
Deshalb gilt für dieses Skript:
|
||||
|
||||
- Es muss mit `sudo` oder als `root` ausgeführt werden, da die Quelldateien Root-Rechte erfordern.[cite:123][cite:120]
|
||||
- Das Backup-Ziel sollte auf einem vertrauenswürdigen Datenträger liegen und gegen unbefugten Zugriff geschützt sein.[cite:123][cite:120]
|
||||
- Ein Linux-Dateisystem wie ext4, XFS oder btrfs ist für `--link-dest` sinnvoll, weil Hardlinks benötigt werden.[cite:34][cite:91]
|
||||
|
||||
## Beispielskript
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
DEST_BASE="/run/media/hans/usbsicherung/system-config-backup"
|
||||
HOST="$(hostname -s)"
|
||||
STAMP="$(date +%F_%H-%M-%S)"
|
||||
TARGET_DIR="${DEST_BASE}/${HOST}/${STAMP}"
|
||||
LATEST_LINK="${DEST_BASE}/${HOST}/latest"
|
||||
LOG_DIR="${DEST_BASE}/${HOST}/logs"
|
||||
LOG_FILE="${LOG_DIR}/netzwerk-backup-${STAMP}.log"
|
||||
KEEP=20
|
||||
|
||||
WG_SRC="/etc/wireguard"
|
||||
NM_SRC="/etc/NetworkManager/system-connections"
|
||||
|
||||
log() {
|
||||
local msg="[$(date +%F\ %T)] $*"
|
||||
echo "${msg}"
|
||||
mkdir -p "${LOG_DIR}"
|
||||
echo "${msg}" >> "${LOG_FILE}"
|
||||
}
|
||||
|
||||
fail() {
|
||||
log "FEHLER: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ ${EUID} -ne 0 ]]; then
|
||||
fail "Dieses Skript muss mit sudo oder als root ausgeführt werden, da /etc/wireguard und /etc/NetworkManager/system-connections Root-Rechte benötigen."
|
||||
fi
|
||||
|
||||
if [[ ! -d "${DEST_BASE}" ]]; then
|
||||
fail "Zielbasis ${DEST_BASE} existiert nicht oder ist nicht gemountet."
|
||||
fi
|
||||
|
||||
if [[ ! -w "${DEST_BASE}" ]]; then
|
||||
fail "Zielbasis ${DEST_BASE} ist nicht beschreibbar."
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_DIR}" "${LOG_DIR}"
|
||||
|
||||
RSYNC_OPTS=(
|
||||
-aHAX
|
||||
--numeric-ids
|
||||
--delete
|
||||
--info=stats2,progress2
|
||||
--human-readable
|
||||
--partial
|
||||
)
|
||||
|
||||
if [[ -L "${LATEST_LINK}" ]] && [[ -d "$(readlink -f "${LATEST_LINK}")" ]]; then
|
||||
RSYNC_OPTS+=(--link-dest="$(readlink -f "${LATEST_LINK}")")
|
||||
log "Verwende link-dest: $(readlink -f "${LATEST_LINK}")"
|
||||
else
|
||||
log "Kein vorheriger Snapshot gefunden – es wird ein vollständiger Lauf erstellt."
|
||||
fi
|
||||
|
||||
backup_tree() {
|
||||
local src="$1"
|
||||
local name="$2"
|
||||
|
||||
if [[ -d "${src}" ]]; then
|
||||
log "Sichere ${src} -> ${TARGET_DIR}/${name}/"
|
||||
rsync "${RSYNC_OPTS[@]}" "${src}/" "${TARGET_DIR}/${name}/" | tee -a "${LOG_FILE}"
|
||||
else
|
||||
log "Quelle ${src} existiert nicht – wird übersprungen."
|
||||
fi
|
||||
}
|
||||
|
||||
backup_tree "${WG_SRC}" "wireguard"
|
||||
backup_tree "${NM_SRC}" "networkmanager-system-connections"
|
||||
|
||||
ln -sfn "${TARGET_DIR}" "${LATEST_LINK}"
|
||||
log "latest-Link zeigt jetzt auf ${TARGET_DIR}"
|
||||
|
||||
cd "${DEST_BASE}/${HOST}"
|
||||
SNAPS=(20*/)
|
||||
|
||||
if (( ${#SNAPS[@]} > KEEP )); then
|
||||
log "Rotationslauf: ${#SNAPS[@]} Snapshots vorhanden, KEEP=${KEEP}."
|
||||
ls -1dt 20*/ | tail -n +$((KEEP + 1)) | while read -r old; do
|
||||
log "Lösche alten Snapshot: ${old}"
|
||||
rm -rf -- "${old}"
|
||||
done
|
||||
else
|
||||
log "Keine Rotation nötig. Snapshots vorhanden: ${#SNAPS[@]}"
|
||||
fi
|
||||
|
||||
log "Netzwerk-Konfigurationsbackup abgeschlossen."
|
||||
```
|
||||
|
||||
## Verwendung
|
||||
|
||||
Zuerst die Syntax prüfen:
|
||||
|
||||
```bash
|
||||
bash -n netzwerk-sicherung.sh
|
||||
```
|
||||
|
||||
Dann das Skript mit Root-Rechten ausführen:
|
||||
|
||||
```bash
|
||||
sudo bash netzwerk-sicherung.sh
|
||||
```
|
||||
|
||||
Da die Quellen sensible Daten enthalten, ist ein Aufruf ohne `sudo` nicht ausreichend.[cite:123][cite:120]
|
||||
|
||||
## Zielstruktur
|
||||
|
||||
Pro Lauf wird ein neuer Snapshot angelegt.[cite:34][cite:92]
|
||||
|
||||
```text
|
||||
/run/media/hans/usbsicherung/system-config-backup/
|
||||
└── <hostname>/
|
||||
├── 2026-04-28_11-15-00/
|
||||
│ ├── wireguard/
|
||||
│ └── networkmanager-system-connections/
|
||||
├── latest -> /run/media/hans/usbsicherung/system-config-backup/<hostname>/2026-04-28_11-15-00
|
||||
└── logs/
|
||||
```
|
||||
|
||||
## Wiederherstellung
|
||||
|
||||
Für einen Test-Restore sollte nie direkt produktiv nach `/etc` zurückgeschrieben werden, sondern zunächst in ein Testverzeichnis.[cite:105][cite:107] Ein Beispiel für WireGuard:
|
||||
|
||||
```bash
|
||||
mkdir -p /tmp/restore-netz
|
||||
SNAP="/run/media/hans/usbsicherung/system-config-backup/$(hostname -s)/2026-04-28_11-15-00"
|
||||
rsync -aHAX "${SNAP}/wireguard/" /tmp/restore-netz/wireguard/
|
||||
```
|
||||
|
||||
Für NetworkManager entsprechend:
|
||||
|
||||
```bash
|
||||
rsync -aHAX "${SNAP}/networkmanager-system-connections/" /tmp/restore-netz/networkmanager-system-connections/
|
||||
```
|
||||
|
||||
Danach sollten Dateirechte, Inhalte und Konfigurationsvollständigkeit geprüft werden.[cite:105][cite:110] Beim produktiven Restore nach `/etc/NetworkManager/system-connections` müssen restriktive Rechte wie `600` erhalten bleiben, da NetworkManager Dateien mit zu offenen Rechten ignorieren kann.[cite:120][cite:122]
|
||||
|
||||
## Nach einem Restore
|
||||
|
||||
Wenn NetworkManager-Profile produktiv zurückkopiert wurden, kann ein erneutes Laden oder ein Neustart des Dienstes nötig sein.[cite:120][cite:122]
|
||||
|
||||
Beispiel:
|
||||
|
||||
```bash
|
||||
sudo chmod 600 /etc/NetworkManager/system-connections/*
|
||||
sudo systemctl restart NetworkManager
|
||||
```
|
||||
|
||||
## Mögliche Erweiterungen
|
||||
|
||||
Sinnvoll wären zusätzlich ein `--dry-run`-Schalter, optionales Backup weiterer Netzdateien wie `/etc/NetworkManager/NetworkManager.conf` oder `/etc/resolv.conf`, sowie eine Automatisierung per `systemd`-Timer.[cite:124][cite:125]
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
DEST_BASE="/run/media/hans/usbsicherung/system-config-backup"
|
||||
HOST="$(hostname -s)"
|
||||
STAMP="$(date +%F_%H-%M-%S)"
|
||||
TARGET_DIR="${DEST_BASE}/${HOST}/${STAMP}"
|
||||
LATEST_LINK="${DEST_BASE}/${HOST}/latest"
|
||||
LOG_DIR="${DEST_BASE}/${HOST}/logs"
|
||||
LOG_FILE="${LOG_DIR}/netzwerk-backup-${STAMP}.log"
|
||||
KEEP=20
|
||||
|
||||
WG_SRC="/etc/wireguard"
|
||||
NM_SRC="/etc/NetworkManager/system-connections"
|
||||
|
||||
log() {
|
||||
local msg="[$(date +%F\ %T)] $*"
|
||||
echo "${msg}"
|
||||
mkdir -p "${LOG_DIR}"
|
||||
echo "${msg}" >> "${LOG_FILE}"
|
||||
}
|
||||
|
||||
fail() {
|
||||
log "FEHLER: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ ${EUID} -ne 0 ]]; then
|
||||
fail "Dieses Skript muss mit sudo oder als root ausgeführt werden, da /etc/wireguard und /etc/NetworkManager/system-connections Root-Rechte benötigen."
|
||||
fi
|
||||
|
||||
if [[ ! -d "${DEST_BASE}" ]]; then
|
||||
fail "Zielbasis ${DEST_BASE} existiert nicht oder ist nicht gemountet."
|
||||
fi
|
||||
|
||||
if [[ ! -w "${DEST_BASE}" ]]; then
|
||||
fail "Zielbasis ${DEST_BASE} ist nicht beschreibbar."
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_DIR}" "${LOG_DIR}"
|
||||
|
||||
RSYNC_OPTS=(
|
||||
-aHAX
|
||||
--numeric-ids
|
||||
--delete
|
||||
--info=stats2,progress2
|
||||
--human-readable
|
||||
--partial
|
||||
)
|
||||
|
||||
if [[ -L "${LATEST_LINK}" ]] && [[ -d "$(readlink -f "${LATEST_LINK}")" ]]; then
|
||||
RSYNC_OPTS+=(--link-dest="$(readlink -f "${LATEST_LINK}")")
|
||||
log "Verwende link-dest: $(readlink -f "${LATEST_LINK}")"
|
||||
else
|
||||
log "Kein vorheriger Snapshot gefunden – es wird ein vollständiger Lauf erstellt."
|
||||
fi
|
||||
|
||||
backup_tree() {
|
||||
local src="$1"
|
||||
local name="$2"
|
||||
|
||||
if [[ -d "${src}" ]]; then
|
||||
log "Sichere ${src} -> ${TARGET_DIR}/${name}/"
|
||||
rsync "${RSYNC_OPTS[@]}" "${src}/" "${TARGET_DIR}/${name}/" | tee -a "${LOG_FILE}"
|
||||
else
|
||||
log "Quelle ${src} existiert nicht – wird übersprungen."
|
||||
fi
|
||||
}
|
||||
|
||||
backup_tree "${WG_SRC}" "wireguard"
|
||||
backup_tree "${NM_SRC}" "networkmanager-system-connections"
|
||||
|
||||
ln -sfn "${TARGET_DIR}" "${LATEST_LINK}"
|
||||
log "latest-Link zeigt jetzt auf ${TARGET_DIR}"
|
||||
|
||||
cd "${DEST_BASE}/${HOST}"
|
||||
SNAPS=(20*/)
|
||||
|
||||
if (( ${#SNAPS[@]} > KEEP )); then
|
||||
log "Rotationslauf: ${#SNAPS[@]} Snapshots vorhanden, KEEP=${KEEP}."
|
||||
ls -1dt 20*/ | tail -n +$((KEEP + 1)) | while read -r old; do
|
||||
log "Lösche alten Snapshot: ${old}"
|
||||
rm -rf -- "${old}"
|
||||
done
|
||||
else
|
||||
log "Keine Rotation nötig. Snapshots vorhanden: ${#SNAPS[@]}"
|
||||
fi
|
||||
|
||||
log "Netzwerk-Konfigurationsbackup abgeschlossen."
|
||||
Reference in New Issue
Block a user