Provision S3 Storage End-to-End¶
This guide walks through the complete lifecycle of setting up S3-compatible object storage: create an RGW user, inspect the credentials, create a bucket, apply a quota, and upload a file via a presigned URL.
Time to complete: ~10 minutes
Prerequisites: An organization, a project with object storage enabled, and a bearer token with rgw:create and rgw:update permissions.
Step 1 — Create an RGW user¶
POST /rgw/users
Authorization: Bearer <token>
Content-Type: application/json
{
"user": {
"name": "my-app-storage",
"project_id": "<project-uuid>"
}
}
The response includes the new user's id, access_key_id, and the unmasked secret_key. Store the secret key immediately — subsequent calls return it masked.
{
"id": "b3f1c2d4-...",
"name": "my-app-storage",
"project_id": "<project-uuid>",
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"locked": false,
"quota": {
"max_size_kb": 524288000,
"enabled": true
}
}
A default quota of 500 GB is applied automatically.
Step 2 — Create a bucket¶
Use any S3-compatible client with the credentials from step 1. Here is an example with the AWS CLI:
aws configure --profile my-app \
--region de-muc1 \
--endpoint-url https://storage.muc1.de.bnerd.com
# Enter credentials when prompted:
# AWS Access Key ID: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws --profile my-app s3 mb s3://my-app-assets
Alternatively, create a bucket through the platform API via the buckets endpoint or the dashboard file browser.
Step 3 — Adjust quota (admin only)¶
If the default 500 GB is insufficient, an admin can raise it:
PATCH /rgw/users/<user-id>
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"quota": {
"max_size_kb": 1073741824,
"enabled": true
}
}
max_size_kb: 1073741824 = 1 TB. Use -1 to remove the size limit entirely.
Admin-only
Quota changes require platform-admin privileges. Non-admin requests with a quota field receive 403 Forbidden.
Step 4 — Generate a presigned upload URL¶
To allow a browser or client to upload directly to RGW without routing through your backend:
POST /rgw/users/<user-id>/buckets/my-app-assets/objects/upload_url
Authorization: Bearer <token>
Content-Type: application/json
{ "key": "uploads/logo.png" }
Response:
The client can PUT the file body directly to url — no additional headers required. The URL expires in 15 minutes.
Step 5 — Verify the upload¶
aws --profile my-app \
--endpoint-url https://storage.muc1.de.bnerd.com \
s3 ls s3://my-app-assets/uploads/
Or via the platform API:
GET /rgw/users/<user-id>/buckets/my-app-assets/objects?prefix=uploads/
Authorization: Bearer <token>
Rotating the secret key¶
The response includes the new unmasked secret_key. Update your application's environment variables or secrets manager before the old key is invalidated.
Locked users cannot rotate keys
If locked: true, renew_key is a no-op. An admin must unlock the user first.
Clean up¶
To delete the user and all its data:
Irreversible
purge_objects=true deletes every object in every bucket before removing the user. The platform records an audit event with the bucket names and total size before the purge runs. There is no undo.
Using the dashboard¶
All user and key management is available in the dashboard at app.bnerd.cloud:
- Create an RGW user: Services → Object Storage → New User
- View / rotate keys: User detail → Access Keys tab → Rotate Key
- Browse buckets: User detail → Buckets tab — file browser included
- Request quota increase: contact your account manager or open a support ticket
Using the CLI¶
# List RGW users
bnerd rgw users list
# Create a user
bnerd rgw users create my-app-storage
# Show user (includes access_key_id)
bnerd rgw users get <user-id>
# Rotate the S3 access key
bnerd rgw users renew-key <user-id>
# List buckets
bnerd rgw buckets list --user-id <user-id>
Using Terraform¶
resource "bnerd_rgw_user" "app" {
name = "my-app-storage"
project_id = var.project_id
}
output "s3_access_key" { value = bnerd_rgw_user.app.access_key_id }
output "s3_secret_key" {
value = bnerd_rgw_user.app.secret_key
sensitive = true
}
quota and locked are computed/read-only — managed by platform admins, not Terraform. See Terraform Provider reference.
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
secret_key shows as masked (***) | The key was already returned once and is now masked | Rotate the key with POST /rgw/users/{id}/renew_key to get a new unmasked value |
403 on renew_key | User is locked (locked: true) | Request an admin unlock before rotating |
S3 client 403 AccessDenied | Wrong endpoint URL or wrong credentials | Verify endpoint is https://storage.muc1.de.bnerd.com, and check the access key and secret key |
| Bucket create fails | Quota reached | Check quota.max_size_kb vs current usage — request a quota increase if needed |
purge_objects irreversible | Expected — deletion is permanent | Ensure you have a backup before deleting a user with purge_objects=true |