2 điểm bởi GN⁺ 2024-06-02 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trong các rủi ro rò rỉ dữ liệu AWS, truy cập trái phép vào bucket S3 xuất hiện lặp đi lặp lại; do thiết kế API cũ và các hành vi ngoại lệ, việc đánh giá đơn giản “công khai/riêng tư” trở nên khó khăn
  • Nhiều thao tác S3 không được gọi qua endpoint AWS chung mà qua chính URL của bucket; với policy bucket cấu hình sai, ngay cả request curl không xác thực cũng có thể thực hiện các thao tác nguy hiểm
  • Không thể xem là an toàn chỉ vì đã chặn s3:ListBucket; các đường như ListBucketVersions, ListMultipartUploads, fetch-owner có thể làm lộ object key và định danh tài khoản
  • Người upload có thể ảnh hưởng đến các thuộc tính object như storage class, tag, Object Lock, một số header liên quan đến redirect, nên cần kiểm soát bổ sung như điều kiện IAM và chính sách vòng đời
  • Nếu chỉ nhìn vào ACL và thiết lập chặn truy cập công khai để kết luận là riêng tư, bạn có thể bỏ sót các đường truy cập; người dùng Internet có thể truy cập object S3 thông qua CloudFront distribution hoặc Cognito identity pool

Thiết kế API S3 cũ và lời gọi ẩn danh

  • S3 là một trong những dịch vụ AWS đời đầu nên rất vững chắc và được kiểm thử kỹ, nhưng do dấu vết từ trước khi có các mẫu thiết kế chuẩn hóa, nó có dạng API khác với các dịch vụ AWS khác
  • Một số API S3 dùng endpoint chung như s3.us-east-2.amazonaws.com, nhưng nhiều thao tác phải request trực tiếp đến URL bucket mục tiêu
    • Ví dụ liệt kê bucket có dạng GET / với Host: [bucketname].s3.amazonaws.com
    • Truy vấn tag của bucket cũng gửi GET /?tagging đến host của bucket đó
  • Nhiều dịch vụ AWS như EC2 hay DynamoDB thường dùng endpoint chung và truyền tài nguyên mục tiêu qua HTTP header hoặc tham số
  • Bucket S3 hỗ trợ cả truy cập công khai lẫn truy cập có xác thực, nên không phải lúc nào cũng rõ thao tác API nào có thể thực hiện mà không cần xác thực
  • Nếu policy bucket mẫu cho phép Principal: "*"Action: "s3:*" trên tài nguyên bucket, request không xác thực cũng có thể xóa bucket
  • Một số thao tác không hỗ trợ request ẩn danh và sẽ trả về lỗi như s3:GetBucketOwnershipControls does not support Anonymous requests!
  • Request API ẩn danh được ghi vào CloudTrail dưới tài khoản anonymous
    • Nếu là request không xác thực, không thể xác định ai đã xóa bucket, hay ai đã truy vấn cấu hình mã hóa hoặc trạng thái logging
  • Có thể kiểm thử các đường như /?logging, /?tagging, /?encryption ngay cả trong trình duyệt
  • Cũng có các thao tác như GetObjectTorrent vẫn còn tài liệu nhưng không thể thực thi nữa

Chỉ chặn ListBucket khó ngăn lộ object key

  • Để tải object S3, cần key của từng object; key được dùng như đường dẫn file
  • Request GET đến bucket gốc có thể trả về nội dung bucket tùy điều kiện, nên từ chối s3:ListBucket trông như một biện pháp phòng vệ phổ biến
  • Ngay cả khi dùng ACL public-read cùng với policy từ chối s3:ListBucket, vẫn còn các đường để lấy object key
    • GET /?versions, tức s3:ListBucketVersions, trả về metadata của các phiên bản object trong bucket
    • GET /?uploads, tức s3:ListMultipartUploads, trả về danh sách các multipart upload đang diễn ra
  • Tài liệu HeadBucket có nội dung nói về việc kiểm tra bucket có tồn tại và quyền truy cập hay không, nhưng trên thực tế nó kiểm tra liệu có quyền thực hiện thao tác ListBucket hay không
  • Nếu chỉ kiểm tra việc ListBucket có bị từ chối hay không, bạn có thể bỏ sót khả năng lộ object key S3

Chi phí và rò rỉ từ multipart upload chưa hoàn tất

  • Multipart upload bắt đầu bằng create-multipart-upload và upload các phần bằng upload-part
  • Multipart upload chưa hoàn tất không dễ kiểm tra trong web console; có thể kiểm tra bằng /?uploads hoặc aws s3api list-multipart-uploads --bucket [bucket-name]
  • Nếu request hoàn tất không được gửi thành công, Amazon S3 không ghép các phần lại và cũng không tạo object
    • Các phần đã upload vẫn nằm trong tài khoản cho đến khi multipart upload hoàn tất hoặc bị hủy
    • Các phần được lưu trữ phát sinh chi phí lưu trữ S3
  • Chưa tìm thấy cách tải về các phần của object trước khi hoàn tất, nhưng có thể xóa chúng
  • AWS khuyến nghị áp dụng quy tắc vòng đời để xóa các upload chưa hoàn tất sau một số ngày nhất định
  • Khi liệt kê multipart upload chưa hoàn tất bằng /?uploads, ARN của principal đã bắt đầu upload sẽ được trả về
    • Nếu bạn xem các định danh như account ID, ARN là không nhạy cảm thì điều này có thể không phải vấn đề
    • Nếu không muốn công khai định danh hữu ích cho kẻ tấn công, có thể xem đây là một dạng rò rỉ

ACL và xác minh tài khoản dựa trên email

  • Tài liệu ACL của S3 vẫn còn dấu vết từ thời AWS account được định danh bằng email của root user
  • Thao tác PutBucketACL có thể chỉ định grantee bằng địa chỉ email
    • Dùng Type: AmazonCustomerByEmailEmailAddress
  • Nếu không có AWS account liên kết với email đã chỉ định, lỗi UnresolvableGrantByEmailAddress sẽ xảy ra
    • Thông báo lỗi có dạng “địa chỉ email bạn cung cấp không khớp với bất kỳ tài khoản nào trong hồ sơ”
  • Do hành vi này, có thể kiểm tra một địa chỉ email cụ thể có AWS account đã đăng ký hay không

Storage class và metadata object mà người upload có thể chọn

  • Storage class của S3 được áp dụng cho object, không phải bucket
  • Không có thiết lập ở cấp bucket để cố định storage class mong muốn; chủ thể upload có thể chỉ định storage class của object
    • Ví dụ: aws s3 cp "my.txt" "s3://mybucket/myobject.txt" --storage-class [CLASS]
  • Trong danh sách được định nghĩa sẵn, người upload có thể ảnh hưởng đến chi phí lưu trữ và truy cập trên mỗi GB mà chủ bucket phải chịu
  • Nếu dùng condition key s3:x-amz-storage-class trong IAM policy, có thể giới hạn các storage class được phép
    • Policy ví dụ chỉ cho phép STANDARD đối với s3:PutObject
  • Nếu thiết lập chính sách vòng đời, có thể chuyển tất cả object sang một storage class nhất định sau một khoảng thời gian
  • Với upload dùng pre-signed URL, AWS Signature Version 4 yêu cầu ký mọi header bắt đầu bằng X-Amz-
    • Storage class được chỉ định bằng header x-amz-storage-class
    • Nếu ứng dụng không được triển khai cực kỳ sai, không có cách thao túng tức thì rõ ràng

Tag, Object Lock và redirect cũng nằm trong phạm vi ảnh hưởng của người upload

  • Nhiều thuộc tính liên quan đến object S3 do người upload kiểm soát
  • Object tag có thể được chỉ định khi upload
    • Ví dụ: --tagging "AllYourTags=AreBelong&To=Us"
  • Các hệ thống tự động hóa dựa trên giá trị tag có thể bị ảnh hưởng bởi giá trị tag do người upload tạo
  • Object Lock có thể thiết lập lưu giữ object và legal hold nếu object locking được bật trên bucket
    • Lệnh ví dụ dùng --object-lock-retain-until-date "2099-01-01T00:00:00+0000", --object-lock-legal-hold-status "ON", --object-lock-mode "COMPLIANCE"
  • Với bucket bật static website hosting, có thể tạo open redirect bằng cấu hình của file được upload
  • Cũng cần chú ý đến danh sách đầy đủ các header mà PutObject hỗ trợ
    • Pre-signed URL có các giới hạn
    • Trong cấu hình dựa vào Cognito identity và IAM policy, request có thể được ký trong ngữ cảnh Cognito đã xác thực

Rò rỉ chủ bucket và định danh tài khoản

  • Để kiểm tra một account ID cụ thể có phải là chủ sở hữu của bucket có thể truy cập hay không, có thể thêm header x-amz-expected-bucket-owner vào request ListBucket
    • Nếu đưa account ID sai, AccessDenied sẽ được trả về
    • Nếu đưa account ID đúng và caller có quyền ListBucket, phản hồi bình thường sẽ được trả về
  • Nếu dùng tham số fetch-owner=true của API ListBucket, mỗi key trong phản hồi sẽ bao gồm phần tử Owner
  • ID trong Owner là chuỗi hex 64 ký tự mà tài liệu AWS gọi là canonical user ID
    • Đây là dạng đã được làm rối của AWS account ID
  • Nếu đặt canonical user ID vào Principal của IAM policy dưới dạng CanonicalUser, lưu rồi làm mới, nó sẽ được diễn giải thành AWS account ID
  • ListBucketVersionsListMultipartUploads cũng hoạt động tương tự dù không có fetch-owner

Object key S3 trông giống tên file nhưng hoạt động khác

  • Object key của S3 phân biệt chữ hoa chữ thường
  • Dù tên trông giống nhau, nếu khác chữ hoa chữ thường thì có thể upload nhiều object
  • Nếu ứng dụng xử lý object key S3 như tên file không phân biệt hoa thường, có thể phát sinh vấn đề
    • Ứng dụng ví dụ lưu mật khẩu người dùng trong file S3 và dùng tên file làm tên người dùng
    • Khi đăng ký chỉ kiểm tra file có tồn tại hay không, còn khi đổi mật khẩu thì chuyển tên người dùng sang chữ thường rồi ghi vào file
    • jeff đã tồn tại, vẫn có thể đăng ký JEFF, và người dùng JEFF có thể ghi đè file của jeff khi đổi mật khẩu
  • Object key S3 có thể dùng bất kỳ ký tự UTF-8 nào
    • Một số ký tự có thể gây vấn đề trong một số ứng dụng và giao thức
    • Khoảng trắng, dấu gạch chéo, ký tự phần trăm, v.v. cũng là object key hợp lệ

