Hanzo

Hanzo S3

S3-compatible object storage for AI infrastructure

Hanzo S3

API reference · Hanzo S3 API → — every endpoint, generated from the OpenAPI spec.

Hanzo S3 is a high-performance, S3-compatible object storage service built for AI workloads. It provides durable, scalable storage for model artifacts, training datasets, media assets, event streams, and application data across the Hanzo platform.

Hanzo S3 is built on SeaweedFS (Apache-2.0) and exposes the AWS S3 API with Signature V4 authentication. Any S3 client, SDK, or tool works unmodified — point it at the endpoint and use your access key and secret key.

S3 APIhttps://s3.hanzo.ai
Consolehttps://s3.hanzo.ai (web admin)
ProtocolAWS S3 (SigV4), path-style and virtual-host style
Regionus-east-1 (default; cosmetic — set it on your client)
Sourcegithub.com/hanzoai/s3

Features

  • S3 API Compatible: Drop-in replacement for Amazon S3 — works with aws CLI, mc, boto3, @aws-sdk/client-s3, and any other S3 SDK
  • Buckets & Objects: Full create/list/delete, put/get/head/copy/delete, and ListObjects v1 + v2 + versions
  • Multipart Uploads: Create, upload-part, copy-part, complete, abort, and list — for large objects
  • Presigned URLs: Time-limited GET/PUT URLs for browser and client-side transfers
  • POST-Policy Uploads: Direct browser form uploads with policy constraints
  • Versioning: Track and restore previous versions of any object
  • Object Lock: Retention and legal-hold for compliance (WORM)
  • Lifecycle Rules: Automated expiration and tiering
  • Server-Side Encryption: SSE-S3 and SSE-KMS (keys managed by Hanzo KMS)
  • Bucket Policies, ACLs, CORS, Tagging: Standard S3 access and metadata controls
  • Advanced IAM (optional): OIDC/JWT identity providers, STS role assumption, and AWS-style policy documents

Architecture

Hanzo S3 runs the SeaweedFS storage stack behind the S3 gateway:

┌───────────────────────────────────────────────────────────────┐
│  Clients                                                       │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐  │
│  │ aws CLI  │  │ mc       │  │ boto3 /  │  │ Console      │  │
│  │          │  │          │  │ aws-sdk  │  │ s3.hanzo.ai  │  │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └──────┬───────┘  │
└───────┼─────────────┼─────────────┼───────────────┼──────────┘
        │             │             │               │
        ▼             ▼             ▼               ▼
┌───────────────────────────────────────────────────────────────┐
│  s3.hanzo.ai — S3 Gateway (SigV4 auth, S3 → Filer translation) │
└───────────────┬───────────────────────────────────────────────┘

   ┌────────────┼─────────────────────────┐
   ▼            ▼                          ▼
┌────────┐  ┌────────┐               ┌──────────────────┐
│ Master │  │ Filer  │               │ Volume servers   │
│ (topo) │  │ (meta) │               │ (object data)    │
└────────┘  └────────┘               └──────────────────┘
ComponentRole
S3 GatewayTranslates S3 API calls to Filer operations, enforces SigV4 auth
MasterCluster topology and volume assignment
FilerObject metadata, directory tree, bucket configuration
Volume serversDurable object data storage (Haystack-style needle storage)

Credentials

Hanzo S3 authenticates with an access key + secret key using AWS Signature V4 — exactly like Amazon S3. Each identity is granted a set of actions (Admin, Read, Write, List, Tagging), optionally scoped to specific buckets.

Store your S3 credentials in Hanzo KMS and inject them at runtime — never hard-code them:

# Pull credentials from KMS (machine-identity auth), then use any S3 client
export AWS_ACCESS_KEY_ID=$(hanzo kms secret get --env prod --path /s3 ACCESS_KEY)
export AWS_SECRET_ACCESS_KEY=$(hanzo kms secret get --env prod --path /s3 SECRET_KEY)

In Kubernetes, sync the keys into a Secret with a KMSSecret CRD instead of embedding them in manifests.

Quick Start

Any S3 client works. The examples below use the host s3.hanzo.ai with credentials from the environment.

MinIO Client (mc)

mc alias set hanzo https://s3.hanzo.ai "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY"

mc mb hanzo/my-models                       # create a bucket
mc cp ./model.safetensors hanzo/my-models/  # upload
mc ls hanzo/my-models/                       # list
mc cp hanzo/my-models/model.safetensors ./  # download
mc mirror ./training-data/ hanzo/datasets/  # recursive sync

AWS CLI

The AWS CLI works against Hanzo S3 with --endpoint-url. Set any region (it is not used for routing).

aws --endpoint-url https://s3.hanzo.ai --region us-east-1 s3 mb s3://my-models
aws --endpoint-url https://s3.hanzo.ai --region us-east-1 s3 cp ./model.safetensors s3://my-models/
aws --endpoint-url https://s3.hanzo.ai --region us-east-1 s3 ls s3://my-models/
aws --endpoint-url https://s3.hanzo.ai --region us-east-1 s3 sync ./run-042/ s3://datasets/run-042/

Python (boto3)

import boto3
from datetime import timedelta

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.hanzo.ai",
    aws_access_key_id=os.environ["AWS_ACCESS_KEY_ID"],
    aws_secret_access_key=os.environ["AWS_SECRET_ACCESS_KEY"],
    region_name="us-east-1",
)

