2 points par GN⁺ 2024-06-02 | 1 commentaires | Partager sur WhatsApp
  • Dans les risques de fuite de données AWS, les accès non autorisés aux buckets S3 reviennent régulièrement, et l’ancien design de l’API ainsi que certains comportements exceptionnels rendent difficile un simple jugement « public/privé »
  • De nombreuses opérations S3 ne sont pas appelées via un endpoint AWS générique, mais via l’URL du bucket elle-même ; avec une politique de bucket mal configurée, même une requête curl non authentifiée peut permettre des opérations dangereuses
  • Bloquer seulement s3:ListBucket ne suffit pas forcément à être en sécurité : des chemins comme ListBucketVersions, ListMultipartUploads ou fetch-owner peuvent révéler des clés d’objets et des identifiants de compte
  • L’uploader peut influencer des propriétés d’objet comme la classe de stockage, les tags, Object Lock et certains en-têtes liés aux redirections ; des contrôles supplémentaires tels que des conditions IAM et des règles de cycle de vie sont donc nécessaires
  • Se fier uniquement aux ACL et aux paramètres de blocage de l’accès public pour conclure qu’un bucket est privé peut faire manquer certains chemins d’accès ; des internautes peuvent accéder à des objets S3 via une distribution CloudFront ou un identity pool Cognito

Ancien design de l’API S3 et appels anonymes

  • S3 étant l’un des premiers services d’AWS, il est robuste et bien testé, mais les traces d’une époque antérieure aux modèles de conception standardisés lui donnent une forme d’API différente de celle d’autres services AWS
  • Certaines API S3 utilisent des endpoints génériques comme s3.us-east-2.amazonaws.com, mais de nombreuses opérations doivent être envoyées directement à l’URL du bucket cible
    • Un exemple de listing de bucket est un GET / avec Host: [bucketname].s3.amazonaws.com
    • La récupération des tags d’un bucket envoie aussi GET /?tagging à l’hôte du bucket concerné
  • Beaucoup de services AWS, comme EC2 ou DynamoDB, utilisent généralement un endpoint générique et transmettent la ressource cible via des en-têtes HTTP ou des paramètres
  • Les buckets S3 prenant en charge à la fois l’accès public et l’accès authentifié, il n’est pas toujours clair quelles opérations d’API sont possibles sans authentification
  • Si un exemple de politique de bucket autorise Principal: "*" et Action: "s3:*" sur la ressource du bucket, une requête non authentifiée peut même supprimer le bucket
  • Certaines opérations ne prennent pas en charge les requêtes anonymes et renvoient une erreur comme s3:GetBucketOwnershipControls does not support Anonymous requests!
  • Les requêtes API anonymes sont enregistrées dans CloudTrail sous le compte anonymous
    • Si la requête n’est pas authentifiée, il est impossible d’identifier qui a supprimé le bucket, ou consulté la configuration de chiffrement ou l’état de journalisation
  • Des chemins comme /?logging, /?tagging et /?encryption peuvent aussi être testés dans un navigateur
  • Certaines opérations, comme GetObjectTorrent, restent documentées mais ne peuvent plus être exécutées

Bloquer ListBucket ne suffit pas à empêcher l’exposition des clés d’objets

  • Pour télécharger un objet S3, il faut connaître sa clé, qui s’utilise comme un chemin de fichier
  • Une requête GET à la racine du bucket peut, selon les conditions, renvoyer son contenu ; refuser s3:ListBucket semble donc être une défense courante
  • Même en combinant une ACL public-read et une politique refusant s3:ListBucket, il reste des chemins pour obtenir des clés d’objets
    • GET /?versions, c’est-à-dire s3:ListBucketVersions, renvoie les métadonnées des versions d’objets dans le bucket
    • GET /?uploads, c’est-à-dire s3:ListMultipartUploads, renvoie la liste des multipart uploads en cours
  • La documentation de HeadBucket évoque la vérification de l’existence du bucket et des droits d’accès, mais en pratique elle vérifie si l’appelant a le droit d’effectuer l’action ListBucket
  • Se limiter à vérifier que ListBucket est refusé peut faire manquer un risque d’exposition des clés d’objets S3

