Du hast deinen Fileserver migriert. Größen stimmen. Prüfsummen bestehen. Du gibst das Projekt frei.
Drei Wochen später bemerkt jemand, dass /srv/confidential, das auf dem alten Server den Modus 0700 hatte, auf dem neuen 0755 ist. Jeder lokale Benutzer kann es lesen. Die Dateien darin haben die richtigen Berechtigungen. Der Ordner selbst nicht.
Das ist häufiger als du denkst, und fast niemand prüft es.
Die meisten Migrationstools, Skripte und selbst handgeschriebene cp-Befehle folgen dem gleichen Muster:
Schritt 1 ist das Problem. Wenn ein Tool ein Verzeichnis erstellt, braucht es irgendeinen Modus. Der quasi-universelle Standard ist 0755. Das Verzeichnis ist ein Container, etwas das existieren muss, bevor Dateien hineinkönnen. Berechtigungserhaltung ist ein nachträglicher Gedanke, wenn überhaupt.
So sieht das in der Praxis aus:
# Was die meisten Skripte intern tun
mkdir -p /dest/srv/confidential # erstellt als 0755
cp source_files... /dest/srv/confidential/
# fertig. Hat sich nie den Modus des Quellverzeichnisses angeschaut.
# Was auf der Quelle tatsächlich existierte
drwx------ root root /srv/confidential # 0700
drwxr-x--- root staff /srv/finance # 0750
drwxrwx--- root dev /srv/shared-builds # 0770
Nach der Migration ist jedes einzelne davon 0755. Weltweit lesbar.
Sicherheitsauswirkung
Ein Verzeichnis mit Berechtigungen 0755 bedeutet, dass jeder Benutzer auf dem System seinen Inhalt auflisten und Dateien darin lesen kann (vorausgesetzt die Dateiberechtigungen erlauben es). Wenn die Quelle 0700 hatte, war dieser Zugriff absichtlich eingeschränkt. Deine Migration hat ihn geöffnet.
Vergleiche Verzeichnisberechtigungen zwischen Quelle und Ziel mit einem einzigen find-Befehl:
# Auf der Quelle
find /srv -type d -exec stat -c '%a %n' {} \; | sort > /tmp/source-dirs.txt
# Auf dem Ziel
find /dest/srv -type d -exec stat -c '%a %n' {} \; | sort > /tmp/dest-dirs.txt
# Vergleichen (Pfadpräfix vorher entfernen)
diff <(sed 's| /srv| |' /tmp/source-dirs.txt) \
<(sed 's| /dest/srv| |' /tmp/dest-dirs.txt)
Wenn jede Zeile im Diff auf der rechten Seite 0755 zeigt, hat dein Tool die Verzeichnisberechtigungen nicht erhalten.
Für eine schnelle Stichprobe an einem einzelnen Verzeichnis:
stat -c '%a' /source/path/to/directory
stat -c '%a' /dest/path/to/directory
Wenn diese beiden Zahlen nicht übereinstimmen, hast du ein Problem.
Das ist subtil. Selbst Tools, die Berechtigungen auf “bekannten” Verzeichnissen erhalten, übersehen oft Zwischenverzeichnisse.
Angenommen deine Quelle hat diese Struktur:
/data/projects/client-a/reports/2025/
Dein Tool sieht /data/projects/client-a/reports/2025/quarterly.pdf in der Dateiliste. Es braucht den vollständigen Verzeichnisbaum, bevor es diese Datei schreiben kann. Also macht es das Äquivalent von:
os.MkdirAll("/dest/data/projects/client-a/reports/2025", 0755)
mkdir -p /dest/data/projects/client-a/reports/2025
Jedes Verzeichnis in dieser Kette wird mit 0755 erstellt. Selbst wenn das Tool später zurückkommt, um Berechtigungen auf /dest/data/projects/client-a/ zu setzen, werden die Zwischenverzeichnisse (/data, /data/projects) möglicherweise nie korrigiert, weil sie nicht als explizite Einträge in den Scan-Ergebnissen vorkamen.
mkdir -p nutzt immer Standardwerte
Sowohl Gos os.MkdirAll als auch das Shell-Kommando mkdir -p erstellen Zwischenverzeichnisse mit dem Standardmodus (maskiert durch umask). Sie akzeptieren keine Pro-Ebene-Modi. Jedes Tool, das diese Funktionen nutzt, um übergeordnete Verzeichnisse spontan zu erstellen, produziert 0755-Elternverzeichnisse, unabhängig davon, was die Quelle hatte.
rsync mit dem -a-Flag handhabt das, größtenteils:
rsync -a /source/ /dest/
Das -a-Flag beinhaltet -p (Berechtigungen erhalten), was für Dateien und Verzeichnisse gilt. Nach dem Transfer macht rsync einen zweiten Durchlauf, um Verzeichnisberechtigungen zu setzen. Das ist notwendig, weil Verzeichnisse während des Kopierens beschreibbar sein müssen und danach restriktiv gesetzt werden.
Wo rsync dennoch Fehler machen kann:
0755-Modus. Der Berechtigungs-Fixup-Durchlauf ist nie gelaufen.--ignore-existing oder --update kann den Verzeichnis-Metadaten-Durchlauf für Verzeichnisse überspringen, die es als “bereits erledigt” betrachtet.Auch nach rsync verifizieren
Selbst mit rsync -a, führe den find ... stat-Vergleich von oben durch. Nimm nichts an. Es dauert 30 Sekunden und kann dir ein Berechtigungs-Audit-Versagen Wochen später ersparen.
Verzeichnisberechtigungen sind nur ein Teil. Eine vollständige Migration erhält drei Attribute für jedes Verzeichnis:
| Attribut | Was es steuert | Gängiger Standard |
|---|---|---|
| Modus (Berechtigungen) | Wer lesen, schreiben, betreten darf | 0755 |
| Besitz (uid/gid) | Welcher Benutzer und welche Gruppe es besitzt | root:root |
| Zeitstempel (mtime) | Wann es zuletzt geändert wurde | Zeitpunkt der Migration |
Die meisten Tools, die Berechtigungen übersehen, übersehen auch Zeitstempel. Besitzrechte werden etwas häufiger erhalten, weil Tools, die als root laufen, tendenziell chown für Dateien und Verzeichnisse gleichermaßen nutzen. Aber Zeitstempel auf Verzeichnissen werden häufig ignoriert, weil sie als kosmetisch gelten.
Sie sind nicht kosmetisch, wenn du Monitoring- oder Compliance-Tools hast, die “zuletzt geändert”-Daten auf Verzeichnisstrukturen verfolgen.
syncopio advantage
syncopio erhält Berechtigungen, Besitzrechte und Zeitstempel auf jedem Verzeichnis, einschließlich Zwischenverzeichnisse, die während des Transfers erstellt werden. Es wendet Verzeichnis-Metadaten an, nachdem alle Dateien geschrieben wurden, sodass restriktive Berechtigungen das Kopieren nicht blockieren. Kein zweiter Durchlauf, kein manueller Fixup.
Nach jeder Migration, unabhängig vom verwendeten Tool:
1. Verzeichnis-Modi vergleichen
find /source -type d -exec stat -c '%a %n' {} \; | sort > /tmp/src.txt
find /dest -type d -exec stat -c '%a %n' {} \; | sort > /tmp/dst.txt
diff /tmp/src.txt /tmp/dst.txt
2. Auf 0755 überall prüfen
# Das findet Verzeichnisse, die auf dem Ziel 0755 sind, aber NICHT 0755 auf der Quelle
# (d.h. etwas hat sich geändert)
find /dest -type d -perm 0755 -exec stat -c '%n' {} \;
Wenn die Liste verdächtig lang ist und deine Quelle verschiedene Berechtigungen hatte, hat das Tool Standardwerte verwendet.
3. Besitz prüfen
find /source -type d -exec stat -c '%U:%G %n' {} \; | sort > /tmp/src-own.txt
find /dest -type d -exec stat -c '%U:%G %n' {} \; | sort > /tmp/dst-own.txt
diff /tmp/src-own.txt /tmp/dst-own.txt
4. Restriktive Verzeichnisse gezielt prüfen
Das sind die, die am meisten zählen:
# Verzeichnisse finden, die restriktiv sein SOLLTEN (nicht weltlesbar)
find /source -type d ! -perm -o=r -exec stat -c '%a %n' {} \;
# Dann prüfen, ob das Ziel übereinstimmt
5. Zeitstempel stichprobenartig prüfen
stat -c '%y %n' /source/some/directory
stat -c '%y %n' /dest/some/directory
Wenn der Zeitstempel des Ziels das Datum deiner Migration zeigt statt des Originaldatums, wurden Zeitstempel nicht erhalten.
Wenn du bereits migriert hast und Berechtigungen reparieren musst:
# Fixup-Script aus der Quelle generieren
find /source -type d -exec stat -c 'chmod %a "%n"' {} \; \
| sed 's|/source|/dest|' > fixup-perms.sh
# Erst prüfen
less fixup-perms.sh
# Anwenden
bash fixup-perms.sh
Für Besitzrechte:
find /source -type d -exec stat -c 'chown %U:%G "%n"' {} \; \
| sed 's|/source|/dest|' > fixup-owners.sh
bash fixup-owners.sh
Das funktioniert, ist aber ein Pflaster. Die richtige Lösung ist ein Tool, das diese Metadaten beim initialen Transfer erhält.
Weiterführende Lektüre: