Feature request: secure-uploads for S3 backends without per-object ACLs

AI-generated summary

This feature request addresses a conflict in Discourse’s secure_uploads implementation on S3-compatible backends that do not support per-object ACLs. polybos explains that avatars and site assets are currently served via direct, unauthenticated URLs, requiring public read access. However, secure post uploads require authenticated access to remain private. Since both file types often share the same bucket and path prefixes, users cannot configure the bucket to be both private (for security) and public (for assets) without per-object ACLs. This results in broken avatars if the bucket is set to private.

The poster requests two potential solutions: serving public assets via presigned URLs when the bucket is private, or supporting separate buckets/prefixes for public assets versus secure uploads. Other users have confirmed this issue affects various environments. CrookedGrandma encountered similar limitations when attempting to use Azure with a local file server, while satonotdead reported the same problem when using Bunny CDN’s S3-compatible endpoint.

Problem

On S3-compatible backends that don’t support per-object ACLs secure_uploads cannot coexist with publicly-served content.

Avatars and theme/site assets seems to be served via direct, unauthenticated S3 URLs, which requires public read on the object. But the same bucket holds secure post uploads that should stay private in my desired setup — and both (public and private files) share the same path prefixes (original/..., optimized/...). Without per-object ACLs, there’s no way to make the public files public and the other files private.

My current situation: avatars and assets are broken (bucket is private → 403 for those files), while secure post uploads work fine via the /secure-uploads/ proxy.

The core conflict

Secure uploads require an authenticated read path; avatars/assets require an unauthenticated. Both sit behind the same bucket-level boundary, which can’t distinguish them without per-object ACLs.

Requested solutions

  1. Serve avatars/assets via presigned URLs when the bucket is private and ACLs are disabled — same mechanism as secure uploads. From my perspective this could also work just for logged-in users for scenarios with a non-public Discourse instance.
  2. Support separate buckets or prefixes for public assets vs. secure uploads, so the access boundary aligns with the public/private boundary and suitable ACLs could be created.

Is either approach feasible, or is there already a supported path I’ve missed?

3 Likes

Just ran into this exact issue when trying to implement Discourse in Azure, which offers no S3-compatible service. Therefore, we’re trying to run a local file server, but none offers per-object ACLs.

Added my vote. I found this limitation, trying to use Bunny CDN (with their S3 compatible endpoint) for hosting Discourse files on their storage service.