Coûts et exposition des multipart uploads non terminés

  • Un multipart upload commence avec create-multipart-upload, puis les parties sont envoyées avec upload-part
  • Les multipart uploads non terminés ne sont pas faciles à repérer dans la console web ; on peut les vérifier avec /?uploads ou aws s3api list-multipart-uploads --bucket [bucket-name]
  • Si la requête de finalisation n’est pas envoyée avec succès, Amazon S3 n’assemble pas les parties et ne crée pas l’objet
    • Les parties uploadées restent dans le compte jusqu’à ce que le multipart upload soit terminé ou interrompu
    • Les parties stockées génèrent des frais de stockage S3
  • Aucune méthode n’a été trouvée pour télécharger les parties d’un objet avant finalisation, mais leur suppression est possible
  • AWS recommande d’appliquer une règle de cycle de vie qui supprime les uploads non terminés après un certain nombre de jours
  • Lister les multipart uploads non terminés avec /?uploads renvoie l’ARN du principal qui a lancé l’upload
    • Si l’on ne considère pas les identifiants comme les ID de compte ou les ARN comme sensibles, ce n’est pas forcément un problème
    • Si l’on refuse d’exposer des identifiants utiles à un attaquant, cela peut être considéré comme une exposition

ACL et vérification de compte basée sur l’e-mail

  • La documentation des ACL S3 conserve des traces de l’époque où les comptes AWS étaient identifiés par l’e-mail de l’utilisateur racine
  • L’opération PutBucketACL peut désigner le grantee par adresse e-mail
    • Elle utilise Type: AmazonCustomerByEmail et EmailAddress
  • S’il n’existe pas de compte AWS associé à l’e-mail indiqué, une erreur UnresolvableGrantByEmailAddress se produit
    • Le message d’erreur indique que « l’adresse e-mail fournie ne correspond à aucun compte enregistré »
  • Ce comportement permet de vérifier si une adresse e-mail donnée possède un compte AWS enregistré

Classes de stockage et métadonnées d’objet que l’uploader peut choisir

  • Les classes de stockage S3 s’appliquent aux objets, pas aux buckets
  • Il n’existe pas de paramètre permettant de fixer la classe de stockage souhaitée au niveau du bucket ; l’entité qui effectue l’upload peut définir la classe de stockage de l’objet
    • Exemple : aws s3 cp "my.txt" "s3://mybucket/myobject.txt" --storage-class [CLASS]
  • L’uploader peut, parmi une liste prédéfinie, influencer les coûts de stockage et d’accès par Go supportés par le propriétaire du bucket
  • Dans une politique IAM, la clé de condition s3:x-amz-storage-class permet de limiter les classes de stockage autorisées
    • L’exemple de politique n’autorise que STANDARD pour s3:PutObject
  • En configurant une politique de cycle de vie, on peut transférer tous les objets vers une classe de stockage donnée après un certain délai
  • Pour les uploads utilisant une URL pré-signée, AWS Signature Version 4 exige la signature de tous les en-têtes commençant par X-Amz-
    • La classe de stockage est indiquée avec l’en-tête x-amz-storage-class
    • Sauf implémentation très défaillante de l’application, il n’existe pas de moyen évident de la manipuler immédiatement

Tags, Object Lock et redirections sont aussi sous l’influence de l’uploader

  • De nombreuses propriétés liées aux objets S3 sont contrôlées par l’uploader
  • Les tags d’objet peuvent être définis au moment de l’upload
    • Exemple : --tagging "AllYourTags=AreBelong&To=Us"
  • Les systèmes qui automatisent des traitements selon les valeurs de tags peuvent être influencés par les tags créés par l’uploader
  • Object Lock permet de définir la conservation d’un objet et un legal hold lorsque l’object locking est activé sur le bucket
    • La commande d’exemple utilise --object-lock-retain-until-date "2099-01-01T00:00:00+0000", --object-lock-legal-hold-status "ON" et --object-lock-mode "COMPLIANCE"
  • Dans les buckets où l’hébergement de site web statique est activé, une redirection ouverte est possible via la configuration du fichier uploadé
  • Il faut aussi prêter attention à la liste complète des en-têtes pris en charge par PutObject
    • Les URL pré-signées ont des limitations
    • Dans les configurations reposant sur une identité Cognito et des politiques IAM, les requêtes peuvent être signées avec le contexte Cognito authentifié

