S3 Access Denied trotz öffentlichem Objekt: Block Public Access verstehen und beheben

Du hast ein Bild in S3 hochgeladen, die Berechtigungen auf 'öffentlich' gesetzt – und trotzdem liefert die URL nur ein nichtssagendes Access Denied. Das ist einer der häufigsten Stolpersteine bei S3, weil AWS zwei unabhängige Kontrollschichten betreibt, die sich gegenseitig überschreiben können. Die Objekt-ACL allein reicht nicht aus, wenn 'Block Public Access' auf Bucket-Ebene aktiv ist.

TL;DR: S3 Access Denied trotz öffentlichem Objekt

SchichtEinstellungWirkung bei Fehler
Block Public Access (Bucket)Aktiv (Standard)Überschreibt alle ACLs und Bucket-Policies – öffentlicher Zugriff wird blockiert
Objekt-ACLpublic-read gesetztWirkungslos, solange Block Public Access aktiv ist
Bucket PolicyKein s3:GetObject für *Kein anonymer Zugriff ohne explizite Allow-Policy
Object OwnershipBucket owner enforcedACLs sind deaktiviert – public-read hat keine Wirkung

Wie S3-Zugriffskontrolle wirklich funktioniert

S3 wertet Zugriffsanfragen in einer festen Reihenfolge aus. 'Block Public Access' ist dabei keine normale IAM-Policy – es ist ein separater Mechanismus, der vor der Policy-Auswertung greift und öffentliche Zugriffe pauschal unterbindet. Das bedeutet: Selbst wenn Objekt-ACL und Bucket Policy öffentlichen Zugriff erlauben würden, blockiert dieser Schalter die Anfrage, bevor sie die eigentliche Berechtigungsprüfung erreicht.

Block Public Access verhält sich wie ein Hauptschalter vor dem Sicherungskasten. Ob die einzelnen Sicherungen (ACLs, Policies) durchgeschaltet sind oder nicht, spielt keine Rolle – wenn der Hauptschalter offen ist, kommt kein Strom durch.

Zusätzlich hat AWS mit der Einstellung 'Object Ownership: Bucket owner enforced' ACLs auf Bucket-Ebene vollständig deaktiviert. Wer also public-read per ACL setzt, bemerkt möglicherweise nicht einmal, dass diese Einstellung stillschweigend ignoriert wird.

graph TD A["Anonyme Anfrage
an S3-URL"] --> B{"Block Public Access
aktiv?"} B -- "Ja" --> C["Access Denied
Auswertung endet hier"] B -- "Nein" --> D{"Object Ownership:
BucketOwnerEnforced?"} D -- "Ja" --> E["ACLs ignoriert
weiter zu Bucket Policy"] D -- "Nein" --> F["ACLs werden
ausgewertet"] E --> G{"Bucket Policy erlaubt
s3:GetObject für *?"} F --> H{"Objekt-ACL
public-read gesetzt?"} G -- "Ja" --> I["Zugriff gewährt"] G -- "Nein" --> C H -- "Ja" --> I H -- "Nein" --> C
  1. Anfrage eingehend: Ein anonymer Client ruft die S3-URL auf.
  2. Block Public Access: AWS prüft zuerst, ob Block Public Access für den Bucket oder das Konto aktiv ist. Ist das der Fall, endet die Auswertung hier mit Access Denied.
  3. Object Ownership: Falls ACLs deaktiviert sind ('Bucket owner enforced'), werden Objekt-ACLs ignoriert.
  4. Bucket Policy: Gibt es eine explizite Allow-Policy für anonymen Zugriff (Principal: "*")?
  5. Objekt-ACL: Nur wenn ACLs aktiviert sind und Block Public Access inaktiv ist, wird public-read berücksichtigt.
  6. Zugriff gewährt oder verweigert: Erst wenn alle Schichten passiert sind, wird das Objekt ausgeliefert.

S3 Access Denied diagnostizieren: Schritt-für-Schritt

Schritt 1: Block Public Access auf Bucket-Ebene prüfen

Block Public Access ist bei neuen Buckets standardmäßig vollständig aktiviert. Das ist der häufigste Grund für Access Denied bei vermeintlich öffentlichen Objekten – und wird im S3-Konsolen-Workflow beim Hochladen nicht explizit angezeigt. Prüfe zuerst diesen Schalter, bevor du Zeit mit ACLs oder Policies verbringst.

aws s3api get-public-access-block \
  --bucket DEIN-BUCKET-NAME

Erwartete Ausgabe, wenn Block Public Access vollständig aktiv ist:

{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": true,
        "IgnorePublicAcls": true,
        "BlockPublicPolicy": true,
        "RestrictPublicBuckets": true
    }
}

Alle vier Werte auf true bedeuten: Kein öffentlicher Zugriff möglich, unabhängig von ACLs oder Bucket Policy.

Schritt 2: Block Public Access auf Kontoebene prüfen

Selbst wenn du Block Public Access auf Bucket-Ebene deaktivierst, kann die Kontoebene den Zugriff weiterhin blockieren. Diese Einstellung wird häufig übersehen, weil sie in einem anderen Bereich der Konsole liegt und separat verwaltet wird.

aws s3control get-public-access-block \
  --account-id 123456789012

Wenn hier ebenfalls alle vier Werte true sind, muss auch diese Einstellung angepasst werden – Bucket-Ebene allein reicht dann nicht.

Schritt 3: Object Ownership prüfen

Wenn 'Object Ownership' auf BucketOwnerEnforced gesetzt ist, sind ACLs deaktiviert. Das bedeutet: Das Setzen von public-read per ACL hat keinerlei Wirkung. Dieser Zustand ist nicht offensichtlich – die API akzeptiert den ACL-Befehl ohne Fehlermeldung, ignoriert ihn aber stillschweigend.

aws s3api get-bucket-ownership-controls \
  --bucket DEIN-BUCKET-NAME

Wenn die Ausgabe BucketOwnerEnforced zeigt, musst du statt einer ACL eine Bucket Policy für öffentlichen Zugriff verwenden.

Schritt 4: Bucket Policy prüfen

Nachdem Block Public Access deaktiviert und Object Ownership geklärt ist, braucht der Bucket eine explizite Policy, die anonymen Lesezugriff erlaubt. Ohne diese Policy bleibt der Zugriff verweigert, auch wenn alle anderen Einstellungen korrekt sind.

aws s3api get-bucket-policy \
  --bucket DEIN-BUCKET-NAME

Wenn keine Policy existiert oder s3:GetObject für Principal: "*" fehlt, ist das der nächste Ansatzpunkt.

Schritt 5: Objekt-ACL prüfen (nur wenn ACLs aktiviert sind)

Erst wenn die vorherigen Schichten geklärt sind, lohnt sich ein Blick auf die Objekt-ACL. Wenn Block Public Access aktiv oder ACLs deaktiviert sind, ist dieser Schritt irrelevant.

aws s3api get-object-acl \
  --bucket DEIN-BUCKET-NAME \
  --key pfad/zum/bild.jpg

S3 Access Denied beheben: Die zwei Lösungswege

Je nach Konfiguration gibt es zwei valide Ansätze. Der empfohlene Weg ist die Bucket Policy – sie funktioniert unabhängig von der Object Ownership-Einstellung und ist expliziter steuerbar.

Lösung 1 (Empfohlen): Block Public Access deaktivieren und Bucket Policy setzen

Schritt 1: Block Public Access auf Bucket-Ebene deaktivieren.

🔽 Block Public Access deaktivieren (CLI)
aws s3api put-public-access-block \
  --bucket DEIN-BUCKET-NAME \
  --public-access-block-configuration \
    "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"

Schritt 2: Bucket Policy für öffentlichen Lesezugriff setzen. Passe den Pfad im Resource-Feld an, wenn nur bestimmte Objekte öffentlich sein sollen (z.B. arn:aws:s3:::DEIN-BUCKET-NAME/public/*).

🔽 Bucket Policy für öffentlichen Lesezugriff (JSON)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::DEIN-BUCKET-NAME/*"
    }
  ]
}
aws s3api put-bucket-policy \
  --bucket DEIN-BUCKET-NAME \
  --policy file://bucket-policy.json

Lösung 2 (Legacy): ACL-basierter öffentlicher Zugriff

Dieser Weg funktioniert nur, wenn Object Ownership nicht auf BucketOwnerEnforced gesetzt ist. AWS empfiehlt, ACLs für die meisten Anwendungsfälle zu deaktivieren und stattdessen Bucket Policies zu verwenden.

aws s3api put-object-acl \
  --bucket DEIN-BUCKET-NAME \
  --key pfad/zum/bild.jpg \
  --acl public-read

Dieser Befehl schlägt fehl oder hat keine Wirkung, wenn Block Public Access aktiv oder ACLs deaktiviert sind.

Erfahrung aus der Praxis: Die stille Falle

Ein typisches Muster: Ein Entwickler lädt ein Bild hoch, setzt die ACL auf public-read – die Konsole bestätigt die Aktion ohne Fehlermeldung. Die URL liefert trotzdem Access Denied. Der erste Verdacht fällt auf die ACL selbst, dann auf die Bucket Policy. Beides wird geprüft, alles sieht korrekt aus.

Die eigentliche Ursache: Object Ownership war auf BucketOwnerEnforced gesetzt. Die ACL wurde zwar akzeptiert, aber vollständig ignoriert. Es gibt keinen Hinweis in der Konsole oder der API-Antwort, dass der Befehl wirkungslos war. Das CloudTrail-Log zeigt den PutObjectAcl-Aufruf als erfolgreich – was technisch korrekt ist, aber irreführend.

Der Fix war eine Bucket Policy mit s3:GetObject für Principal: "*". Zwei Minuten Arbeit – nach einer Stunde Debugging in der falschen Schicht.

graph LR S["Symptom:
Access Denied"] --> M["Fehldiagnose:
ACL und Policy geprüft"] M --> U["Eigentliche Ursache:
BucketOwnerEnforced"] U --> F["Fix:
Bucket Policy gesetzt"] F --> R["Ergebnis:
Zugriff funktioniert"]
  1. Symptom: Access Denied trotz gesetzter public-read ACL.
  2. Erste Diagnose: ACL-Einstellung und Bucket Policy geprüft – beide schienen korrekt.
  3. Eigentliche Ursache: Object Ownership auf BucketOwnerEnforced – ACLs werden ignoriert, ohne Fehlermeldung.
  4. Fix: Bucket Policy mit explizitem Allow für s3:GetObject gesetzt.

IAM-Berechtigungen für die Diagnose

Für die oben genannten CLI-Befehle benötigst du folgende IAM-Berechtigungen. Beachte, dass s3:GetPublicAccessBlock auf Kontoebene über s3control aufgerufen wird und eine separate Berechtigung erfordert.

🔽 IAM Policy für S3-Diagnose (Least Privilege)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketPublicAccessBlock",
        "s3:PutBucketPublicAccessBlock",
        "s3:GetBucketOwnershipControls",
        "s3:GetBucketPolicy",
        "s3:PutBucketPolicy",
        "s3:GetObjectAcl",
        "s3:PutObjectAcl"
      ],
      "Resource": [
        "arn:aws:s3:::DEIN-BUCKET-NAME",
        "arn:aws:s3:::DEIN-BUCKET-NAME/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetAccountPublicAccessBlock"
      ],
      "Resource": "*"
    }
  ]
}

Hinweis: s3:GetAccountPublicAccessBlock erfordert Resource: "*", da es sich um eine kontoweite Einstellung handelt, die nicht auf einzelne Bucket-ARNs eingeschränkt werden kann.

S3 Access Denied: Wrap-Up und nächste Schritte

S3-Zugriffssteuerung ist mehrschichtig – und 'Block Public Access' ist bewusst so konzipiert, dass es alle anderen Einstellungen überschreibt. Für produktive Workloads ist öffentlicher S3-Zugriff selten die richtige Wahl. Erwäge stattdessen CloudFront mit Origin Access Control (OAC), um Inhalte kontrolliert auszuliefern, ohne den Bucket direkt öffentlich zu machen.

Weiterführende Dokumentation:

Glossar

BegriffBedeutung
Block Public AccessAWS-Mechanismus auf Konto- und Bucket-Ebene, der öffentlichen Zugriff pauschal unterbindet – unabhängig von ACLs und Bucket Policies.
Object ACLZugriffskontrollliste auf Objektebene. Wird ignoriert, wenn 'Object Ownership: Bucket owner enforced' aktiv ist.
Bucket PolicyRessourcenbasierte IAM-Policy auf Bucket-Ebene. Ermöglicht feingranulare Zugriffssteuerung, auch für anonyme Zugriffe.
Object OwnershipBucket-Einstellung, die steuert, ob ACLs aktiv sind. 'BucketOwnerEnforced' deaktiviert ACLs vollständig.
Principal: *IAM-Policy-Element für anonymen (nicht authentifizierten) Zugriff. Erforderlich für öffentlich zugängliche S3-Objekte via Bucket Policy.

Kommentare

Beliebte Posts aus diesem Blog

EC2 ohne Internetzugang im eigenen VPC – Internet Gateway und Route Table korrekt einrichten

EC2 SSH Verbindungs-Timeout: Security Group Inbound-Regeln richtig konfigurieren