DefangLabs / DefangLabs/defang
S3 / Object Storage Support
@lionello is already working on this.
Since Aug 14, 2026.
- Dominant language
- Go
- Stars
- 166
- Forks
- 24
- Avg merge
- 10h 8m
- Merged PRs (30d)
- 33
Description
This is an issue to track provisioning of managed object storage, like AWS S3, DigitalOcean Spaces, GCS, etc.
Please vote on this issue if you would like to express support for this feature.
Design (consolidated from #2212, 2026-09-01)
The extension is x-defang-s3. It attaches to a stub service, in the same way as x-defang-postgres / x-defang-redis: keep a minio:-shaped service block in compose.yaml and tag it. The minio image is a sentinel only — Defang elides it and never runs it, so the archival status of MinIO Community Edition does not apply. Defang provisions real object storage per cloud and injects the env vars the app already reads, so compose.yaml does not change per cloud.
The name says the protocol, not the backend: the app-facing contract is the S3 API on every cloud, the same way x-defang-postgres names Postgres. (Earlier drafts said x-defang-object-store.)
Per cloud
- AWS — a native S3 bucket. No static keys: Defang scopes an IAM policy for the bucket onto the task role and leaves the access-key/secret-key env vars empty. S3 SDKs that use the AWS default credential chain pick the task role up on their own.
provider/defangaws/aws/s3.goalready hascreatePrivateBucket(SSE, public-access block, retain/force-destroy recipes), so provisioning is mostly done. - Azure — no native S3 API, so this cloud needs a translation layer:
s3proxywithjclouds.provider=azureblob-sdkand emptyjclouds.identity/jclouds.credential, which givesDefaultAzureCredential→ managed identity with SDK-handled token refresh. (The olderazureblobprovider cannot refresh — s3proxy issue 352.) The app-to-proxy hop still needs a project-local generated SigV4 key pair, because clients such asrust-s3always sign; useauthorization=aws-v2-or-v4and path-style addressing. Sidecars are not supported on Azure today, sos3proxymust run as a standalone service first. - GCP — a native GCS bucket over its S3-compatible XML/interop API. Auth is HMAC keys minted for a dedicated service account. This is a real static secret, so "no static keys" is best-effort per cloud and does not gate v1.
Decisions locked
- One bucket per
x-defang-s3service for v1. Multiple buckets per extension is long-term. - The bucket name is declared in the extension. DNS cannot carry the endpoint: the name is globally unique, and TLS breaks as well, because no certificate matches
objs.project.internaland path style does not help (SNI still carries the private name). So env-var injection is the only route, and the CLI injects env at compose-load time, before provisioning — a generated name is not known yet. - Env var convention needs no new code:
wireDependentServicesinfixup.goalready emits<SERVICE>_URLfor the model-provider wiring. Reuse it, e.g.OBJS_URL, plus_BUCKETand_REGION. - Retain or delete on
compose downis a recipe setting, the same as postgres/redis. - No manual bucket-collision handling. Pulumi's
aws.s3.Bucketalready surfacesBucketAlreadyExists/BucketAlreadyOwnedByYouas a normal apply error. Keep only the bucket-name-shape pre-flight check.pulumi.Importis a nice-to-have.
Out of scope for v1
- Presigned URLs for third-party clients (browsers). SigV4 signs the
Hostheader, so a signature-less or localhost-trust proxy hop breaks them. - A local/ephemeral dev storage engine and the split-horizon DNS work that presigned-URL portability needs.
Phases and status
| Phase | Work | Status |
|---|---|---|
| 1 | CLI wiring in defang: extension allowlist, name validation, IsMinioRepo, env injection |
#2239 open |
| 2 | AWS ObjectStore component in pulumi-defang |
DefangLabs/pulumi-defang#503 (draft) |
| 3 | Azure via standalone s3proxy |
not started |
| 4 | GCP via GCS interop + HMAC | not started |
Provider-side tracking and the full design thread: DefangLabs/pulumi-defang#480. Prior art: the closed WIP PR DefangLabs/defang-mvp#1537 (learnings recorded there) and DefangLabs/defang-mvp#1527.
Forcing function: the Buzz BYOC deploy bundle (DefangLabs/buzz#2) hand-writes S3 endpoint and static-key config today, and has no clean Azure story. With x-defang-s3 that bundle would not need to diverge from deploy/compose/.
Still open
- GCP: HMAC keys vs. a proxy, and whether "no static keys" is AWS-only.
- Should Defang warn when a compose file keeps a plain
minioon a mounted volume, separately from this extension?
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.