# Create a bucket and upload
s3.create_bucket(Bucket="my-models")
s3.upload_file("model.safetensors", "my-models", "v1/model.safetensors")

# List objects
for obj in s3.list_objects_v2(Bucket="my-models", Prefix="v1/").get("Contents", []):
    print(obj["Key"], obj["Size"])

# Presigned download URL (1 hour)
url = s3.generate_presigned_url(
    "get_object",
    Params={"Bucket": "my-models", "Key": "v1/model.safetensors"},
    ExpiresIn=3600,
)
print(url)

JavaScript / TypeScript (@aws-sdk/client-s3)

import { S3Client, PutObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3'
import { readFileSync } from 'node:fs'

const client = new S3Client({
  endpoint: 'https://s3.hanzo.ai',
  region: 'us-east-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
  },
  forcePathStyle: true,
})

await client.send(new PutObjectCommand({
  Bucket: 'my-models',
  Key: 'v1/model.safetensors',
  Body: readFileSync('model.safetensors'),
}))

const out = await client.send(new ListObjectsV2Command({ Bucket: 'my-models', Prefix: 'v1/' }))
for (const obj of out.Contents ?? []) console.log(obj.Key, obj.Size)

Multipart Uploads

Large objects upload in parts. High-level SDK helpers (aws s3 cp, boto3 upload_file, mc cp) use multipart automatically. To drive it explicitly:

# The AWS CLI automatically switches to multipart above the threshold
aws --endpoint-url https://s3.hanzo.ai s3 cp ./checkpoint-70b.safetensors s3://my-models/ \
  --expected-size 140000000000

The underlying operations — CreateMultipartUpload, UploadPart, CompleteMultipartUpload, AbortMultipartUpload, ListParts, ListMultipartUploads — are all available via the S3 API for clients that manage parts directly.

Bucket Policies

Hanzo S3 supports standard S3 policy documents via PutBucketPolicy:

aws --endpoint-url https://s3.hanzo.ai s3api put-bucket-policy \
  --bucket public-assets \
  --policy file://policy.json

Public read-only (policy.json):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::public-assets/*"]
    }
  ]
}

Versioning

# Enable versioning
aws --endpoint-url https://s3.hanzo.ai s3api put-bucket-versioning \
  --bucket my-models --versioning-configuration Status=Enabled

# List versions
aws --endpoint-url https://s3.hanzo.ai s3api list-object-versions --bucket my-models

# Get a specific version
aws --endpoint-url https://s3.hanzo.ai s3api get-object \
  --bucket my-models --key v1/model.safetensors --version-id "<id>" restored.safetensors

Encryption

All data is encrypted at rest. Choose the key management model per bucket:

MethodDescription
SSE-S3Server-managed keys (default)
SSE-KMSKeys managed by Hanzo KMS (kms.hanzo.ai)
aws --endpoint-url https://s3.hanzo.ai s3api put-bucket-encryption \
  --bucket sensitive-data \
  --server-side-encryption-configuration '{
    "Rules": [{ "ApplyServerSideEncryptionByDefault": { "SSEAlgorithm": "aws:kms" } }]
  }'

Object Lock & Lifecycle

# Lifecycle: expire objects after 90 days
aws --endpoint-url https://s3.hanzo.ai s3api put-bucket-lifecycle-configuration \
  --bucket logs --lifecycle-configuration file://lifecycle.json

# Object Lock retention (WORM) is set at bucket creation and per-object
aws --endpoint-url https://s3.hanzo.ai s3api put-object-retention \
  --bucket archives --key 2026/report.pdf \
  --retention '{ "Mode": "COMPLIANCE", "RetainUntilDate": "2027-01-01T00:00:00Z" }'

Console

The Hanzo S3 web admin console is available at s3.hanzo.ai. It provides a file browser, bucket management, and cluster status. The console is protected by an administrator login configured at deployment.

For day-to-day object operations, use the S3 API (CLI/SDK) rather than the console.

Self-Hosting

Run a standalone Hanzo S3 server (SeaweedFS in S3 mode):

# Single-node server with the S3 gateway enabled
docker run -p 8333:8333 -p 8888:8888 -p 9333:9333 \
  -v /data:/data \
  ghcr.io/hanzoai/s3:latest \
  server -dir=/data -s3 -filer
PortService
8333S3 API gateway
8888Filer (metadata + web UI)
9333Master (topology)
8080Volume server
23646Web admin console

Provide credentials with an identity config file (-config) or the AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY environment variables. The public hostnames s3.hanzo.ai are wired at the ingress layer (-domainName / S3_EXTERNAL_URL), not baked into the binary.

SDK Compatibility

Hanzo S3 has no bespoke SDK — and needs none. Every standard AWS S3 SDK works by setting the endpoint to https://s3.hanzo.ai:

LanguagePackage
Pythonboto3, aioboto3
JavaScript / TypeScript@aws-sdk/client-s3
Gogithub.com/aws/aws-sdk-go-v2
Javasoftware.amazon.awssdk:s3
Rustaws-sdk-s3
CLIaws, mc (MinIO Client), rclone

Key management for SSE-KMS encryption and S3 credential storage

Backend-as-a-service that uses Hanzo S3 for file storage

Identity provider for advanced OIDC-based S3 access

Deploy and operate Hanzo S3 on your clusters

How is this guide?

Last updated on

On this page