Dù trông như “bucket riêng tư”, vẫn có thể còn đường truy cập

  • Ngay cả khi ACL bị tắt, resource policy được đặt hẹp và block public access được bật, bucket vẫn có thể truy cập công khai
  • Đường phổ biến nhất là Amazon CloudFront distribution
    • Khi đặt CDN trước bucket S3, thường có ý định phân phối nội dung qua Internet
    • Công cụ bảo mật có thể đánh giá bucket không công khai nếu resource policy của bucket được giới hạn cho CloudFront
  • Trong ví dụ, get-bucket-policy-status trả về IsPublic: false
    • Request trực tiếp đến bucket trả về AccessDenied
    • Gửi cùng request đến domain CloudFront distribution thì nội dung object được trả về
  • Cognito identity pool cũng có thể làm lộ bucket có resource policy bị giới hạn
    • Sau khi đăng nhập thành công, Cognito cung cấp AWS credential tạm thời của vai trò đã cấu hình sẵn
    • Nếu vai trò đó có quyền s3:ListBuckets3:GetObject, người dùng có thể gọi S3 API
  • Có hai cấu hình Cognito có thể tương đương truy cập công khai
    • Self-registration: nếu người dùng Internet có thể đăng ký và đăng nhập vào app, về thực chất đó là truy cập công khai
    • Guest access: cung cấp định danh duy nhất và AWS credential cho người dùng chưa xác thực
  • Ví dụ guest access là luồng nhận IdentityId bằng get-id, nhận credential tạm thời bằng get-credentials-for-identity, rồi chạy aws s3 ls với profile đó
  • CloudFront và Cognito identity pool thực tế được dùng rất nhiều trên Internet, nhưng là các đường truy cập công khai hiếm khi được công cụ bảo mật hiển thị