Exposition du propriétaire du bucket et des identifiants de compte

  • Pour vérifier si un ID de compte donné est propriétaire d’un bucket accessible, on peut ajouter l’en-tête x-amz-expected-bucket-owner à une requête ListBucket
    • Si l’ID de compte est incorrect, AccessDenied est renvoyé
    • Si l’ID de compte est correct et que l’appelant dispose du droit ListBucket, la réponse est normale
  • Le paramètre fetch-owner=true de l’API ListBucket ajoute un élément Owner à chaque clé dans la réponse
  • L’ID dans Owner est une chaîne hexadécimale de 64 caractères que la documentation AWS appelle canonical user ID
    • Il s’agit d’une forme obfusquée de l’ID de compte AWS
  • Si l’on met ce canonical user ID dans le champ Principal d’une politique IAM en tant que CanonicalUser, puis que l’on enregistre et actualise, il est interprété comme un ID de compte AWS
  • ListBucketVersions et ListMultipartUploads se comportent de manière similaire, même sans fetch-owner

Les clés d’objets S3 ressemblent à des noms de fichiers, mais fonctionnent différemment

  • Les clés d’objets S3 sont sensibles à la casse
  • Même si les noms semblent identiques, il est possible d’uploader plusieurs objets lorsque la casse diffère
  • Si une application traite les clés d’objets S3 comme des noms de fichiers insensibles à la casse, des problèmes peuvent survenir
    • L’application d’exemple stocke les mots de passe des utilisateurs dans des fichiers S3 et utilise le nom d’utilisateur comme nom de fichier
    • À l’inscription, elle vérifie seulement l’existence du fichier ; lors du changement de mot de passe, elle convertit le nom d’utilisateur en minuscules avant d’écrire dans le fichier
    • Même si jeff existe déjà, l’inscription de JEFF est possible, et l’utilisateur JEFF peut écraser le fichier de jeff en changeant son mot de passe
  • N’importe quel caractère UTF-8 peut être utilisé dans une clé d’objet S3
    • Certains caractères peuvent poser problème dans certaines applications et certains protocoles
    • Les espaces, les barres obliques et les signes pourcentage sont aussi valides dans les clés d’objets

Même un « bucket privé » apparent peut garder des chemins d’accès

  • Même si les ACL sont désactivées, que la politique de ressource est strictement limitée et que le blocage de l’accès public est activé, un bucket peut rester accessible publiquement
  • Le chemin le plus courant est une distribution Amazon CloudFront
    • Lorsqu’un CDN est placé devant un bucket S3, l’intention est généralement de diffuser du contenu sur Internet
    • Les outils de sécurité peuvent considérer qu’un bucket n’est pas public si sa politique de ressource est limitée à CloudFront
  • Dans l’exemple, get-bucket-policy-status renvoie IsPublic: false
    • Une requête envoyée directement au bucket renvoie AccessDenied
    • La même requête envoyée au domaine de distribution CloudFront renvoie le contenu de l’objet
  • Un identity pool Cognito peut aussi exposer un bucket dont la politique de ressource est limitée
    • Après une connexion réussie, Cognito fournit des identifiants AWS temporaires pour un rôle préconfiguré
    • Si ce rôle dispose des permissions s3:ListBucket et s3:GetObject, l’utilisateur peut appeler l’API S3
  • Deux configurations Cognito peuvent relever de l’accès public
    • Self-registration : si les internautes peuvent s’inscrire à l’application et se connecter, cela devient en pratique un accès public
    • Guest access : fournit un identifiant unique et des identifiants AWS à des utilisateurs non authentifiés
  • Un exemple d’accès invité suit le flux suivant : obtenir un IdentityId avec get-id, récupérer des identifiants temporaires avec get-credentials-for-identity, puis exécuter aws s3 ls avec ce profil
  • CloudFront et les identity pools Cognito sont effectivement souvent utilisés sur Internet, mais ce sont des chemins d’accès public rarement signalés par les outils de sécurité

