vom impliziten Standardwert zum kontrollierten Audit
Dateiberechtigungen entstehen in Bash-Skripten oft nur implizit über die geerbte umask, statt explizit gesetzt zu werden, und genau das führt zu unnötig weiten Zugriffsrechten. Dieser Artikel zeigt, wie umask, chmod und chown systematisch eingesetzt werden, welche Risiken SUID und SGID in Automatisierungsskripten bergen, und wie ein eigenes Audit-Skript Dateiberechtigungen zuverlässig prüft.
Inhaltsverzeichnis
- 1. Warum Dateiberechtigungen in Bash-Skripten oft übersehen werden
- 2. umask verstehen und in Skripten explizit setzen
- 3. Berechtigungen neuer Dateien und Verzeichnisse kontrollieren
- 4. chmod, chown und die Prinzipien geringster Rechte
- 5. SUID, SGID und Sticky Bit: Risiken in Automatisierungsskripten
- 6. Berechtigungen systematisch prüfen: ein Audit-Skript bauen
- 7. ACLs und erweiterte Berechtigungen aus Bash heraus verwalten
- 8. Berechtigungsfehler in CI/CD und Deployment-Pipelines vermeiden
- 9. Vergleich: riskante vs. sichere Berechtigungsmuster
- 10. Zusammenfassung
- 11. FAQ
1. Warum Dateiberechtigungen in Bash-Skripten oft übersehen werden
Dateiberechtigungen gehören zu den am häufigsten übersehenen Sicherheitsaspekten in Bash-Skripten, weil sie meist implizit über die aktuell gültige umask entstehen, statt bewusst gesetzt zu werden. Ein Skript, das mit touch oder einer Umleitung eine neue Datei erzeugt, übernimmt automatisch die Berechtigungen, die sich aus dem Standardwert minus der umask ergeben, ohne dass ein Entwickler diesen Wert je explizit überprüft hat. In vielen produktiven Umgebungen führt das dazu, dass sensible Log-Dateien, Konfigurationsdateien mit Zugangsdaten oder temporäre Zwischenergebnisse mit weit offeneren Rechten entstehen als eigentlich nötig.
Das Problem verschärft sich, wenn Bash-Skripte in unterschiedlichen Kontexten laufen, etwa interaktiv in einer Entwickler-Shell mit einer restriktiven umask und automatisiert in einem Cronjob oder Container mit einer deutlich offeneren Standard-umask. Ein Skript, das seine Dateiberechtigungen nie explizit setzt, verhält sich dadurch je nach Ausführungskontext unterschiedlich, was Sicherheitsannahmen unzuverlässig macht und in Audits regelmäßig als Finding auftaucht.
Systematisches Prüfen von Dateiberechtigungen bedeutet deshalb zweierlei: Erstens, die umask am Skriptanfang explizit setzen, statt sich auf die geerbte Umgebung zu verlassen. Zweitens, kritische Dateien nach ihrer Erzeugung aktiv mit chmod auf die minimal nötigen Rechte zu beschränken, unabhängig davon, was die umask ergeben hätte.
2. umask verstehen und in Skripten explizit setzen
Die umask ist eine Maske, die von den Standardberechtigungen neuer Dateien und Verzeichnisse abgezogen wird. Für Dateien ist der Standardwert 666 (rw für alle), für Verzeichnisse 777 (rwx für alle), und die umask entfernt daraus bitweise die entsprechenden Bits. Eine umask von 022 führt bei neuen Dateien zu 644 (Besitzer liest und schreibt, Gruppe und Andere lesen nur) und bei Verzeichnissen zu 755. Eine restriktivere umask von 077 entfernt alle Rechte für Gruppe und Andere und führt zu 600 beziehungsweise 700.
In Bash-Skripten, die sensible Daten verarbeiten, etwa Backup-Skripte, Deployment-Skripte mit Zugangsdaten oder Wartungsskripte, die temporäre Dateien mit internen Informationen erzeugen, sollte die umask am Skriptanfang explizit auf 077 gesetzt werden. Das stellt sicher, dass jede neu erzeugte Datei standardmäßig nur für den Besitzer lesbar und schreibbar ist, unabhängig davon, welche umask die aufrufende Umgebung mitbringt.
#!/usr/bin/env bash
# Explicit umask at script start, independent of the calling environment
set -euo pipefail
# Restrictive umask: new files 600, new directories 700
umask 077
# Every file created from here on inherits the restrictive default
readonly SECRET_FILE="/var/run/deploy-secret.tmp"
echo "temporary-token-value" > "$SECRET_FILE"
# Verify: should print 600
stat -c '%a' "$SECRET_FILE"
trap 'rm -f "$SECRET_FILE"' EXIT
Wichtig ist, die umask nach getaner Arbeit nicht zurückzusetzen, wenn das Skript in einer interaktiven Shell per source eingebunden wird, weil sonst die restriktive Einstellung unbeabsichtigt auf die aufrufende Shell übergreift. In eigenständig ausgeführten Skripten, die als eigener Prozess laufen, ist das kein Problem, weil die umask nur innerhalb des Skript-Prozesses gilt und beim Beenden automatisch verworfen wird.
3. Berechtigungen neuer Dateien und Verzeichnisse kontrollieren
Neben der umask sollten Bash-Skripte bei der Erzeugung besonders sensibler Dateien zusätzlich explizite Berechtigungen setzen, statt sich ausschließlich auf die umask zu verlassen. Das erhöht die Robustheit gegen den Fall, dass die umask an anderer Stelle im Skript versehentlich verändert wurde oder ein aufgerufenes externes Tool seine eigene umask setzt. install -m 600 ist hierfür oft die robustere Wahl gegenüber touch gefolgt von chmod, weil es die Berechtigung atomar bei der Erzeugung setzt und keine Zeitspanne existiert, in der die Datei mit den Standardrechten sichtbar ist.
Für Verzeichnisse gilt dasselbe Prinzip: mkdir -m 700 verzeichnis setzt die Berechtigung direkt beim Anlegen, statt in zwei Schritten mkdir und chmod auszuführen, zwischen denen ein Zeitfenster mit falschen Berechtigungen entstehen könnte. Diese sogenannte Time of Check to Time of Use Lücke, kurz TOCTOU, ist ein reales Risiko in mehrbenutzerfähigen Systemen, in denen andere Prozesse zwischen den beiden Schritten auf die Datei zugreifen könnten.
#!/usr/bin/env bash
set -euo pipefail
# Atomic creation with explicit permissions, no TOCTOU gap
install -m 600 /dev/null /var/run/app-token.tmp
# Directory creation with permissions set atomically
mkdir -m 700 -p /var/backups/app-private
# Avoid this pattern: gap between creation and chmod
# touch /tmp/sensitive.log # world-readable for a brief moment
# chmod 600 /tmp/sensitive.log # too late if another process reads first
4. chmod, chown und die Prinzipien geringster Rechte
Das Prinzip geringster Rechte bedeutet, jeder Datei, jedem Verzeichnis und jedem Prozess genau die Berechtigungen zu geben, die für die jeweilige Aufgabe minimal nötig sind, nicht mehr. In der Praxis bedeutet das für Bash-Skripte, dass ausführbare Skripte mit 755 statt 777 versehen werden, Konfigurationsdateien mit Zugangsdaten mit 600 statt 644, und Verzeichnisse mit sensiblen Inhalten mit 700 statt 755. chmod sollte in Deployment- und Wartungsskripten immer mit der symbolischen Notation dokumentiert werden, etwa chmod u=rw,go= datei, weil diese Notation die beabsichtigte Rechtevergabe expliziter macht als eine reine Oktalzahl.
chown ist die zweite Hälfte des Prinzips geringster Rechte: Eine Datei mit korrekten Berechtigungsbits, aber dem falschen Besitzer, kann trotzdem zu weitem Zugriff führen. Skripte, die im Namen eines Deployment-Nutzers laufen, sollten Dateien konsequent diesem Nutzer zuordnen, statt sie versehentlich unter root oder einem generischen Service-Account anzulegen, was in vielen Umgebungen der Fall ist, wenn ein Skript ohne explizites chown als root gestartet wird.
#!/usr/bin/env bash
set -euo pipefail
readonly DEPLOY_USER="deploy"
readonly DEPLOY_GROUP="deploy"
readonly CONFIG_FILE="/etc/app/secrets.env"
# Explicit, documented permission and ownership assignment
chmod u=rw,go= "$CONFIG_FILE"
chown "$DEPLOY_USER:$DEPLOY_GROUP" "$CONFIG_FILE"
# Verify before proceeding — abort if permissions drifted
perms=$(stat -c '%a' "$CONFIG_FILE")
if [[ "$perms" != "600" ]]; then
echo "[ERROR] Unexpected permissions on $CONFIG_FILE: $perms" >&2
exit 1
fi
5. SUID, SGID und Sticky Bit: Risiken in Automatisierungsskripten
Das SUID Bit lässt ein ausführbares Programm mit den Rechten seines Besitzers laufen, unabhängig davon, welcher Nutzer es tatsächlich startet. Wird SUID versehentlich auf ein Bash-Skript gesetzt, ignoriert der Linux-Kernel dieses Bit zwar bei direkt interpretierten Shell-Skripten aus Sicherheitsgründen weitgehend, aber SUID-Binärdateien, die von einem Bash-Skript aufgerufen werden, können trotzdem eine erhebliche Rechteausweitung ermöglichen, wenn das Skript deren Aufruf nicht sorgfältig kontrolliert. Ein Audit sollte deshalb systematisch nach SUID- und SGID-Dateien suchen, die von Automatisierungsskripten berührt oder erzeugt werden.
Das Sticky Bit auf Verzeichnissen, etwa auf /tmp, verhindert, dass Nutzer Dateien anderer Nutzer im selben Verzeichnis löschen können, selbst wenn sie Schreibrechte auf das Verzeichnis haben. Bash-Skripte, die eigene temporäre Verzeichnisse mit weiten Schreibrechten für mehrere Nutzer anlegen, sollten das Sticky Bit konsequent setzen, um genau dieses Risiko auszuschließen.
#!/usr/bin/env bash
set -euo pipefail
# Audit: find SUID/SGID files that might affect automation
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null \
| while IFS= read -r f; do
echo "[SUID/SGID] $f ($(stat -c '%U:%a' "$f"))"
done
# Shared temp directory with sticky bit: prevents cross-user deletion
mkdir -m 1777 -p /var/tmp/shared-worker-dir
6. Berechtigungen systematisch prüfen: ein Audit-Skript bauen
Ein wiederverwendbares Audit-Skript, das kritische Pfade regelmäßig gegen erwartete Berechtigungen prüft, macht das Prinzip geringster Rechte messbar statt nur behauptet. Ein solches Skript definiert für jeden kritischen Pfad die erwartete Berechtigung, den erwarteten Besitzer, und meldet jede Abweichung als konkretes Finding mit Pfad, tatsächlichem und erwartetem Wert. Dieses Muster lässt sich als Cronjob, als Pre-Deployment-Check oder als Teil einer Monitoring-Pipeline integrieren.
Wichtig ist, das Audit-Skript nicht nur einmalig zu schreiben, sondern regelmäßig laufen zu lassen, weil Berechtigungen sich im Laufe der Zeit durch manuelle Eingriffe, fehlerhafte Deployment-Skripte oder vergessene temporäre Änderungen unbemerkt verschieben können.
#!/usr/bin/env bash
set -euo pipefail
declare -A EXPECTED_PERMS=(
["/etc/app/secrets.env"]="600"
["/etc/app/config.yml"]="644"
["/var/backups/app-private"]="700"
["/usr/local/bin/deploy.sh"]="755"
)
declare -a findings=()
for path in "${!EXPECTED_PERMS[@]}"; do
[[ -e "$path" ]] || continue
actual=$(stat -c '%a' "$path")
expected="${EXPECTED_PERMS[$path]}"
if [[ "$actual" != "$expected" ]]; then
findings+=("$path: expected $expected, found $actual")
fi
done
if (( ${#findings[@]} > 0 )); then
printf '[PERMISSION DRIFT] %s\n' "${findings[@]}" >&2
exit 1
fi
echo "[OK] All audited paths have expected permissions"
7. ACLs und erweiterte Berechtigungen aus Bash heraus verwalten
Klassische Unix-Berechtigungen mit Besitzer, Gruppe und Anderen reichen in komplexeren Szenarien oft nicht aus, etwa wenn mehrere Service-Accounts unterschiedliche Zugriffsrechte auf dieselbe Datei benötigen, ohne dass eine gemeinsame Gruppe sinnvoll ist. Access Control Lists, kurz ACLs, erlauben feingranularere Regeln über setfacl und getfacl, die über die klassischen neun Berechtigungsbits hinausgehen. Bash-Skripte, die ACLs setzen, sollten diese ebenfalls in ihr Audit-Skript aufnehmen, weil stat allein ACL-Einträge nicht anzeigt und ein Audit ohne ACL-Prüfung eine falsche Sicherheit vermitteln kann.
Ein häufiger Fehler ist, ACLs einmalig zu setzen und danach zu vergessen, dass ein einfaches chmod auf dieselbe Datei die feingranularen ACL-Einträge teilweise überschreiben oder maskieren kann. Skripte, die sowohl klassische Berechtigungen als auch ACLs setzen, sollten die Reihenfolge konsequent einhalten: erst chmod, dann setfacl, damit die ACL-Einstellungen nicht durch eine spätere chmod-Operation ungewollt zurückgesetzt werden.
#!/usr/bin/env bash
set -euo pipefail
readonly SHARED_LOG="/var/log/app/shared-access.log"
# Base permission first, then fine-grained ACL entries
chmod 640 "$SHARED_LOG"
setfacl -m u:monitoring:r-- "$SHARED_LOG"
setfacl -m u:backup:r-- "$SHARED_LOG"
# Include ACL check in the audit
getfacl --omit-header "$SHARED_LOG"
8. Berechtigungsfehler in CI/CD und Deployment-Pipelines vermeiden
Deployment-Pipelines sind eine besonders häufige Quelle von Berechtigungsfehlern, weil Dateien oft von einem CI Runner mit dessen eigener umask erzeugt und anschließend per rsync oder scp auf ein Zielsystem übertragen werden, ohne dass die Zielberechtigungen explizit kontrolliert werden. rsync überträgt standardmäßig die Quellberechtigungen, was dazu führen kann, dass eine im CI Runner großzügig gesetzte Berechtigung unverändert auf dem produktiven System landet.
Deployment-Skripte sollten deshalb nach jeder Übertragung explizit die Zielberechtigungen setzen, statt sich auf die übertragenen Quellberechtigungen zu verlassen. Ein abschließender Audit-Schritt, der die im vorherigen Abschnitt gezeigte Prüfung direkt nach dem Deployment ausführt, fängt Berechtigungsabweichungen ab, bevor sie in der Produktion zu einem Sicherheitsproblem werden.
9. Vergleich: riskante vs. sichere Berechtigungsmuster
Die folgende Tabelle stellt häufige riskante Berechtigungsmuster ihren sicheren Gegenstücken gegenüber, wie sie in Bash Automatisierung typischerweise vorkommen.
| Situation | Riskant | Sicher | Vorteil |
|---|---|---|---|
| Neue Datei mit Secrets | touch datei; echo geheim > datei |
umask 077; install -m 600 … |
Kein Zeitfenster mit offenen Rechten |
| Ausführbares Skript | chmod 777 deploy.sh |
chmod 755 deploy.sh |
Kein Schreibzugriff für Andere |
| Gemeinsames Temp-Verzeichnis | mkdir -m 777 tmp |
mkdir -m 1777 tmp |
Sticky Bit verhindert fremdes Löschen |
| Deployment per rsync | Quellberechtigungen ungeprüft übernehmen | Zielberechtigungen nach Transfer explizit setzen | Konsistente, geprüfte Rechte im Ziel |
| Prüfung der Berechtigungen | Nur bei manuellem Verdacht | Automatisiertes Audit-Skript, regelmäßig | Abweichungen werden zuverlässig erkannt |
Mironsoft
Berechtigungs-Audits und Härtung von Bash-Automatisierung
Unklare Dateiberechtigungen in eurer Deployment-Pipeline?
Wir prüfen umask, Datei- und Verzeichnisberechtigungen sowie SUID/SGID-Risiken in euren Skripten und bauen automatisierte Audit-Checks für eure Produktionsumgebung.
Berechtigungs-Audit
umask, chmod, chown und ACLs systematisch prüfen
SUID/SGID-Scan
Rechteausweitungs-Risiken in Automatisierungspfaden finden
Audit-Automatisierung
Regelmäßige Prüf-Skripte in Cron oder CI integrieren
10. Zusammenfassung
Dateiberechtigungen in Bash-Skripten entstehen zu oft implizit über eine geerbte umask, statt bewusst gesetzt zu werden. Eine explizite umask 077 am Skriptanfang, atomare Dateierzeugung mit install -m statt getrennter touch und chmod Schritte, und konsequentes chown auf den korrekten Deployment-Nutzer bilden das Fundament sicherer Berechtigungsverwaltung. SUID, SGID und das Sticky Bit verdienen besondere Aufmerksamkeit, weil sie Rechteausweitung ermöglichen können, wenn sie unbedacht gesetzt oder von Automatisierungsskripten berührt werden.
Ein wiederverwendbares Audit-Skript, das kritische Pfade regelmäßig gegen erwartete Berechtigungen prüft, macht das Prinzip geringster Rechte messbar. Gerade in Deployment-Pipelines, wo Dateien über mehrere Systeme mit unterschiedlichen umask-Werten wandern, ist eine explizite Prüfung nach jedem Transfer unverzichtbar, um unbemerkte Berechtigungsabweichungen zu verhindern.
Dateiberechtigungen in Bash prüfen — Das Wichtigste auf einen Blick
umask
Am Skriptanfang explizit setzen, zum Beispiel umask 077 für sensible Daten, statt der geerbten Umgebung zu vertrauen.
Atomare Erzeugung
install -m 600 oder mkdir -m 700 statt getrennter touch/mkdir und chmod Schritte, keine TOCTOU-Lücke.
SUID/SGID/Sticky Bit
Regelmäßig nach SUID/SGID-Dateien suchen, Sticky Bit auf gemeinsamen Temp-Verzeichnissen setzen.
Audit
Wiederverwendbares Skript mit erwarteten Berechtigungen, regelmäßig per Cron oder in CI ausgeführt.