1 bình luận

 
GN⁺ 2024-06-02
Ý kiến trên Hacker News
  • Có nhiều điểm thú vị, nhưng tôi khó đồng ý với việc xem chuyện hệ thống tệp phân biệt chữ hoa/thường là một điều đáng phàn nàn
    Tôi nghĩ vốn dĩ nó nên như vậy, và việc macOS không làm thế mới là điều gây khó chịu

    • Tôi không hiểu vì sao “vốn dĩ nó nên như vậy”. Windows cũng không phân biệt chữ hoa/thường, nên S3 cũng không hẳn là phá vỡ một thông lệ gần như phổ quát
      Việc tên tệp phân biệt chữ hoa/thường có thể gây bất ngờ ngay cả với người dùng không rành kỹ thuật. Nếu ai đó nói đã gửi “Book Draft 1.docx” nhưng trong hộp thư lại có “Book draft 1.docx”, thường người ta sẽ không nói “có vẻ bạn gửi nhầm tệp khác rồi?”
      Trong văn bản, chữ hoa/thường thường cũng không làm thay đổi ý nghĩa. “Hi, how are you?” và “hi, how are you?” có cùng nghĩa; chữ hoa làm đổi nghĩa chủ yếu khi phân biệt danh từ riêng với danh từ chung, mà đây hiếm khi là mối quan tâm trong tên tệp
    • Từ góc độ triển khai kỹ thuật, việc 'A' và 'a' là hai ký tự khác nhau đã được xác lập rõ trong ASCII, Unicode, v.v.
      Bỏ qua sở thích cá nhân, tôi khó hiểu việc nhà phát triển hay quản trị hệ thống lại ngạc nhiên hoặc khó chịu vì hệ thống tệp phân biệt chữ hoa/thường. Nếu cần, nhà phát triển có thể trừu tượng hóa điều đó cho người dùng cuối, chẳng hạn như trong kết quả tìm kiếm
    • Tôi là tác giả bài viết. Đây giống một quan sát hơn là phàn nàn. Không phải vấn đề tuyệt đối tốt/xấu, mà là một yếu tố cần cân nhắc khi thiết kế ứng dụng
    • Tôi không rõ lợi ích chính xác của việc tên tệp phân biệt chữ hoa/thường là gì. Ngược lại, nó mở ra rất nhiều lỗi phổ biến vốn ngay từ đầu đã có thể không xảy ra
      Nó cũng không giống như lập trình, nơi việc ép code style có thể giúp tăng tính dễ đọc. Ngay cả trong lập trình, trước khi IDE đủ thông minh để bắt lỗi gõ sai tên biến, đây cũng từng là nguyên nhân gây bug. Một trong những điểm tôi thích ở Pascal là, khác với C, nó không buộc phải bận tâm đến chữ hoa/thường
    • macOS có bảo toàn chữ hoa/thường. Cá nhân tôi thấy đó là cách kết hợp khá tốt ưu điểm của cả hai phía
      Bạn có thể đặt tên tệp theo phong cách mình muốn và cách viết đó được giữ nguyên, nhưng khi tìm kiếm hoặc xử lý thì không cần nhớ chính xác phong cách đó. Vì tìm kiếm không phân biệt chữ hoa/thường
  • Phân biệt chữ hoa/thường còn là phần dễ; điều kém trực quan hơn là đường dẫn S3 là giả
    S3 chấp nhận tải lên “/builds/1/installer.exe” và cũng hiển thị danh sách trong /builds, nhưng thực tế bạn chỉ tải lên một key tên là '/builds/1/installer.exe' có chứa ký tự '/' trong tên
    Vì vậy “/builds/1//installer.exe” và “/builds//1/installer.exe” cũng có thể được tải lên và là các tệp hoàn toàn khác nhau. Chúng chỉ là tên key, không có thư mục thật

    • Đúng. Tuy nhiên có ngoại lệ nếu dùng Directory buckets mới của S3 [1], và điều này ngược lại còn khiến tổng thể khó hiểu hơn
      [1] https://docs.aws.amazon.com/AmazonS3/latest/userguide/direct...
    • Cũng không nên bỏ qua việc "/" chỉ là ký tự phân tách đường dẫn mặc định. Nếu bạn cần "/" trong tên tệp, bạn có thể dùng một ký tự khác làm dấu phân tách: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObje...
    • Ngoài việc diễn giải đường dẫn theo một dạng chuẩn nào đó, chẳng hạn gộp các dấu / trùng lặp, tôi không rõ thư mục thật về bản chất khác gì với tiền tố
    • Cách dùng tiền tố tạo ra rất nhiều bug. Tôi hiểu vì sao AWS làm vậy và thực ra đó là một cách tiếp cận thông minh, nhưng vẫn có rất nhiều nhà phát triển mắc bẫy
      Năm nay hệ thống vận hành của chúng tôi cũng gặp một bug kỳ lạ, phải 5 người cùng xem mới tìm ra. Nguyên nhân là một object có tên đúng nghĩa là “/”, và phần mềm đã cố xử lý nó như một đường dẫn thay vì một tệp
  • Khó mà tin dùng S3 hay các dịch vụ AWS khác. Không có gì trực quan, có quá nhiều thành phần chuyển động, và quá nhiều tài liệu phải đọc
    Dù vậy, như bài gốc nêu, bạn vẫn có thể vô tình công khai mọi thứ ra thế giới. Tôi thà dùng các dịch vụ thực sự đơn giản như Hetzner Storage Boxes hay DigitalOcean Spaces

    • Tôi thích DigitalOcean Spaces, nhưng ở đó cũng có những điểm kỳ quặc gây phiền
      Gần đây tôi phát hiện rằng nếu tải lên qua pipe một tệp video lớn hơn vài MB, Location trả về sẽ thiếu https://. Vì vậy với mỗi lần upload tệp, tôi phải kiểm tra xem Location có bắt đầu bằng https không, nếu không thì thêm vào
      Đương nhiên, trong issue GitHub của S3 Node client thì họ nói “có vẻ là bug của DigitalOcean”, còn trên forum DigitalOcean thì họ nói “có vẻ là bug của S3 Node client”
    • Cách DigitalOcean xử lý giá trị bí mật đủ để khiến bất kỳ ai cũng phải sợ. Khi dùng Container Registry và cấu hình để K8S tự động truy cập, bạn có biết dịch vụ đó tạo ra một secret có toàn quyền truy cập Spaces không?
    • Sau vài năm tạm ngưng phát triển cloud và chủ yếu làm phía client, gần đây tôi quay lại và ngạc nhiên trước mức độ phức tạp đã tích tụ, cũng như gánh nặng nhận thức cần có để xây dựng một giải pháp vững như pháo đài trên public cloud
      Rất nhiều tính năng và điểm đặc thù vốn được thiết kế để hỗ trợ một số tình huống đặc biệt nay đã trở thành một phần của giao thức thông thường. Có vẻ vì lý do kinh doanh, họ cố làm sao để không ai phải quay lưng rời đi
  • Cũng phải cẩn thận khi xóa hàng chục tỷ đối tượng. Nếu gọi trực tiếp API xóa thì có thể tốn kém
    Thay vào đó, có thể thiết lập miễn phí quy tắc vòng đời đặt thời điểm hết hạn là now cho wildcard hoặc cho toàn bộ bucket. Khi đó việc tính phí lưu trữ sẽ dừng ngay lập tức và AWS sẽ tự xử lý việc xóa

    • Nói chính xác thì các lệnh gọi xóa là miễn phí; thứ phát sinh chi phí là lệnh gọi liệt kê để lấy danh sách đối tượng. Về lý thuyết, nếu bạn biết có những đối tượng nào từ nguồn khác thì sẽ miễn phí
    • Hiệu lực của quy tắc vòng đời không diễn ra tức thì. Nó được áp dụng bằng một tác vụ hàng loạt chạy mỗi ngày một lần, nên việc loại bỏ không xảy ra ngay
    • Vì AWS có thể chọn thời điểm xóa thực tế. Trong metadata, đối tượng được đánh dấu là đã xóa, còn AWS có thể xử lý việc xóa vào khung giờ tải thấp
      Điều này cũng tránh việc máy chủ API S3 bị dội bởi số lượng request mỗi giây quá lớn
  • Việc các multipart upload thất bại vẫn âm thầm nằm lại, và nếu không cấu hình vòng đời một cách rõ ràng thì còn bị tính cả chi phí lưu trữ, thật sự rất tệ
    Tôi cứ tưởng chữ S trong “Simple” là đơn giản

    • Đúng, chuyện đó tệ thật. Có thể đổ lỗi cho ahenry@, GM của S3 lúc đó
      Đề xuất của tôi là các part của upload chưa hoàn tất chỉ tồn tại 24 giờ sau hoạt động cuối cùng, và trong thời gian đó cũng không tính phí lưu trữ. ahenry@ đã bác bỏ điều đó
    • Vì vấn đề này mà chúng tôi đã mất hàng nghìn đô la
      Trên một máy chủ rất cũ, có một cron script chạy hằng đêm trong gần 10 năm, bắt đầu một multipart upload. Nó dùng để đẩy bản sao lưu vào một bucket, nhưng bucket đó cũng lưu nội dung người dùng upload, nên việc nó lớn lên từng chút mỗi ngày trông có vẻ bình thường
      Script ở trạng thái “không hoạt động”, nên chúng tôi không phụ thuộc vào dữ liệu sao lưu; trên S3 cũng không thấy file nào, và kích thước bucket tăng đều nhưng không quá mức. Thế rồi mùa xuân này nhìn lại thì thấy nó đang lưu gần 3TB multipart upload chưa hoàn tất
      Tất nhiên tôi biết câu chuyện này đầy rẫy các thực hành tệ
    • Chữ S đó là S trong cách đơn giản để làm chi phí tăng vọt
    • Cái tên “Simple” được đặt vào thời mà phương án thay thế là tự quản lý cả một cụm server gắn đĩa. Thời gian làm thay đổi mọi thứ
    • Tôi cũng từng giẫm phải mìn chi phí lưu trữ. May là chỉ vài cent, nhưng cách console hiển thị thông tin liên quan quá tệ nên tôi khá bực
  • Tôi có cảm giác các cuộc thảo luận về phân biệt/không phân biệt chữ hoa chữ thường nhìn chung quá lấy tiếng Anh làm trung tâm
    Nói cách khác, đặc biệt trong IT, các cuộc thảo luận liên quan đến ngôn ngữ quá thường xuyên lấy tiếng Anh làm trung tâm

    • Tôi lại thấy lấy tiếng Anh làm trung tâm là điều may mắn. Vì ASCII dễ xử lý hơn Unicode rất nhiều
      Nói từ góc nhìn của một người không dùng tiếng Anh làm tiếng mẹ đẻ, trong lập trình đã có quá nhiều khái niệm và yếu tố rồi. Tốt hơn là đừng tăng thêm độ phức tạp bằng cách phải xét tới 101 ngôn ngữ khác
      Unicode và múi giờ là những yếu tố tiêu biểu của việc cố xét đến nhiều ngôn ngữ và văn hóa hơn trong lập trình, nhưng kết quả là chúng tạo ra nỗi đau lớn nhất cho tất cả mọi người, kể cả lập trình viên không nói tiếng Anh
      Tôi không muốn viết chương trình bằng tiếng mẹ đẻ của mình. Nhất là nếu cái giá phải trả là khi lập trình phải cân nhắc tất cả các ngôn ngữ chính. Việc các thảo luận IT lấy tiếng Anh làm trung tâm là ổn. Đa dạng là phức tạp, còn tiếng Anh không phải ngôn ngữ thuộc sở hữu của ai, mà chỉ là công cụ mọi người dùng để giao tiếp
      Nhờ ngôn ngữ chung đó, tôi có thể diễn đạt suy nghĩ của mình với nhiều người ở Ấn Độ, Trung Quốc, Nhật Bản, Nam Mỹ, v.v. Khoảnh khắc họ quyết định nói bằng tiếng Anh, họ cũng sở hữu tiếng Anh. Không cần kéo chính trị đa dạng vào IT; tốt hơn là cứ để ở khía cạnh kỹ thuật
    • Nhân nói về văn hóa không dùng tiếng Anh, trong tiếng Nhật, các hệ thống không phân biệt chữ hoa chữ thường có phân biệt hiragana và katakana không?
      Ở một khía cạnh nào đó, hai hệ chữ âm tiết này có cảm giác giống như bảng chữ cái viết hoa/viết thường
  • Còn vài điều nữa
    Multipart upload không thể thực hiện từ nhiều máy có thông tin xác thực của instance. Lý do là các principal khác nhau nên không thể truy cập multipart upload của nhau. Nếu muốn ghép một multipart upload từ nhiều máy, bạn cần một IAM user thực sự
    Các request LIST không chỉ chậm mà còn rất đắt nếu thực hiện với số lượng lớn. Có các cách vòng tránh như “bucket inventory”, nhưng chúng không tiện cũng không rẻ
    Việc tạo bucket dùng DNS ở bên trong, nên không có tính nhất quán đọc-sau-ghi. Vì vậy đôi khi bạn không thể truy cập ngay sau khi tạo bucket, hoặc không thể xóa bucket vừa tạo trước khi chờ đủ lâu để thay đổi được lan truyền. Xem https://github.com/julik/talks/blob/master/euruko-2019-no-su...
    Có thể tạo đồng thời một object tên “foo” và một object tên “foo/bar”. Khi đó cấu trúc sẽ thành kiểu file ghi đè lên thư mục, khiến dữ liệu trong bucket không thể chuyển sang cấu trúc hệ thống file
    S3 phân biệt chữ hoa/chữ thường, nên có thể tạo các object không thể chuyển sang cấu trúc hệ thống file. Kho lưu trữ file của Rails từng bị hỏng nặng trên macOS vì giả định storage có phân biệt chữ hoa/chữ thường, và đã được sửa để luôn dùng định danh chữ thường
    Phần lớn cấu hình S3 cho phép GET nhưng không cho phép HEAD. Có vẻ đây là cách để ngăn dò xem object có tồn tại hay không, nhưng tôi không chắc. Dù sao đi nữa, luồng thân thiện với cache để kiểm tra kích thước object bằng request HEAD sẽ không hoạt động, đặc biệt với pre-signed URL. Thay vào đó phải đi vòng bằng GET với Range rất nhỏ, chẳng hạn chỉ lấy byte đầu tiên
    Nếu tạo nhiều pre-signed URL, có khả năng tăng tốc độ tạo lên 10–40 lần: https://github.com/WeTransfer/wt_s3_signer
    Bạn vẫn phải trả chi phí lưu trữ cho các multipart upload chưa hoàn tất. Cần đặc biệt cẩn thận nếu kiến trúc của bạn cho phép người dùng bắt đầu những upload kiểu này. Có một thiết lập tự động xóa các multipart upload chưa hoàn tất sau một khoảng thời gian; nếu không muốn khổ sở thì nên bật nó
    Nghịch lý là S3 từng mang tính cách mạng và hiện vẫn là một sản phẩm tuyệt vời ở nhiều tầng. Chỉ là càng nhiều tính năng thì càng nhiều bẫy

    • Thứ khiến tôi mắc kẹt vài tuần trước là giới hạn kích thước chunk ban đầu tối thiểu 5MiB của multipart upload: https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts...
      Tôi đã tạo một pipeline hậu xử lý CSV dạng streaming trong Elixir để sửa và chèn cột bằng Stream.transform(https://hexdocs.pm/elixir/Stream.html#transform/3). Các module AWS và CSV của Elixir xử lý dữ liệu streaming đầu vào, nhưng nếu tổng lượng stream đầu ra nhỏ hơn 5MiB thì module AWS vẫn dùng multipart upload, khiến S3 báo lỗi, khá buồn
  • Có một vấn đề thú vị khác mà tôi và đồng nghiệp đã phân tích trong vài ngày mới chẩn đoán được. Sau khi một kết nối TCP đơn lẻ gửi 100 HTTP request, S3 sẽ lặng lẽ bỏ các request sau đó
    https://github.com/aws/aws-sdk-go/issues/2825

    • Không hẳn là lặng lẽ bỏ; nó gửi header cho biết đã đóng kết nối TCP
      Đây là pattern phổ biến khi muốn dùng keep-alive vì hiệu năng, nhưng cũng muốn ngăn client bám quá lâu và tạo hotspot trên load balancer
  • Một điểm nữa là ở storage class tiêu chuẩn, S3 có độ trễ cao nên không phù hợp để phục vụ web
    Nhiều người nghĩ có thể host trực tiếp tài nguyên website như ảnh hoặc font từ S3, nhưng trải nghiệm người dùng có thể tệ đi
    “applications can achieve consistent small object latencies (and first-byte-out latencies for larger objects) of roughly 100–200 milliseconds.”
    Nguồn: https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimi...

    • Phần lớn mọi người dùng S3 làm origin cho AWS CloudFront để phân phối nội dung
      Dùng CloudFront signed cookies, bạn cũng có thể cấp cho một người dùng cụ thể quyền truy cập CDN chỉ tới nội dung thuộc sở hữu của họ trong S3. Khá hay
    • Để phục vụ tài sản web, thông thường dùng S3 cùng với CloudFront
      Có thể cache các tài sản được truy cập thường xuyên để giảm độ trễ, đồng thời cũng giảm chi phí đáng kể
    • S3 không được tối ưu cho việc phục vụ website trực tiếp, mà được tối ưu để lưu trữ bền vững và truy xuất lượng dữ liệu gần như không giới hạn
  • Việc uploader quyết định quy tắc nghe khá dữ dằn. Có phải điều đó nghĩa là với một website cấu hình lỏng lẻo, một người dùng đủ động cơ có thể khiến nội dung người dùng được upload lên Amazon Glacier, rồi sau đó được phục vụ từ đó không?