2 Punkte von GN⁺ 2024-06-02 | 1 Kommentare | Auf WhatsApp teilen
  • Bei AWS-Datenlecks taucht unbefugter Zugriff auf S3-Buckets immer wieder auf, und wegen alter API-Designs sowie besonderer Verhaltensweisen ist eine einfache Einstufung als „öffentlich/privat“ schwierig
  • Viele S3-Operationen werden nicht über allgemeine AWS-Endpunkte, sondern über die Bucket-URL selbst aufgerufen; bei fehlerhaften Bucket-Richtlinien sind mit einer nicht authentifizierten curl-Anfrage sogar riskante Operationen möglich
  • Es reicht nicht unbedingt, nur s3:ListBucket zu blockieren; Pfade wie ListBucketVersions, ListMultipartUploads und fetch-owner können Objektschlüssel und Konto-Identifikatoren offenlegen
  • Uploader können Einfluss auf Storage-Klasse, Tags, Object Lock und einige Redirect-bezogene Header nehmen, daher sind zusätzliche Kontrollen wie IAM-Bedingungen und Lifecycle-Richtlinien nötig
  • Wer nur anhand von ACLs und Einstellungen zum Sperren öffentlichen Zugriffs urteilt, dass ein Bucket privat sei, kann Zugriffswege übersehen; über CloudFront-Distributionen oder Cognito Identity Pools können Internetnutzer auf S3-Objekte zugreifen

Altes S3-API-Design und anonyme Aufrufe

  • S3 ist einer der frühen AWS-Services, daher robust und gut getestet, hat aber wegen Spuren aus der Zeit vor standardisierten Designmustern eine andere API-Form als viele andere AWS-Services
  • Einige S3-APIs verwenden allgemeine Endpunkte wie s3.us-east-2.amazonaws.com, aber viele Operationen müssen direkt an die Ziel-Bucket-URL gesendet werden
    • Ein Beispiel für das Abrufen der Bucket-Liste ist Host: [bucketname].s3.amazonaws.com in der Form GET /
    • Auch zum Abrufen von Bucket-Tags wird GET /?tagging an den entsprechenden Bucket-Host gesendet
  • Viele AWS-Services wie EC2 oder DynamoDB nutzen allgemeine Endpunkte, und die Angabe der Zielressource über HTTP-Header oder Parameter ist dort üblich
  • S3-Buckets unterstützen sowohl öffentlichen Zugriff als auch authentifizierten Zugriff, daher ist nicht immer klar, welche API-Operationen ohne Authentifizierung möglich sind
  • Wenn eine Beispiel-Bucket-Richtlinie Principal: "*" und Action: "s3:*" für die Bucket-Ressource erlaubt, kann der Bucket auch ohne Authentifizierung gelöscht werden
  • Einige Operationen unterstützen keine anonymen Anfragen; dann wird ein Fehler wie s3:GetBucketOwnershipControls does not support Anonymous requests! zurückgegeben
  • Anonyme API-Anfragen werden in CloudTrail unter dem Konto anonymous protokolliert
    • Bei nicht authentifizierten Anfragen lässt sich dann nicht erkennen, wer den Bucket gelöscht oder die Verschlüsselungs- bzw. Logging-Einstellungen abgefragt hat
  • Pfade wie /?logging, /?tagging und /?encryption lassen sich auch im Browser testen
  • Es gibt auch Operationen wie GetObjectTorrent, die zwar noch dokumentiert sind, aber nicht mehr ausgeführt werden können

Das Blockieren von ListBucket allein verhindert die Offenlegung von Objektschlüsseln oft nicht

  • Um ein S3-Objekt herunterzuladen, wird der jeweilige Schlüssel des Objekts benötigt; er funktioniert ähnlich wie ein Dateipfad
  • Eine GET-Anfrage an den Root eines Buckets kann je nach Bedingungen den Bucket-Inhalt zurückgeben, weshalb das Verweigern von s3:ListBucket oft wie eine naheliegende Schutzmaßnahme wirkt
  • Selbst bei public-read-ACL und einer Richtlinie, die s3:ListBucket verweigert, bleiben Wege offen, um Objektschlüssel zu erhalten
    • GET /?versions, also s3:ListBucketVersions, gibt Metadaten zu Objektversionen im Bucket zurück
    • GET /?uploads, also s3:ListMultipartUploads, gibt eine Liste laufender Multipart-Uploads zurück
  • Die Dokumentation zu HeadBucket enthält Formulierungen zur Prüfung von Bucket-Existenz und Zugriffsrechten, tatsächlich wird aber geprüft, ob die Berechtigung zur Ausführung von ListBucket besteht
  • Wer nur prüft, ob ListBucket verweigert wird, kann Möglichkeiten zur Offenlegung von S3-Objektschlüsseln übersehen

Kosten und Offenlegung durch nicht abgeschlossene Multipart-Uploads

  • Ein Multipart-Upload beginnt mit create-multipart-upload, anschließend werden mit upload-part die Teile hochgeladen
  • Nicht abgeschlossene Multipart-Uploads sind in der Webkonsole nicht leicht zu finden; sichtbar werden sie über /?uploads oder aws s3api list-multipart-uploads --bucket [bucket-name]
  • Wenn die Abschlussanfrage nicht erfolgreich übertragen wird, setzt Amazon S3 die Teile nicht zusammen und erstellt auch kein Objekt
    • Die hochgeladenen Teile verbleiben im Konto, bis der Multipart-Upload abgeschlossen oder abgebrochen wird
    • Für die gespeicherten Teile fallen S3-Speicherkosten an
  • Es wurde kein Weg gefunden, Teile eines Objekts vor dem Abschluss herunterzuladen, eine Löschung ist jedoch möglich
  • AWS empfiehlt, Lifecycle-Regeln zu verwenden, die nicht abgeschlossene Uploads nach einer bestimmten Anzahl von Tagen löschen
  • Wenn nicht abgeschlossene Multipart-Uploads über /?uploads aufgelistet werden, wird die ARN des Principals zurückgegeben, der den Upload gestartet hat
    • Wer Kennungen wie Konto-ID oder ARN nicht als sensibel betrachtet, sieht darin möglicherweise kein Problem
    • Wer die Offenlegung für Angreifer nützlicher Identifikatoren vermeiden will, kann das durchaus als Exposition werten

ACLs und kontobasierte Prüfung per E-Mail

  • In der S3-ACL-Dokumentation finden sich noch Spuren aus der Zeit, in der AWS-Konten über die E-Mail-Adresse des Root-Benutzers identifiziert wurden
  • Bei der Operation PutBucketACL kann der Grantee per E-Mail-Adresse angegeben werden
    • Verwendet werden Type: AmazonCustomerByEmail und EmailAddress
  • Falls zu der angegebenen E-Mail-Adresse kein AWS-Konto existiert, wird der Fehler UnresolvableGrantByEmailAddress zurückgegeben
    • Die Fehlermeldung lautet sinngemäß, dass die angegebene E-Mail-Adresse keinem Konto in den Aufzeichnungen zugeordnet werden kann
  • Dadurch lässt sich prüfen, ob zu einer bestimmten E-Mail-Adresse ein registriertes AWS-Konto existiert

Vom Uploader wählbare Storage-Klasse und Objektmetadaten

  • Die Storage-Klasse in S3 gilt nicht für den Bucket, sondern für das Objekt
  • Es gibt keine Einstellung, mit der sich auf Bucket-Ebene eine gewünschte Storage-Klasse festschreiben ließe; stattdessen kann die hochladende Instanz die Storage-Klasse des Objekts festlegen
    • Ein Beispiel ist aws s3 cp "my.txt" "s3://mybucket/myobject.txt" --storage-class [CLASS]
  • Uploader können innerhalb einer vorgegebenen Liste die Speicher- und Zugriffskosten pro GB beeinflussen, die der Bucket-Eigentümer trägt
  • Mit dem IAM-Bedingungsschlüssel s3:x-amz-storage-class lassen sich in Richtlinien zulässige Storage-Klassen einschränken
    • Eine Beispielrichtlinie erlaubt für s3:PutObject nur STANDARD
  • Mit Lifecycle-Richtlinien lässt sich festlegen, dass alle Objekte nach einer gewissen Zeit in eine bestimmte Storage-Klasse überführt werden
  • Bei Uploads über pre-signed URLs verlangt AWS Signature Version 4 die Signatur aller Header, die mit X-Amz- beginnen
    • Die Storage-Klasse wird über den Header x-amz-storage-class angegeben
    • Sofern die Anwendung nicht extrem fehlerhaft implementiert ist, gibt es hier keinen offensichtlichen Weg zur sofortigen Manipulation

