dibbla storage
Provision S3-compatible buckets with a hard quota and credentials scoped to exactly that bucket, injected into your apps as secrets.
dibbla storage manages S3-compatible object storage buckets. Creating a bucket
gives you three things at once: the bucket, a credential scoped to that bucket
alone, and four secrets carrying that credential into your apps. Your code
reads environment variables and speaks plain S3 — you never copy a key anywhere.
The command is also available as dibbla buckets.
Buckets belong to your organization, not to a single app — like databases. Use
--deployment <alias> to scope a bucket’s secrets to one app instead.
The injected secrets
Creating a bucket named my-uploads injects four secrets:
| Secret | What it holds |
|---|---|
STORAGE_MY_UPLOADS_ENDPOINT | The S3 endpoint URL |
STORAGE_MY_UPLOADS_BUCKET | The bucket name |
STORAGE_MY_UPLOADS_ACCESS_KEY_ID | The scoped access key |
STORAGE_MY_UPLOADS_SECRET_ACCESS_KEY | Its secret |
The <NAME> segment is the bucket name uppercased with hyphens turned into
underscores — bucket names may contain hyphens, environment variable names may
not. A bucket called my-uploads therefore yields STORAGE_MY_UPLOADS_*.
The credential is scoped by policy to that one bucket: it cannot read, write or even list any other bucket in the platform.
storage list
dibbla storage list
dibbla storage list --quiet # names only, one per line
storage create
dibbla storage create my-uploads
dibbla storage create my-uploads --size 25Gi
dibbla storage create my-uploads --deployment my-app
dibbla storage create logs-archive --size 5Gi --expire-days 90
| Flag | Meaning |
|---|---|
--name | Bucket name, as an alternative to the positional argument |
--size | Hard quota, e.g. 5Gi, 500Mi. Defaults to 5Gi |
--deployment <alias> | Scope the bucket’s secrets to one app instead of the whole org |
--expire-days <n> | Delete objects automatically once they are this old |
Name rules: 3–48 characters of lowercase letters, digits and hyphens,
starting and ending with a letter or digit (^[a-z0-9][a-z0-9-]{1,46}[a-z0-9]$).
Uppercase and underscores are rejected. The names workflows, files,
cnpg-backups and workflow-artifacts are reserved by the platform.
The quota is hard. Once a bucket is full, uploads fail at the S3 layer with
a quota error rather than silently succeeding — size it for real usage, and use
--expire-days for data that ages out.
storage info
dibbla storage info
Prints size, object count and quota for every bucket. Sizes come from the store’s usage accounting, so a very recent upload can take a moment to appear.
storage rotate
dibbla storage rotate my-uploads
dibbla storage rotate my-uploads --no-restart
Mints a replacement credential and updates the injected secrets. The old key stops working immediately.
Because pods read secrets from the environment when they start, a rotated key
only reaches a running app on restart — so rotate restarts the bound
deployment’s services for you. That is the whole point: without it, “rotate”
would be an outage spelled differently. --no-restart skips the restart, and
then your running pods hold an invalid key until you restart them yourself with
dibbla apps restart.
storage delete
dibbla storage delete my-uploads
dibbla storage delete my-uploads --yes
dibbla storage delete my-uploads --force # bucket still holds objects
Deletes the bucket, its scoped credential and its four injected secrets. A
bucket that still contains objects is refused unless you pass --force.
storage credentials
A bucket’s keys are injected into your app as STORAGE_<NAME>_* secrets, and a
secret is write-only: no Dibbla API, CLI command or MCP tool returns its value.
So storage credentials no longer prints the app’s keys. It asks Dibbla for a
key of your own instead — for that one bucket’s objects only, expiring after an
hour, and never the app’s key, which stays as it is.
It does not work from your own computer yet. The key comes with the
storage’s address inside Dibbla, which aws, mc or rclone on your machine
cannot reach.
Until it does, a local run points its STORAGE_<NAME>_* lines at a local
S3-compatible store such as MinIO, or runs without the bucket, and
dibbla export copies a bucket’s objects out as plain
files.
There is deliberately no storage connect: S3 has no interactive client like
psql to wrap.
Using a bucket from your app
Any S3 SDK works. Read the injected variables and use path-style addressing:
import os, boto3
s3 = boto3.client(
"s3",
endpoint_url=os.environ["STORAGE_MY_UPLOADS_ENDPOINT"],
aws_access_key_id=os.environ["STORAGE_MY_UPLOADS_ACCESS_KEY_ID"],
aws_secret_access_key=os.environ["STORAGE_MY_UPLOADS_SECRET_ACCESS_KEY"],
config=boto3.session.Config(s3={"addressing_style": "path"}),
)
s3.put_object(Bucket=os.environ["STORAGE_MY_UPLOADS_BUCKET"], Key="hello.txt", Body=b"hi")
When storage is not available
On an instance where the platform has no object storage configured, every
storage command fails with STORAGE_NOT_CONFIGURED. That is the server saying
the capability is switched off, not a problem with your setup — self-hosted
installs enable it in the Helm values.