S3-Compatible API
AWS compatibleQuake AI Object Storage exposes an S3-compatible gateway. Use standard AWS SDKs, the AWS CLI, boto3, s3cmd, rclone, or any S3-compatible tool. Point it at the Quake AI endpoint.
Looking for the native OpenStack API? Swift API reference →
Authentication
The S3 API uses EC2 credentials (access key + secret key), not Keystone tokens. These are the same credential type used by AWS, so your tools don't need to know about OpenStack.
Create credentials
Console: Go to Storage → Object Storage → S3 Credentials and select Create S3 Credential. Copy the access key and secret key immediately: the secret is shown only once.
CLI:
openstack ec2 credentials create # Output: # +------------+--------------------------------------+ # | Field | Value | # +------------+--------------------------------------+ # | access | fgmWGy9r92iv5RRk0kscAWSWAs2Pu00O | # | secret | tYuXhyDFE2v888k43sRIn0zs2Pu0RRkt | # +------------+--------------------------------------+ # List existing credentials openstack ec2 credentials list
Credentials are tied to your user account and work across all Quake AI Cloud projects. See How to create S3 credentials for the full walkthrough.
Endpoints
Each region has its own S3 endpoint. Use path-style addressing; virtual-hosted-style is not supported.
| Region | Endpoint |
|---|---|
| US East 1 | https://object.us-east-1.rumble.cloud |
| US East 2 | https://object.us-east-2.rumble.cloud |
| US West 1 | https://object.us-west-1.rumble.cloud |
Replace the endpoint in all SDK configuration examples below with the one matching your region.
SDK examples
Copy-paste ready examples for the most popular S3 tools. Replace YOUR_ACCESS_KEY and YOUR_SECRET_KEY with your EC2 credentials.
Python (boto3)
import boto3
s3 = boto3.client(
"s3",
endpoint_url="https://object.us-east-2.rumble.cloud",
aws_access_key_id="YOUR_ACCESS_KEY",
aws_secret_access_key="YOUR_SECRET_KEY",
)
# List buckets
for bucket in s3.list_buckets()["Buckets"]:
print(bucket["Name"])
# Upload a file
s3.upload_file("local-file.txt", "my-bucket", "remote-file.txt")
# Download a file
s3.download_file("my-bucket", "remote-file.txt", "downloaded.txt")
# Generate a presigned URL (valid 1 hour)
url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": "my-bucket", "Key": "remote-file.txt"},
ExpiresIn=3600,
)
print(url)AWS CLI
# Configure a named profile aws configure set aws_access_key_id YOUR_ACCESS_KEY --profile rumble aws configure set aws_secret_access_key YOUR_SECRET_KEY --profile rumble aws configure set region us-east-1 --profile rumble aws configure set endpoint_url https://object.us-east-1.rumble.cloud --profile rumble # List buckets aws s3 ls --profile rumble # Create a bucket aws s3 mb s3://my-bucket --profile rumble # Upload a file aws s3 cp local-file.txt s3://my-bucket/ --profile rumble # Sync a directory aws s3 sync ./local-dir s3://my-bucket/prefix/ --profile rumble # Delete a bucket and all contents aws s3 rb s3://my-bucket --force --profile rumble
s3cmd
# Configure s3cmd (use the downloaded .cfg or configure manually) # ~/.s3cfg or pass -c /path/to/config.cfg [default] access_key = YOUR_ACCESS_KEY secret_key = YOUR_SECRET_KEY host_base = object.us-east-2.rumble.cloud host_bucket = object.us-east-2.rumble.cloud use_https = True # List buckets s3cmd ls # Create a bucket s3cmd mb s3://my-bucket # Upload a file s3cmd put local-file.txt s3://my-bucket/ # Download a file s3cmd get s3://my-bucket/remote-file.txt ./downloaded.txt # Set CORS (XML only) s3cmd setcors cors-policy.xml s3://my-bucket
Go (aws-sdk-go-v2)
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func main() {
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithRegion("us-east-1"),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
"YOUR_ACCESS_KEY",
"YOUR_SECRET_KEY",
"",
)),
)
if err != nil {
log.Fatal(err)
}
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String("https://object.us-east-1.rumble.cloud")
o.UsePathStyle = true
})
out, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
if err != nil {
log.Fatal(err)
}
for _, b := range out.Buckets {
fmt.Println(*b.Name)
}
}UsePathStyle: true is required; virtual-hosted-style bucket addressing is not supported.
Operation compatibility
Supported operations map to the AWS S3 API. Unsupported operations return 501 Not Implemented or 403 Forbidden. Partial support means the operation works with limitations noted below.
Buckets
ListBucketsCreateBucketDeleteBucketHeadBucketGetBucketLocationGetBucketAclPutBucketAclObjects
ListObjectsV2ListObjects (v1)PutObjectGetObjectHeadObjectDeleteObjectDeleteObjects (multi)CopyObjectPutObjectAclGetObjectAclMultipart
CreateMultipartUploadUploadPartCompleteMultipartUploadAbortMultipartUploadListMultipartUploadsListPartsCORS
PutBucketCorsGetBucketCorsDeleteBucketCorsVersioning
PutBucketVersioningGetBucketVersioningListObjectVersionsLifecycle
PutBucketLifecycleEvents
PutBucketNotificationPolicies
PutBucketPolicyGetBucketPolicyTagging
PutBucketTaggingQuery
SelectObjectContentEncryption
PutBucketEncryptionLimitations vs. AWS S3
The S3-compatible gateway is backed by OpenStack Swift. Some AWS S3 features have no Swift equivalent and are not available.
Lifecycle policies
PutBucketLifecycleConfiguration is not implemented. Object expiration must be managed via the Swift native API or application logic.
Event notifications
No SNS/SQS/Lambda-style event notifications. Poll for changes or use application-level event tracking.
IAM / Bucket policies
PutBucketPolicy and IAM-style policies are not supported. Access control uses Swift ACLs via the native API.
Versioning
Basic enable/suspend and delete markers work. MFA delete and advanced versioning features are not available.
Server-side encryption
PutBucketEncryption is not implemented via S3. Use Swift X-Object-Meta-Encryption headers via the native API.
Object tagging
PutObjectTagging and PutBucketTagging are not supported. Use Swift metadata headers instead.
Select / query
SelectObjectContent (S3 Select) is not available. Download objects and process locally.
Virtual-hosted-style addressing
Only path-style addressing is supported. Set UsePathStyle/force_path_style in your SDK configuration.
Bucket naming
Bucket names are scoped to your project (tenant), not globally unique. URLs include the tenant ID prefix for unauthenticated access.
CORS configuration
Enable cross-origin access for web applications by setting a CORS policy on your bucket. Both JSON (AWS CLI) and XML (s3cmd) formats work.
# Set CORS with AWS CLI (JSON)
aws s3api put-bucket-cors --profile rumble \
--bucket my-bucket \
--cors-configuration '{
"CORSRules": [{
"AllowedOrigins": ["https://app.example.com"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}]
}'
# Set CORS with s3cmd (XML file)
s3cmd setcors cors-policy.xml s3://my-bucket
# Verify
aws s3api get-bucket-cors --profile rumble --bucket my-buckethttps://object.{region}.rumble.cloud/{tenant_id}:bucket/object. See the full CORS guide for details and common pitfalls.Large object support
Objects larger than 5 GB must use multipart upload. The S3 multipart API is fully supported.
| Limit | Value |
|---|---|
| Max single PUT size | 5 GB |
| Max object size (multipart) | 5 TB |
| Part size range | 5 MB – 5 GB |
| Max parts per upload | 10,000 |
| Max concurrent multipart uploads | No hard limit (project quota applies) |
Both the AWS CLI and boto3 handle multipart uploads automatically for large files. No extra configuration needed.