Tags, Object Lock und Redirects liegen ebenfalls im Einflussbereich des Uploaders

  • Viele Eigenschaften von S3-Objekten werden vom Uploader kontrolliert
  • Objekttags können beim Upload gesetzt werden
    • Ein Beispiel ist --tagging "AllYourTags=AreBelong&To=Us"
  • Systeme, die Automatisierung anhand von Tag-Werten ausführen, können durch vom Uploader gesetzte Tag-Werte beeinflusst werden
  • Object Lock ermöglicht das Setzen von Objektaufbewahrung und Legal Hold, wenn für den Bucket Object Locking aktiviert ist
    • Beispielbefehle verwenden --object-lock-retain-until-date "2099-01-01T00:00:00+0000", --object-lock-legal-hold-status "ON" und --object-lock-mode "COMPLIANCE"
  • In Buckets mit aktiviertem Static Website Hosting sind Open Redirects über Einstellungen der hochgeladenen Datei möglich
  • Auch auf die vollständige Liste der von PutObject unterstützten Header sollte geachtet werden
    • Bei pre-signed URLs gibt es Einschränkungen
    • In Setups, die auf Cognito Identity und IAM-Richtlinien basieren, können Anfragen mit einem authentifizierten Cognito-Kontext signiert werden

Offenlegung von Bucket-Eigentümer und Konto-Identifikatoren

  • Um zu prüfen, ob eine bestimmte Konto-ID Eigentümer eines zugänglichen Buckets ist, kann in eine ListBucket-Anfrage der Header x-amz-expected-bucket-owner aufgenommen werden
    • Bei falscher Konto-ID wird AccessDenied zurückgegeben
    • Bei korrekter Konto-ID und vorhandener ListBucket-Berechtigung für den Aufrufer kommt eine normale Antwort zurück
  • Mit dem Parameter fetch-owner=true der API ListBucket wird für jeden Schlüssel in der Antwort ein Owner-Element ergänzt
  • Das ID-Feld in Owner ist eine 64-stellige hexadezimale Zeichenkette, die in der AWS-Dokumentation als canonical user ID bezeichnet wird
    • Dabei handelt es sich um eine verschleierte Form der AWS-Konto-ID
  • Wenn man die canonical user ID als CanonicalUser in Principal einer IAM-Richtlinie einträgt, speichert und anschließend aktualisiert, wird sie als AWS-Konto-ID aufgelöst
  • ListBucketVersions und ListMultipartUploads verhalten sich ähnlich, auch ohne fetch-owner

S3-Objektschlüssel sehen wie Dateinamen aus, verhalten sich aber anders

  • Objektschlüssel in S3 sind case-sensitiv
  • Selbst wenn Namen gleich aussehen, können mehrere Objekte hochgeladen werden, wenn sich nur die Groß- und Kleinschreibung unterscheidet
  • Probleme können entstehen, wenn eine Anwendung S3-Objektschlüssel wie nicht case-sensitive Dateinamen behandelt
    • In einem Beispiel speichert eine Anwendung Benutzerpasswörter in S3-Dateien und verwendet den Benutzernamen als Dateinamen
    • Bei der Registrierung wird nur geprüft, ob die Datei existiert; beim Passwortwechsel wird der Benutzername kleingeschrieben und in die Datei geschrieben
    • So kann JEFF registriert werden, obwohl jeff bereits existiert, und der Nutzer JEFF kann beim Passwortwechsel die Datei von jeff überschreiben
  • In S3-Objektschlüsseln kann jedes UTF-8-Zeichen verwendet werden
    • Bestimmte Zeichen können in manchen Anwendungen und Protokollen Probleme verursachen
    • Auch Leerzeichen, Schrägstriche und Prozentzeichen sind in Objektschlüsseln gültig

