Skip to content

Public files don't render in Docker Compose, and 'private' isn't enforced by the bucket in Aspire #1410

Description

@iammukeshm

Follow-up from #1402. Uploads now work in the Docker Compose stack, but files uploaded as Public (for example the admin avatar) still don't render there. BuildPublicUrl returns PublicBaseUrl, or else ServiceUrl (http://rustfs:9000/fsh/...). Browsers can't resolve that host, and the compose bucket has no anonymous-read policy anyway.

Why this isn't a one-line fix

Visibility is not encoded in the storage key. StorageKeyBuilder puts every file under the same layout, so there's no way to grant anonymous read to public files only:

Stack Bucket policy today Effect
Aspire (AppHost.cs) anonymous s3:GetObject on fsh/* Public files render. Private files are also readable without auth by anyone who has the key. Keys contain a UUIDv7, so they're hard to guess, but "private" isn't enforced by the store.
Compose none Private files are safe, public URLs are broken
AWS Terraform off by default; app_s3_public_read_prefix (uploads/) if enabled Can only work if public files live under a known prefix, which they don't

Proposal

  1. Put visibility in the key. Have StorageKeyBuilder add a public/ or private/ root prefix (existing keys stay valid; only new uploads get it).
  2. Grant anonymous read only on public/* in all three stacks: the Aspire bootstrap policy, a new compose bootstrap policy, and the Terraform app_s3_public_read_prefix default changed to public/.
  3. Compose: set Storage__S3__PublicBaseUrl=${FSH_S3_PUBLIC_URL}/fsh.
  4. Changing visibility (if a file can go from public to private) becomes a copy plus delete. We need to check whether the Files module allows that today.

Alternative considered: an API endpoint that answers 302 with a presigned GET for public files. It needs no bucket policy anywhere, but it adds an API round trip per image and URLs change on every request, so browsers and CDNs can't cache them. Prefix + policy is better for public assets, since those are what you want cached.

Also worth doing

Touches src/BuildingBlocks/Storage (key builder, if it lives there) and the Files module, so it needs maintainer sign-off on the design before a PR.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions