Bucket Policies & Zugriffsbeschränkung
Standardmässig hat jedes EC2-Credential eines Projekts vollen Zugriff auf alle Buckets dieses Projekts. Das ist bequem: ein neuer Bucket funktioniert mit den bestehenden Credentials, ohne dass jemand Rechte anpassen muss.
Für manche Buckets ist dieser Default zu weit — etwa für einen Bucket, in den genau eine Applikation schreiben und aus dem genau ein Consumer lesen darf. Statt einen solchen Bucket in ein eigenes Projekt zu verschieben, können Sie den Default mit einer Bucket Policy umkehren: alles für alle verbieten, ausser für Credentials, die eine von zwei benannten Rollen tragen. Alle Buckets und alle Credentials bleiben im selben Projekt.
Welche Credentials eine Bucket Policy adressiert
Eine Bucket Policy adressiert Rollen, keine einzelnen Access Keys. Die Rolle eines Credentials legen Sie im Portal beim Erstellen fest (Credential role), siehe EC2-Credentials erstellen.
Wie der Zugriff standardmässig funktioniert
| Thema | Verhalten |
|---|---|
| Geltungsbereich | Ein Projekt ist der Container: alle Buckets und alle EC2-Credentials darin. |
| Default | Ohne Bucket Policy darf jedes Credential des Projekts jeden Bucket des Projekts lesen und schreiben — projekt- wie usergebunden. |
| Einschränken | Weil der Zugriff per Default erlaubt ist, ändert ein Grant nichts. Nur ein explizites Deny in einer Bucket Policy schränkt ein. |
| Granularität | Eine Policy pro Bucket und Region. Denselben Bucket in der anderen Region braucht eine eigene Policy, siehe Multi Region. |
| Sichtbarkeit | Die Policy beschränkt den Zugriff, nicht die Sichtbarkeit: aws s3 ls ohne Bucket zeigt den Bucket-Namen weiterhin an. |
Voraussetzungen
- Ein Projekt mit dem Quota-Profil object-storage und mindestens einem Bucket, siehe Konfiguration.
- Eine für den S3-Endpunkt und die Region konfigurierte AWS CLI, siehe AWS CLI & IAM Features.
- Zwei EC2-Credentials im Projekt, die eine Rolle tragen, siehe Schritt 1.
- Die Projekt-ID, siehe Schritt 2.
Schritt 1: Credentials mit einer Rolle erstellen
Im Portal: Object Storage → S3 → Projekt auswählen → Credentials → + Create Credentials, dann Credential role ausfüllen:
| Credential | Credential role |
|---|---|
| Schreibzugriff | <bucket>-readwrite |
| Lesezugriff | <bucket>-readonly |
Der Rollenname ist Ihr Berechtigungsumfang
- Der Rollenname ist Freitext und gehört zum Credential. Ein anderer Name bedeutet ein neues Credential.
- Alle Credentials im Projekt mit demselben Rollennamen sind für die Policy gleichwertig — auch usergebundene Credentials anderer User.
- Verwenden Sie keine generischen Namen wie
readwrite, wenn verschiedene Buckets unterschiedlich geschützt sein sollen: ein solches Credential öffnet jeden Bucket, dessen Policy diese Rolle nennt. - Notieren Sie die exakten Namen. Sie brauchen sie wieder, um die Policy zu ändern oder zu widerrufen.
Schritt 2: Projekt-ID ermitteln
Die Policy referenziert Credentials als ARNs:
arn:aws:iam::<PROJECT_ID>:role/<ROLE>
<PROJECT_ID> ist die ID Ihres Projekts, nicht dessen Name. Sie können sie mit dem OpenStack-Client auslesen — openstack ec2 credentials list zeigt sie in der Spalte Project ID, siehe EC2-Credentials — oder der Projektübersicht im Portal entnehmen.
Schritt 3: Policy schreiben
Setzen Sie Ihre Werte als Shell-Variablen und lassen Sie die Shell einsetzen. Bearbeiten Sie die ARNs nicht von Hand: ein einziges falsches Zeichen in einem ARN entzieht allen den Zugriff, auch dem Portal.
export bucket=mein-bucket
export project=<PROJECT_ID>
# Wichtig: unquoted EOF, damit ${bucket} und ${project} ersetzt werden.
cat <<EOF > bucket-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllWithoutRole",
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::${project}:role/${bucket}-readonly",
"arn:aws:iam::${project}:role/${bucket}-readwrite"
]
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::${bucket}",
"arn:aws:s3:::${bucket}/*"
]
},
{
"Sid": "DenyNonReadActionsForReadonlyRole",
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::${project}:role/${bucket}-readonly"
},
"NotAction": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:GetBucketLocation"
],
"Resource": [
"arn:aws:s3:::${bucket}",
"arn:aws:s3:::${bucket}/*"
]
}
]
}
EOF
# Kontrolle: es darf kein ${...} mehr in der Datei stehen
grep -n '\$' bucket-policy.json || echo "OK: alle Variablen ersetzt"
Was die beiden Statements tun:
DenyAllWithoutRole— allen, die nicht eine der beiden Rollen sind, wird alles auf diesem Bucket und seinen Objekten verweigert. Das umfasst alle anderen Credentials des Projekts, das Portal und anonyme Anfragen.DenyNonReadActionsForReadonlyRole— die Read-only-Rolle darf nur lesen (GetObject,ListBucketsowie die Versions- und Location-Abfragen, die manche Clients brauchen). Schreiben und Löschen sind ihr verweigert.
Ein explizites Deny gewinnt immer gegen jedes Allow. Benötigen Sie keinen Read-only-Zugriff, löschen Sie das zweite Statement und den -readonly-Eintrag im ersten.
Schritt 4: Auf einem Test-Bucket proben
Ein Mismatch zwischen Policy und Credentials sperrt den Bucket für alle. Proben Sie zuerst auf einem Wegwerf-Bucket im selben Projekt und derselben Region — das kostet zwei Minuten.
export prod_bucket=mein-bucket
export bucket=${prod_bucket}-fence-test
aws s3 mb s3://${bucket}
# Heredoc aus Schritt 3 erneut ausführen (es nutzt ${bucket} und ${project}),
# dann die Policy auf den Test-Bucket anwenden:
aws s3api put-bucket-policy --bucket="${bucket}" --policy=file://bucket-policy.json
# 1) Read-write-Credential: zuerst dessen Keys exportieren
export AWS_ACCESS_KEY_ID=<readwrite-access-key>
export AWS_SECRET_ACCESS_KEY=<readwrite-secret-key>
AWS_MAX_ATTEMPTS=1 aws s3 cp - s3://${bucket}/hello.txt <<<"hello"
# 2) Read-only-Credential: auf dessen Keys wechseln
export AWS_ACCESS_KEY_ID=<readonly-access-key>
export AWS_SECRET_ACCESS_KEY=<readonly-secret-key>
AWS_MAX_ATTEMPTS=1 aws s3 cp s3://${bucket}/hello.txt -
# 3) Credential ohne Rolle: auf dessen Keys wechseln (erwartet 403)
export AWS_ACCESS_KEY_ID=<roleless-access-key>
export AWS_SECRET_ACCESS_KEY=<roleless-secret-key>
AWS_MAX_ATTEMPTS=1 aws s3api head-bucket --bucket "${bucket}"
Prüfung 3 ist der eigentliche Beweis. Kommt ein Credential ohne Rolle weiterhin durch, brechen Sie ab und kontaktieren Sie den Support — wenden Sie die Policy nicht auf einen produktiven Bucket an.
Aufräumen:
aws s3api delete-bucket-policy --bucket="${bucket}"
aws s3 rm s3://${bucket} --recursive
aws s3 rb s3://${bucket}
Wenn die Probe sich selbst sperrt
Scheitert Prüfung 1 mit Access Denied, passt der Principal in der Policy nicht zu den Credentials: falsche Projekt-ID, anderes Projekt oder ein Tippfehler im Rollennamen. Lassen Sie den Test-Bucket stehen und wenden Sie die Policy nicht auf den produktiven Bucket an. Ohne passendes Credential können weder Sie noch das Portal die Policy entfernen — siehe Widerruf und Aussperrung.
Schritt 5: Auf den Bucket anwenden
export bucket=${prod_bucket}
# Heredoc aus Schritt 3 erneut ausführen, dann:
aws s3api put-bucket-policy --bucket="${bucket}" --policy=file://bucket-policy.json
# Kontrolle: das gespeicherte Dokument sollte Ihrer Datei entsprechen
aws s3api get-bucket-policy --bucket="${bucket}" --query Policy --output text | jq .
Schritt 6: Verifizieren
Führen Sie die drei Prüfungen aus Schritt 4 gegen den produktiven Bucket aus, jede mit ihrem eigenen Credential wie dort gezeigt. Erwartung: Schreiben und Lesen mit dem Read-write-Credential, nur Lesen mit dem Read-only-Credential und 403 für jedes andere Credential des Projekts.
Verhalten im Betrieb
- Portal: das S3-Panel arbeitet mit dem unter
Select Credentialsgewählten Credential. Trägt es keine Rolle, scheitern Browsen, Upload und Policy-Editor mitAccess Denied. Geben Sie dem von Ihren Administratoren genutzten Credential die Rolle<bucket>-readwriteoder arbeiten Sie über die CLI. - Andere Region: wiederholen Sie die Schritte 3 bis 5 für den Bucket in der zweiten Region.
- Neue Buckets: es gibt keine Vererbung. Ein neuer Bucket ist für das ganze Projekt offen, bis er eine eigene Policy bekommt.
- Versionierung: die Read-only-Rolle darf aktuelle und ältere Objektversionen lesen, mehr nicht.
- Rolle ändern: neues Credential erstellen, neue Rolle in die Policy aufnehmen, Applikationen umstellen, danach die alte Rolle aus der Policy entfernen. Niemals in umgekehrter Reihenfolge.
Widerruf und Aussperrung
Zum Widerrufen entfernen Sie die Policy. Dazu brauchen Sie ein Credential mit der Rolle <bucket>-readwrite:
aws s3api delete-bucket-policy --bucket="${bucket}"
Danach gilt wieder der Projekt-Default: alle Credentials des Projekts haben vollen Zugriff.
Aussperrung: niemand kommt mehr an den Bucket
Symptom: alle Credentials des Projekts — inklusive Portal — erhalten auf dem Bucket Access Denied. Ursache: die Rollennamen oder die Projekt-ID in der Policy passen zu keinem existierenden Credential, oder das letzte Credential mit dieser Rolle wurde gelöscht.
Wiederherstellung ohne Support gelingt, solange Sie die Rollennamen aus der Policy kennen. Erstellen Sie im selben Projekt ein neues Credential mit genau diesem Rollennamen (<bucket>-readwrite). Das Deny-Statement nimmt diesen Principal aus, das neue Credential hat also wieder Zugriff. Nutzen Sie es, um die Policy zu löschen, und bauen Sie danach das verlorene Credential neu auf.
Wiederherstellung mit Support: sind die Rollennamen nicht mehr bekannt, eröffnen Sie ein Ticket mit Projekt-ID, Bucket-Name, Region und dem Hinweis, dass eine DenyAllWithoutRole-Bucket-Policy den Bucket sperrt. Der Support kann die Policy entfernen.
Vorbeugen: beide Credentials vor dem Anwenden der Policy erstellen, auf einem Test-Bucket proben und das Read-write-Credential nie löschen, solange die Policy aktiv ist.
Troubleshooting
| Symptom | Ursache und Lösung |
|---|---|
Anfragen hängen etwa eine Minute, dann 403 |
Die CLI wiederholt gescheiterte Requests. export AWS_MAX_ATTEMPTS=1 scheitert sofort — nützlich für die erwarteten Ablehnungen oben. |
MalformedPolicy beim Anwenden |
${...} wurde nicht ersetzt: das Heredoc muss mit <<EOF beginnen, nicht mit <<'EOF'. |
aws s3 rb scheitert |
Der Bucket ist nicht leer. Löschen Sie zuerst die Objekte (aws s3 rm --recursive, braucht die Rolle). |
Der Bucket erscheint weiterhin in aws s3 ls |
Erwartet. Die Policy verweigert den Inhaltszugriff, nicht den Bucket-Namen. |
| Ein zweites Credential mit derselben Rolle funktioniert | Erwartet. Der Rollenname ist der Geltungsbereich, nicht der Key. |