Auch scheinbar „private Buckets“ können noch zugängliche Pfade haben

  • Selbst wenn ACLs deaktiviert sind, die Ressourcenrichtlinie eng gefasst ist und Block Public Access aktiviert wurde, kann ein Bucket öffentlich erreichbar sein
  • Der häufigste Weg ist eine Amazon-CloudFront-Distribution
    • Wenn vor einen S3-Bucket ein CDN geschaltet wird, ist in der Regel beabsichtigt, Inhalte ins Internet auszuliefern
    • Sicherheitstools können einen Bucket als nicht öffentlich einstufen, wenn seine Ressourcenrichtlinie auf CloudFront beschränkt ist
  • Im Beispiel liefert get-bucket-policy-status IsPublic: false zurück
    • Bei einer direkten Anfrage an den Bucket wird AccessDenied zurückgegeben
    • Bei derselben Anfrage an die Domain der CloudFront-Distribution wird der Objektinhalt zurückgegeben
  • Auch ein Cognito Identity Pool kann einen Bucket mit eingeschränkter Ressourcenrichtlinie exponieren
    • Cognito liefert nach erfolgreichem Login temporäre AWS-Anmeldedaten für eine vorab konfigurierte Rolle
    • Wenn diese Rolle s3:ListBucket- und s3:GetObject-Rechte hat, kann der Nutzer die S3-API aufrufen
  • Es gibt zwei Cognito-Konfigurationen, die als öffentlicher Zugriff gelten können
    • Self-registration: Wenn Internetnutzer sich in der App registrieren und anmelden können, ist der Zugriff faktisch öffentlich
    • Guest access: Nicht authentifizierte Nutzer erhalten eine eindeutige Kennung und AWS-Anmeldedaten
  • Ein Beispiel für Gastzugriff ist der Ablauf, bei dem mit get-id eine IdentityId abgefragt, anschließend mit get-credentials-for-identity temporäre Anmeldedaten geholt und dann mit diesem Profil aws s3 ls ausgeführt wird
  • CloudFront und Cognito Identity Pools werden im Internet tatsächlich häufig verwendet, erscheinen in Sicherheitstools aber nur selten als Pfade für öffentlichen Zugriff

