Skip to main content
S3 support has three moving parts: the gateway’s S3 listener, the operator’s credential admin API, and the on-chain delegation from each bucket tape to the gateway’s key. This page walks all three. The first two are for gateway operators; the last one is the single step every bucket owner performs.

Gateway side: enabling the S3 listener

The S3 listener is off by default and binds its own address, separate from the read API. The gateway also needs a delegate keypair: the key that tapes delegate writes to.
Write handling depends on how the client sends the payload. Signed-hash uploads are buffered in memory (up to max_buffered_bytes) and verified before anything lands; declared-size, chunked, and unsigned payloads stream with bounded memory, up to max_object_bytes.

Operator side: credentials and policy

Credentials are managed through an admin API on a separate, operator-token-authenticated listener. It issues and revokes SigV4 credentials. A credential is scoped to specific buckets or to the principal’s own tape. Rules are default-deny, and an explicit deny always wins. The same API sets per-principal budgets and carries an emergency kill switch for all writes. Every authorization decision is logged.
The admin listener binds to gateway.s3.write.admin.listen (default 127.0.0.1:3451, loopback only) and every request must carry Authorization: Bearer <token> matching gateway.s3.write.admin.operator_token. With no token configured, the admin API refuses all requests. Routes: /credentials (create, list; DELETE /credentials/{access_key_id} revokes, PUT .../grade assigns a metering grade), /policy/rules (create, list; delete by /{priority}/{id}), /kill-switch, /budgets, and /ledger/{principal} (usage; PUT/DELETE .../budget overrides a principal’s budget).

Tape side: delegating writes

One on-chain step, performed by the bucket owner: point the tape’s delegate at the gateway’s key. From then on the gateway can register, certify, and delete tracks on your behalf without ever holding your tape keypair (how delegation works). The gateway publishes the key at GET /v1/s3, and tape delegate <address> sets it from the CLI (set up a bucket). From code:
Rust
revoke_tape_delegate removes the delegate again (managing tapes). The failure you’ll actually see when this step is missing: an S3 write returns 403 AccessDenied with a message saying the bucket tape has not delegated writes to this gateway.

How a write gets approved

When an S3 write arrives, the gateway runs six checks in order. If any check fails, the write is refused. Nothing passes by default.
  1. Is writing enabled at all? The kill switch stops every write on the gateway when the operator flips it.
  2. Is this credential in good standing? It must be active, not revoked, and inside its size and rate caps.
  3. May this credential touch this bucket? Each credential is scoped to specific buckets, or to the principal’s own tape.
  4. Do the operator’s rules allow it? Anything not explicitly allowed is refused, and an explicit deny beats any allow.
  5. Does the chain agree? The bucket’s tape must have delegated writes to this gateway’s key, must not be expired, and must have capacity left.
  6. Is there budget left? The write’s bytes are counted against the credential’s budget.
Five of these are the operator’s own settings. Check 5 is not: it belongs to the protocol, so a gateway can never write to a tape that hasn’t opted in, no matter how the gateway itself is configured.