1 commentaires

 
GN⁺ 2024-06-02
Avis de Hacker News
  • Il y a beaucoup de points intéressants, mais j’ai du mal à être d’accord avec l’idée de voir comme un défaut le fait qu’un système de fichiers soit sensible à la casse
    À mes yeux, c’est comme ça que ça devrait être, et c’est plutôt le fait que macOS ne le soit pas qui m’agace

    • Je ne vois pas pourquoi « c’est comme ça que ça devrait être ». Windows n’est pas sensible à la casse non plus, donc S3 ne va pas vraiment à l’encontre d’une convention quasi universelle
      La sensibilité à la casse dans les noms de fichiers peut surprendre même les utilisateurs non techniques. Si quelqu’un dit avoir envoyé « Book Draft 1.docx » et que, dans la boîte mail, on trouve « Book draft 1.docx », on ne répond généralement pas « il me semble que vous avez envoyé un autre fichier »
      Dans l’écriture aussi, la casse ne change généralement pas le sens. « Hi, how are you? » et « hi, how are you? » veulent dire la même chose, et les cas où une majuscule change le sens relèvent surtout de la distinction entre noms propres et noms communs, ce qui est rarement une préoccupation pour les noms de fichiers
    • Du point de vue de l’implémentation technique, le fait que « A » et « a » soient des caractères différents est bien établi dans ASCII, Unicode, etc.
      Indépendamment des préférences personnelles, il est difficile de comprendre qu’un développeur ou un administrateur système soit surpris ou agacé par la sensibilité à la casse d’un système de fichiers. Si nécessaire, le développeur peut l’abstraire pour l’utilisateur final, comme dans des résultats de recherche
    • Je suis l’auteur. Ce n’est pas une plainte, plutôt une observation. Ce n’est pas une question de bien ou de mal dans l’absolu, mais un facteur à prendre en compte lors de la conception d’une application
    • Je ne vois pas exactement quel avantage on tire de noms de fichiers sensibles à la casse. À l’inverse, cela ouvre la porte à beaucoup d’erreurs courantes qui ne pourraient tout simplement pas exister autrement
      Ce n’est pas comme en programmation, où imposer un style de code peut aider la lisibilité. Même en programmation, avant que les IDE ne deviennent assez intelligents pour détecter les fautes de frappe dans les noms de variables, c’était souvent une source de bugs. L’un des points que j’aimais dans Pascal, contrairement à C, était de ne pas avoir à se soucier de la casse
    • macOS préserve la casse. Personnellement, je trouve que c’est un bon compromis entre les deux approches
      On peut écrire les noms de fichiers dans le style qu’on veut et cette graphie est conservée, mais lors d’une recherche ou d’un traitement, on n’a pas besoin de se souvenir exactement de ce style. La recherche n’est en effet pas sensible à la casse
  • La sensibilité à la casse est plutôt simple ; ce qui est moins intuitif, c’est que les chemins S3 sont factices
    S3 accepte l’envoi de « /builds/1/installer.exe » et affiche aussi une liste dans /builds, mais en réalité vous avez importé une seule clé appelée « /builds/1/installer.exe », dont le nom contient des « / »
    Du coup, « /builds/1//installer.exe » et « /builds//1/installer.exe » peuvent aussi être envoyés et sont des fichiers complètement différents. Ce ne sont que des noms de clés ; il n’y a pas de vrais répertoires

    • Exact. Il y a toutefois une exception avec les nouveaux Directory buckets S3 [1], ce qui rend l’ensemble encore plus déroutant
      [1] https://docs.aws.amazon.com/AmazonS3/latest/userguide/direct...
    • Il ne faut pas non plus oublier que « / » n’est que le caractère de séparation de chemin par défaut. Si vous avez besoin d’un « / » dans le nom d’un fichier, vous pouvez utiliser un autre caractère comme délimiteur : https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObje...
    • À part le fait d’interpréter les chemins sous une forme canonique, par exemple en fusionnant les / répétés, je ne vois pas en quoi un vrai répertoire est fondamentalement différent d’un préfixe
    • L’approche par préfixes crée vraiment beaucoup de bugs. Je comprends pourquoi AWS a fait ce choix et c’est effectivement une approche intelligente, mais de nombreux développeurs continuent de se faire piéger
      Cette année, notre système de production a aussi rencontré un bug étrange, et il a fallu cinq personnes pour en trouver la cause. C’était un objet dont le nom était littéralement « / », et le logiciel essayait de le traiter comme un chemin plutôt que comme un fichier
  • Il est difficile de faire confiance à S3 ou à d’autres services AWS. Rien n’est intuitif, il y a trop d’éléments en mouvement et trop de documentation à lire
    Même comme ça, on peut finir, comme dans l’article, par tout rendre public par erreur. Je préférerais utiliser un service réellement simple comme Hetzner Storage Boxes ou DigitalOcean Spaces

    • J’aime bien DigitalOcean Spaces, mais il a aussi ses particularités pénibles
      J’ai récemment découvert que lorsqu’on envoie par pipe un fichier vidéo de plus de quelques Mo, le Location renvoyé omet https://. Il faut donc vérifier à chaque upload que Location commence par https, et l’ajouter si ce n’est pas le cas
      Évidemment, dans les issues GitHub du client S3 Node, on répond « ça ressemble à un bug DigitalOcean », et sur les forums DigitalOcean, « ça ressemble à un bug du client S3 Node »
    • La façon dont DigitalOcean gère les secrets a de quoi faire peur à n’importe qui. Quand vous utilisez Container Registry et que vous configurez K8S pour y accéder automatiquement, saviez-vous que ce service crée un secret ayant un accès complet à Spaces ?
    • Après avoir fait une pause de quelques années dans le développement cloud pour travailler surtout côté client, j’y suis revenu récemment, et j’ai été surpris par la complexité accumulée entre-temps et par la charge cognitive nécessaire pour construire des solutions blindées sur le cloud public
      Une foule de fonctionnalités et de particularités, conçues à l’origine pour aider dans certains cas spécifiques, font désormais partie du protocole courant. J’ai l’impression que c’est le résultat d’une logique commerciale visant à ne faire fuir personne
  • Il faut aussi faire attention lorsqu’on supprime des dizaines de milliards d’objets. Appeler directement l’API de suppression peut coûter cher
    À la place, on peut configurer gratuitement une règle de cycle de vie qui fixe l’expiration à maintenant, pour un wildcard ou pour tout le bucket. La facturation du stockage s’arrête alors immédiatement, et AWS se charge de la suppression

    • À strictement parler, les appels de suppression sont gratuits ; ce qui coûte, ce sont les appels de listage nécessaires pour obtenir les objets. En théorie, si l’on sait depuis une autre source quels objets existent, c’est gratuit
    • L’effet d’une règle de cycle de vie n’est pas immédiat. Elle s’applique via un traitement par lot qui tourne une fois par jour, donc la suppression ne se produit pas tout de suite
    • C’est parce qu’AWS peut choisir le moment de la suppression effective. Les métadonnées indiquent que l’objet a été supprimé, et AWS peut traiter la suppression pendant les périodes de faible utilisation
      Cela évite aussi que les serveurs de l’API S3 se fassent marteler par le nombre de requêtes par seconde
  • Le fait que des uploads multipart échoués restent invisibles et génèrent quand même des frais de stockage si l’on ne configure pas explicitement une règle de cycle de vie est vraiment pénible
    Je croyais que le S de “Simple” voulait dire simplicité

    • Oui, c’est nul. On peut blâmer ahenry@, qui était GM de S3 à l’époque
      Ma proposition était que les parties des uploads incomplets ne restent que 24 heures après la dernière activité, sans facturation du stockage pendant ce délai. ahenry@ a refusé
    • Ce problème nous a coûté plusieurs milliers de dollars
      Sur un très vieux serveur, un script cron lançait chaque nuit, depuis presque dix ans, un upload multipart. Il servait à pousser des sauvegardes dans un bucket qui stockait aussi du contenu uploadé par les utilisateurs, donc le fait qu’il grossisse un peu chaque jour semblait normal
      Le script était « non fonctionnel », donc nous ne dépendions pas des données de sauvegarde ; les fichiers n’apparaissaient pas non plus dans S3, et la taille du bucket augmentait régulièrement sans excès. Puis, ce printemps, nous avons découvert qu’il stockait près de 3 To d’uploads multipart incomplets
      Bien sûr, je sais que cette anecdote est remplie de mauvaises pratiques
    • Le S, c’est celui de Simple méthode pour faire exploser les coûts
    • Le nom “Simple” date d’une époque où l’alternative était de gérer soi-même une flotte de serveurs avec des disques. Le temps change tout
    • Moi aussi, je suis déjà tombé sur une mine de coûts de stockage. Heureusement, ce n’était que quelques centimes, mais la manière dont la console affiche les informations correspondantes est tellement mauvaise que ça m’a bien énervé
  • Les débats sur la sensibilité ou non à la casse me semblent en général beaucoup trop anglocentrés
    Autrement dit, surtout dans l’IT, les discussions liées aux langues sont trop souvent excessivement centrées sur l’anglais

    • Je pense que c’est plutôt une chance que ce soit anglocentré, parce qu’ASCII était bien plus facile à gérer qu’Unicode
      En tant que personne dont l’anglais n’est pas la langue maternelle, je dirais que la programmation comporte déjà beaucoup trop de concepts et d’éléments. Mieux vaut ne pas ajouter de complexité en prenant aussi en compte 101 autres langues
      Unicode et les fuseaux horaires sont des exemples typiques d’éléments visant à prendre en compte davantage de langues et de cultures en programmation, et au final ils créent les plus grosses douleurs pour tout le monde, y compris les programmeurs non anglophones
      Je ne veux pas écrire des programmes dans ma langue maternelle. Encore moins si, en contrepartie, il faut tenir compte de toutes les grandes langues lorsqu’on programme. Que les discussions IT soient centrées sur l’anglais me va. La diversité, c’est de la complexité, et l’anglais n’est pas une langue que quelqu’un possède : c’est simplement un outil que les gens utilisent pour communiquer
      Grâce à cette langue commune, je peux exprimer mes idées à beaucoup de personnes en Inde, en Chine, au Japon, en Amérique du Sud, etc. Dès lors qu’elles choisissent de parler anglais, elles possèdent elles aussi l’anglais. Inutile d’importer la politique de la diversité dans l’IT ; mieux vaut rester sur un plan technique
    • Puisqu’on parle de cultures non anglophones, dans les systèmes japonais insensibles à la casse, est-ce qu’on distingue hiragana et katakana ?
      D’une certaine manière, ces deux syllabaires donnent l’impression d’être comme les alphabets majuscule/minuscule
  • Il y en a encore quelques-uns
    Les uploads multipart ne peuvent pas être effectués depuis plusieurs machines disposant d’identifiants d’instance. Comme les principals diffèrent, ils ne peuvent pas accéder aux uploads multipart les uns des autres. Pour assembler un même upload multipart depuis plusieurs machines, il faut un véritable utilisateur IAM
    Les requêtes LIST ne sont pas seulement lentes : en volume, elles coûtent très cher. Il existe des contournements comme « bucket inventory », mais ce n’est ni pratique ni bon marché
    La création de buckets utilise DNS en interne, elle n’offre donc pas de cohérence lecture-après-écriture. Il arrive ainsi qu’un bucket ne soit pas accessible juste après sa création, ou qu’on ne puisse pas supprimer un bucket fraîchement créé avant d’avoir attendu suffisamment longtemps la propagation des changements. Voir https://github.com/julik/talks/blob/master/euruko-2019-no-su...
    On peut créer simultanément un objet nommé « foo » et un objet nommé « foo/bar ». On se retrouve alors avec une structure où un fichier écrase un répertoire, ce qui rend impossible la portabilité des données du bucket vers une structure de système de fichiers
    S3 est sensible à la casse, ce qui permet de créer des objets impossibles à transposer dans une structure de système de fichiers. Le stockage de fichiers de Rails supposait un stockage sensible à la casse, ce qui a provoqué de gros problèmes sur macOS, et a été corrigé en utilisant toujours des identifiants en minuscules
    La plupart des configurations S3 autorisent GET mais pas HEAD. C’est probablement une façon d’empêcher la détection de l’existence d’un objet, sans certitude. Quoi qu’il en soit, le flux compatible avec les caches consistant à vérifier la taille d’un objet via une requête HEAD ne fonctionne pas, surtout avec des URL pré-signées. Il faut à la place contourner le problème avec un GET sur une plage très petite, par exemple en ne récupérant que le premier octet
    Si vous générez beaucoup d’URL pré-signées, il est possible d’accélérer leur génération d’un facteur 10 à 40 : https://github.com/WeTransfer/wt_s3_signer
    Vous payez tout de même les frais de stockage des uploads multipart inachevés. Il faut être particulièrement prudent si votre architecture permet aux utilisateurs de lancer ce type d’upload. Il existe un réglage pour supprimer automatiquement les uploads multipart inachevés après un certain délai ; activez-le si vous voulez vous éviter des ennuis
    Paradoxalement, S3 a été révolutionnaire et reste un excellent produit à bien des niveaux. Mais comme il a beaucoup de fonctionnalités, il a aussi beaucoup de pièges

    • Ce qui m’a piégé il y a quelques semaines, c’est la limite de taille minimale de 5 Mio pour le premier chunk dans les uploads multipart : https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts...
      J’avais construit en Elixir un pipeline de post-traitement CSV en streaming qui modifie et injecte des colonnes avec Stream.transform(https://hexdocs.pm/elixir/Stream.html#transform/3). Les modules AWS et CSV d’Elixir traitent bien les données entrantes en streaming, mais si le volume total du flux sortant est inférieur à 5 Mio, le module AWS utilise un upload multipart, ce qui provoquait une erreur côté S3, à ma grande tristesse
  • Il y a un autre problème amusant qu’un collègue et moi avons analysé et diagnostiqué pendant plusieurs jours. S3 abandonne silencieusement les requêtes suivantes lorsqu’une même connexion TCP a envoyé 100 requêtes HTTP
    https://github.com/aws/aws-sdk-go/issues/2825

    • Ce n’est pas exactement silencieux : il envoie un en-tête indiquant que la connexion TCP a été fermée
      C’est un schéma courant quand on veut du keep-alive pour les performances, tout en évitant que des clients restent connectés trop longtemps et créent des points chauds sur le répartiteur de charge
  • Il y a aussi le fait que S3, avec la classe de stockage standard, présente une latence élevée et n’est pas adapté au service web direct
    Beaucoup de gens pensent qu’il suffit d’héberger directement depuis S3 des ressources de site web comme des images ou des polices, mais cela peut dégrader l’expérience utilisateur
    « applications can achieve consistent small object latencies (and first-byte-out latencies for larger objects) of roughly 100–200 milliseconds. »
    Source : https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimi...

    • La plupart utilisent S3 comme origine pour AWS CloudFront afin de servir du contenu
      Avec les CloudFront signed cookies, on peut aussi donner à un utilisateur donné un accès CDN uniquement au contenu qui lui appartient dans S3. C’est plutôt élégant
    • Pour servir des assets web, on utilise généralement S3 avec CloudFront
      Cela permet de mettre en cache les assets fréquemment consultés afin de réduire la latence, et aussi de diminuer sensiblement les coûts
    • S3 n’est pas optimisé pour servir directement des sites web, mais pour stocker durablement et récupérer des volumes de données quasi illimités
  • Le fait que l’uploader décide des règles est assez brutal. Sur un site web mal configuré, cela veut-il dire qu’un utilisateur suffisamment motivé pourrait faire en sorte que du contenu utilisateur soit uploadé dans Amazon Glacier, puis servi plus tard depuis là ?