1 Kommentare

 
GN⁺ 2024-06-02
Hacker-News-Kommentare
  • Es gibt viele interessante Punkte, aber ich kann schwer nachvollziehen, warum man es als Problem sieht, dass das Dateisystem zwischen Groß- und Kleinschreibung unterscheidet
    Meiner Meinung nach sollte es genau so sein, und gerade dass macOS das nicht tut, finde ich eher nervig

    • Ich verstehe nicht, warum „es sollte genau so sein“. Windows unterscheidet ebenfalls nicht zwischen Groß- und Kleinschreibung, also verstößt S3 damit auch nicht gegen eine nahezu universelle Konvention
      Dass bei Dateinamen zwischen Groß- und Kleinschreibung unterschieden wird, kann selbst für nichttechnische Nutzer überraschend sein. Wenn jemand sagt, er habe „Book Draft 1.docx“ geschickt, und im Postfach liegt „Book draft 1.docx“, sagt man normalerweise nicht: „Ich glaube, Sie haben eine andere Datei geschickt“
      Auch im geschriebenen Text ändert Groß- und Kleinschreibung meist nicht die Bedeutung. „Hi, how are you?“ und „hi, how are you?“ bedeuten dasselbe, und dass Großschreibung die Bedeutung ändert, ist eher bei Eigennamen im Gegensatz zu Gattungsbegriffen relevant — bei Dateinamen ist das selten wichtig
    • Aus Sicht der technischen Implementierung ist 'A' ein anderes Zeichen als 'a' in ASCII, Unicode usw. klar etabliert
      Unabhängig vom persönlichen Geschmack finde ich es schwer nachvollziehbar, wenn Entwickler oder Systemadministratoren von Groß-/Kleinschreibung in Dateisystemen überrascht oder genervt sind. Falls nötig, kann man das für Endnutzer abstrahieren, etwa wie bei Suchergebnissen
    • Ich bin der Autor. Es ist weniger eine Beschwerde als eine Beobachtung. Es geht nicht um absolut gut oder schlecht, sondern um einen Faktor, den man beim Anwendungsdesign berücksichtigen sollte
    • Ich weiß nicht genau, welchen Vorteil es bringt, dass Dateinamen zwischen Groß- und Kleinschreibung unterscheiden. Umgekehrt werden dadurch viele häufige Fehlerquellen überhaupt erst möglich
      Es ist auch nicht so wie beim Coden, wo ein erzwungener Stil die Lesbarkeit verbessert. In der Programmierung war das ebenfalls oft eine Fehlerquelle, bis IDEs intelligent genug wurden, Tippfehler bei Variablennamen zu erkennen. Eines der guten Dinge an Pascal war, dass man sich im Gegensatz zu C nicht um Groß- und Kleinschreibung kümmern musste
    • macOS bewahrt die Groß- und Kleinschreibung. Meiner Meinung nach ist das eine gute Mischung aus den Vorteilen beider Seiten
      Man kann Dateinamen in der gewünschten Schreibweise verwenden, und diese Darstellung bleibt erhalten, aber beim Suchen oder Verarbeiten muss man sich nicht exakt an diese Schreibweise erinnern. Die Suche unterscheidet nämlich nicht zwischen Groß- und Kleinschreibung
  • Groß-/Kleinschreibung ist noch der einfache Teil; weniger intuitiv ist, dass S3-Pfade nur vorgetäuscht sind
    S3 akzeptiert das Hochladen von „/builds/1/installer.exe“ und zeigt auch eine Liste unter /builds an, aber tatsächlich wurde nur ein einzelner Schlüssel mit dem Namen '/builds/1/installer.exe' hochgeladen, in dessen Namen ein '/' vorkommt
    Deshalb kann man auch „/builds/1//installer.exe“ und „/builds//1/installer.exe“ hochladen, und das sind völlig verschiedene Dateien. Es sind nur Schlüsselnamen; echte Verzeichnisse gibt es nicht

    • Stimmt. Eine Ausnahme sind allerdings die neuen S3-Directory Buckets [1], was das Ganze eher noch verwirrender macht
      [1] https://docs.aws.amazon.com/AmazonS3/latest/userguide/direct...
    • Man darf auch nicht übersehen, dass "/" nur das Standard-Trennzeichen für Pfade ist. Wenn man "/" im Dateinamen braucht, kann man ein anderes Zeichen als Trennzeichen verwenden: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObje...
    • Abgesehen davon, einen Pfad in irgendeiner Standardform zu interpretieren, etwa doppelte / zusammenzufassen, ist mir nicht klar, worin sich ein echtes Verzeichnis grundsätzlich von einem Präfix unterscheidet
    • Der Präfix-Ansatz verursacht wirklich viele Bugs. Ich verstehe, warum AWS das so gemacht hat, und eigentlich ist es ein cleverer Ansatz, aber trotzdem tappen viele Entwickler immer wieder hinein
      Dieses Jahr hatte auch unser Produktionssystem einen seltsamen Bug, den erst fünf Leute gemeinsam gefunden haben. Die Ursache war ein Objekt, dessen Name buchstäblich „/“ war, und die Software versuchte, es nicht als Datei, sondern als Pfad zu behandeln
  • Es fällt mir schwer, S3 oder anderen AWS-Diensten zu vertrauen. Nichts daran ist intuitiv, es gibt zu viele bewegliche Teile und zu viel Dokumentation, die man lesen muss
    Und selbst dann kann man wie im Original versehentlich alles für die ganze Welt öffentlich machen. Ich würde lieber wirklich einfache Dienste wie Hetzner Storage Boxes oder DigitalOcean Spaces verwenden

    • Ich mag DigitalOcean Spaces, aber auch dort gibt es lästige Eigenheiten
      Vor Kurzem habe ich festgestellt, dass beim Hochladen von Videodateien, die größer als einige MB sind, per Pipe im zurückgegebenen Location das https:// fehlt. Deshalb muss ich jetzt bei jedem Datei-Upload prüfen, ob Location mit https beginnt, und es andernfalls hinzufügen
      Natürlich heißt es in einem GitHub-Issue zum S3-Node-Client: „Sieht nach einem DigitalOcean-Bug aus“, während es im DigitalOcean-Forum heißt: „Sieht nach einem Bug im S3-Node-Client aus“
    • Die Art, wie DigitalOcean mit Secrets umgeht, reicht aus, um jedem Angst zu machen. War dir bewusst, dass der Dienst ein Secret mit vollem Zugriff auf Spaces erstellt, wenn man die Container Registry verwendet und K8S für automatischen Zugriff konfiguriert?
    • Ich hatte einige Jahre Pause von Cloud-Entwicklung und hauptsächlich auf der Client-Seite gearbeitet, bin aber kürzlich zurückgekehrt und war überrascht von der inzwischen aufgelaufenen Komplexität und der kognitiven Last, die nötig ist, um in der Public Cloud belastbare Lösungen zu bauen
      Unzählige Funktionen und Eigenheiten, die ursprünglich für einige Sonderfälle gedacht waren, sind inzwischen Teil allgemeiner Protokolle geworden. Vermutlich ist das passiert, damit sich geschäftlich niemand abwendet
  • Auch beim Löschen von zig Milliarden Objekten ist Vorsicht geboten. Wenn man die Delete-API direkt aufruft, kann das teuer werden
    Stattdessen kann man kostenlos eine Lifecycle-Regel für Wildcards oder den gesamten Bucket mit einer Ablaufzeit auf now setzen. Dann wird die Storage-Abrechnung sofort gestoppt und AWS kümmert sich selbst um das Löschen

    • Streng genommen sind Delete-Aufrufe kostenlos; Kosten entstehen durch List-Aufrufe, die nötig sind, um die Objekte zu ermitteln. Theoretisch ist es kostenlos, wenn man aus einer anderen Quelle weiß, welche Objekte vorhanden sind
    • Die Wirkung einer Lifecycle-Regel tritt nicht sofort ein. Sie wird durch einen Batch-Job angewendet, der einmal pro Tag läuft, daher erfolgt die Entfernung nicht unmittelbar
    • Denn AWS kann den tatsächlichen Löschzeitpunkt selbst wählen. In den Metadaten wird ein Objekt als gelöscht markiert, und AWS kann die physische Löschung in Zeiten niedriger Auslastung durchführen
      So lässt sich auch vermeiden, dass die S3-API-Server mit Anfragen pro Sekunde zugeschlagen werden
  • Dass fehlgeschlagene Multipart-Uploads unsichtbar liegen bleiben und ohne explizite Lifecycle-Konfiguration sogar Storage-Kosten verursachen, ist wirklich unerquicklich
    Ich dachte, das S in „Simple“ stünde für Einfachheit

    • Ja, das ist unerquicklich. Dafür kann man ahenry@ verantwortlich machen, der damals GM von S3 war
      Mein Vorschlag war, dass Teile unvollständiger Uploads nur 24 Stunden nach der letzten Aktivität erhalten bleiben und in dieser Zeit auch keine Storage-Kosten berechnet werden. ahenry@ hat das abgelehnt
    • Wegen dieses Problems haben wir Tausende Dollar verbrannt
      Auf einem sehr alten Server lief fast zehn Jahre lang jede Nacht ein Cron-Skript an, das einen Multipart-Upload startete. Es sollte Backups in einen Bucket schieben, aber dieser Bucket speicherte auch von Nutzern hochgeladene Inhalte, sodass es normal wirkte, dass er jeden Tag ein wenig wuchs
      Das Skript war in einem „funktioniert nicht“-Zustand, deshalb waren wir nicht von den Backup-Daten abhängig, in S3 waren auch keine Dateien sichtbar, und die Bucket-Größe stieg stetig, aber nicht übermäßig. Dann stellten wir in diesem Frühjahr fest, dass dort fast 3 TB unvollständige Multipart-Uploads gespeichert wurden
      Natürlich ist mir klar, dass diese Anekdote voller schlechter Praktiken steckt
    • Das S steht für einen simplen Weg, die Kosten in die Höhe zu treiben
    • Der Name „Simple“ stammt aus einer Zeit, als die Alternative darin bestand, selbst einen Haufen Server mit Festplatten zu verwalten. Die Zeiten ändern alles
    • Ich bin auch schon auf eine Storage-Kostenmine getreten. Zum Glück waren es nur ein paar Cent, aber es macht mich ziemlich wütend, wie schlecht die Konsole die relevanten Informationen anzeigt
  • Die Diskussion über Groß-/Kleinschreibung beziehungsweise fehlende Unterscheidung wirkt größtenteils zu englischzentriert
    Anders gesagt: Gerade in der IT sind Sprachdebatten viel zu oft übermäßig auf Englisch ausgerichtet

    • Ich halte es eher für ein Glück, dass es englischzentriert ist. ASCII war im Vergleich zu Unicode viel einfacher zu handhaben
      Aus Sicht eines Nicht-Muttersprachlers hat Programmierung ohnehin schon zu viele Konzepte und Elemente. Es ist besser, die Komplexität nicht noch zu erhöhen, indem man zusätzlich 101 andere Sprachen berücksichtigen muss
      Unicode und Zeitzonen sind typische Beispiele dafür, dass man in der Programmierung mehr Sprachen und Kulturen berücksichtigen will, und am Ende verursachen sie für alle den größten Schmerz, auch für nicht englischsprachige Programmierer
      Ich möchte keine Programme in meiner Muttersprache schreiben. Noch weniger, wenn der Preis dafür wäre, beim Programmieren alle wichtigen Sprachen berücksichtigen zu müssen. Es ist in Ordnung, wenn IT-Debatten englischzentriert sind. Vielfalt bedeutet Komplexität, und Englisch ist keine Sprache, die jemand besitzt, sondern nur ein Werkzeug zur Kommunikation
      Dank dieser gemeinsamen Sprache kann ich meine Gedanken Menschen in Indien, China, Japan, Südamerika und vielen anderen Regionen vermitteln. In dem Moment, in dem sie sich entscheiden, Englisch zu sprechen, gehört Englisch auch ihnen. Man muss keine Diversitätspolitik in die IT hineinziehen; besser bleibt es technisch
    • Wenn wir schon von nicht englischsprachigen Kulturen sprechen: Unterscheiden Systeme, die im Japanischen keine Groß-/Kleinschreibung kennen, zwischen Hiragana und Katakana?
      In gewisser Weise fühlen sich die beiden Silbenschriften wie Groß- und Kleinbuchstaben eines Alphabets an
  • Es gibt noch ein paar weitere Punkte
    Multipart-Uploads lassen sich nicht von mehreren Maschinen mit Instanz-Anmeldedaten aus durchführen. Da es sich um unterschiedliche Principals handelt, können sie nicht auf die Multipart-Uploads der jeweils anderen zugreifen. Wenn man einen Multipart-Upload über mehrere Maschinen hinweg zu einem einzigen zusammensetzen will, braucht man einen echten IAM-Benutzer
    LIST-Anfragen sind nicht nur langsam, sondern in großer Zahl auch sehr teuer. Es gibt Umwege wie „bucket inventory“, aber die sind weder bequem noch günstig
    Die Erstellung von Buckets verwendet intern DNS und hat daher keine Write-after-Read-Konsistenz. Deshalb kann es sein, dass ein Bucket direkt nach dem Anlegen noch nicht erreichbar ist oder dass man einen gerade erstellten Bucket nicht löschen kann, bevor sich die Änderung ausreichend verbreitet hat. Siehe https://github.com/julik/talks/blob/master/euruko-2019-no-su...
    Man kann gleichzeitig ein Objekt namens „foo“ und ein Objekt namens „foo/bar“ anlegen. Dann entsteht eine Struktur, in der eine Datei ein Verzeichnis überschreibt, sodass sich Bucket-Daten nicht in eine Dateisystemstruktur überführen lassen
    S3 unterscheidet zwischen Groß- und Kleinschreibung, daher kann man Objekte anlegen, die sich nicht in eine Dateisystemstruktur überführen lassen. Der Rails-Dateispeicher ging von einem case-sensitiven Speicher aus und brach auf macOS massiv auseinander; behoben wurde das, indem Bezeichner immer kleingeschrieben werden
    Die meisten S3-Konfigurationen erlauben GET, aber nicht HEAD. Das scheint eine Methode zu sein, um das Ermitteln der Existenz von Objekten zu verhindern, sicher bin ich aber nicht. Jedenfalls funktioniert ein cache-freundlicher Ablauf, bei dem man per HEAD-Request die Objektgröße prüft, insbesondere bei pre-signed URLs nicht. Stattdessen muss man mit einem GET mit sehr kleinem Range ausweichen, etwa indem man nur das erste Byte abruft
    Wenn man viele pre-signed URLs erzeugt, lässt sich die Erzeugungsgeschwindigkeit möglicherweise um das 10- bis 40-Fache steigern: https://github.com/WeTransfer/wt_s3_signer
    Auch für nicht abgeschlossene Multipart-Uploads zahlt man weiterhin Speicherkosten. Wenn Nutzer in einer Architektur solche Uploads starten können, muss man besonders aufpassen. Es gibt eine Einstellung, die unvollständige Multipart-Uploads nach einer gewissen Zeit automatisch löscht; wenn man sich Ärger sparen will, sollte man sie aktivieren
    Paradoxerweise war S3 revolutionär und ist auch heute auf vielen Ebenen ein großartiges Produkt. Es hat nur so viele Funktionen, dass es entsprechend viele Fallstricke gibt

    • Was mich vor ein paar Wochen erwischt hat, war die Begrenzung auf eine minimale anfängliche Chunk-Größe von 5 MiB bei Multipart-Uploads: https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts...
      Ich habe in Elixir mit Stream.transform(https://hexdocs.pm/elixir/Stream.html#transform/3) eine Streaming-CSV-Nachbearbeitungspipeline gebaut, die Spalten modifiziert und einfügt. Die AWS- und CSV-Module in Elixir verarbeiten eingehende Streaming-Daten, aber wenn die Gesamtmenge des ausgehenden Streams kleiner als 5 MiB ist, verwendet das AWS-Modul einen Multipart-Upload, was in S3 zu einem Fehler führte — ziemlich frustrierend
  • Es gibt noch ein anderes interessantes Problem, das ich zusammen mit einem Kollegen über mehrere Tage analysiert und diagnostiziert habe. S3 verwirft nach 100 HTTP-Anfragen über eine einzelne TCP-Verbindung stillschweigend alle weiteren Anfragen
    https://github.com/aws/aws-sdk-go/issues/2825

    • Ganz stillschweigend ist es nicht; es sendet einen Header, dass die TCP-Verbindung geschlossen wurde
      Das ist ein gängiges Muster, wenn man aus Performance-Gründen Keep-Alive möchte, aber verhindern will, dass Clients zu lange verbunden bleiben und Hotspots auf dem Load Balancer erzeugen
  • Dazu kommt, dass S3 in der Standard-Speicherklasse eine hohe Latenz hat und sich daher nicht für Web-Serving eignet
    Viele denken, man könne Website-Ressourcen wie Bilder oder Fonts einfach direkt aus S3 hosten, aber das kann die User Experience verschlechtern
    „applications can achieve consistent small object latencies (and first-byte-out latencies for larger objects) of roughly 100–200 milliseconds.”
    Quelle: https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimi...

    • Die meisten verwenden S3 für die Auslieferung von Inhalten als Origin für AWS CloudFront
      Mit CloudFront signed cookies kann man bestimmten Nutzern auch CDN-Zugriff nur auf ihre eigenen Inhalte in S3 geben. Ziemlich cool
    • Um Web-Assets auszuliefern, verwendet man normalerweise S3 zusammen mit CloudFront
      Dadurch werden häufig abgerufene Assets gecacht, die Latenz sinkt, und auch die Kosten lassen sich recht gut senken
    • S3 ist nicht für das direkte Ausliefern von Websites optimiert, sondern dafür, nahezu unbegrenzte Daten dauerhaft zu speichern und wieder abzurufen
  • Dass der Uploader die Regeln festlegt, ist ziemlich heftig. Bedeutet das, dass ein ausreichend motivierter Nutzer auf einer schlecht konfigurierten Website User-Content in Amazon Glacier hochladen könnte, damit er später von dort ausgeliefert wird?