Guides: access & security

How to publish a folder publicly

Serve one prefix to the world — curl-able installers, no credentials — while the rest of the bucket stays locked.

1. Mark the prefix public

Acme publishes installers from public/ in the downloads bucket. In YAML:

# validate
storage:
  buckets:
    downloads:
      public_prefixes:
        - public/

Or in the UI: Settings → Storage → Buckets → expand the downloads row → Anonymous read access → pick Specific prefixes and add public/:

Bucket policies with the public-access tri-state

The tri-state maps directly to the YAML: None (no anonymous access), Specific prefixes (public_prefixes: [...]), Entire bucket (public: true).

Apply the change — it hot-reloads; the proxy synthesizes a read-only public-prefix:downloads admission block from it.

2. Know what anonymous callers get

Anonymous requests can GET, HEAD, and LIST under the prefix (LIST results never escape it), run as an audited $anonymous user, and can never write — full semantics in the authentication reference.

Mind the trailing slash

public/ matches public/installer.zip but not publicity/report.pdf; public (no slash) is a string-prefix match and would expose both. Always end the prefix with / unless you deliberately want string-prefix matching.

Whole-bucket public

public: true is shorthand for public_prefixes: [""] — every object in the bucket becomes anonymously readable:

# validate
storage:
  buckets:
    downloads:
      public: true

The proxy logs a startup warning when a whole bucket is public. Use it only for buckets that contain nothing but published artifacts — anything uploaded there later is public the moment it lands, and LIST exposes every key name in the bucket.

If you only need to share one object for a limited time, don't publish a prefix at all — generate a presigned URL instead (expires after at most 7 days, revocable by rotating the signing user's key):

aws --endpoint-url https://s3.acme.example \
  s3 presign s3://downloads/internal/draft-installer.zip --expires-in 3600

Verify with a cold curl

Test from a shell with no AWS environment — a leftover AWS_ACCESS_KEY_ID would authenticate the request and prove nothing (credentials always win over public-prefix config):

env -i curl -sw "%{http_code}\n" -o /dev/null \
  https://s3.acme.example/downloads/public/installer-1.2.0.zip
# 200

env -i curl -sw "%{http_code}\n" -o /dev/null \
  https://s3.acme.example/downloads/internal/roadmap.pdf
# 403 — outside the public prefix

env -i curl -sw "%{http_code}\n" -o /dev/null -X PUT \
  https://s3.acme.example/downloads/public/evil.zip -d x
# 403 — anonymous writes are always denied

Anonymous fetches appear in Settings → Diagnostics → Audit as user=$anonymous.

Lock writes down

Publishing a prefix doesn't change who can write to it — review that separately: