Skip to content

CONNECT AN API · AMAZON S3 · 5 MINUTES

Connect an S3 bucket

S3 gives your agent four operations on exactly one bucket: list the keys, read an object, write an object, and delete an object. The AWS credential is signed into every request by the gate and never leaves your machine.

This page is for whoever owns the bucket an agent will work in.

The part worth knowing before you start: the bucket name becomes part of the hostname, so a connection physically cannot reach a second bucket. It is not a check that could be misconfigured. There is nowhere to put another bucket name.

A folder of objects your agent can read and add to is the simplest durable memory an agent can have. One bucket, one connection, one grant, and a receipt for every object it touches.


What you need

An access key pair for an IAM identity that can reach the bucket, and the bucket's region. Give that identity the narrowest policy that covers the four operations on that one bucket, because EKKA bounds which bucket the connection reaches and AWS bounds what the key itself can do.

Step 1 · Connect it on this machine

ekka api connect s3 --input bucket=acme-agent-memory --input region=eu-central-1

It asks for the credential at a prompt. Paste the key pair joined by a colon:

accessKeyId:secretAccessKey

For a temporary credential, append the session token as a third value: accessKeyId:secretAccessKey:sessionToken.

The credential is read from a prompt and never from an argument, because an argument lands in your shell history and in the process list where any other user on the machine can read it. For a script, --stdin reads it from standard input and is still never an argument.

Get the region right

The region is part of the address, and the gate never follows a redirect. If the region does not match where the bucket actually lives, the call fails and S3 names the correct endpoint in its answer. Set it to that and reconnect.

Step 2 · Let an agent use it

connect prints this with your values already filled in:

ekka gate grant add --type api --resource apis/s3-acme-agent-memory \
  --capability api.read --no-fingerprint

The bucket is in the resource name. A grant on apis/s3-acme-agent-memory says this agent may reach that bucket and no other, so two buckets are two connections and two grants that can be revoked separately.

api.read covers listObjects and getObject. Add a second grant with api.write for putObject and deleteObject.

Until you run this, nothing can touch the bucket. Connecting and permitting are two separate decisions, so a connection sitting on a machine is not access.

Step 3 · Check it works

ekka api test s3

It checks the config it will use, whether the credential is in the vault, and whether a grant allows the operation.

There is no live call for this one, and the output says so rather than implying a pass. AWS has no endpoint that says "this key is valid" without also doing something, so the honest answer is that the credential is verified the first time a plan uses it. For Slack, Sentry, Jira and Gmail the live row is a real call.


What a plan can do

Four operations. See the exact fields with ekka api spec s3.

Call What it does Needs
listObjects list the keys in the bucket nothing. prefix is optional
getObject read one object key
putObject write one object key, body
deleteObject delete one object key

List what is already there:

{ "id": "existing", "action_ref": "ekka.gate.api.v1",
  "target": "<your api gate>", "op": "read", "call": "listObjects",
  "inputs": { "resource": "apis/s3-acme-agent-memory",
              "prefix": "notes/2026-08/" } }

Write a note the next run will find:

{ "id": "remember", "action_ref": "ekka.gate.api.v1",
  "target": "<your api gate>", "op": "write", "call": "putObject",
  "inputs": { "resource": "apis/s3-acme-agent-memory",
              "key": "notes/2026-08/summary.json",
              "body": "@op.summarize.output" } }

A value may be @input.<name> to take it from the run, or @op.<id>.output to take it from an earlier step. The target is your Enclave's api gate, and ekka gate list names it.

Limits

Consequences of how the gate works, rather than of S3.

  • Object keys are ASCII, without a space, %, + or any non-ASCII character. The gate canonicalizes the request path and refuses anything whose canonical form differs from what goes on the wire, so such a key is unreachable rather than quietly wrong.
  • A body travels as text. An object body is sent as JSON, and a string verbatim. Binary uploads are not expressible.
  • The gate sets the Content-Type it signed, so an uploaded object cannot carry a type of your choosing.
  • Responses are capped, and a capped read is marked truncated in the receipt. A large object is not a download.
  • No caller-supplied x-amz-* headers. Server-side encryption headers, ACLs and storage class are set as bucket policy or defaults, not per request.

S3-compatible stores such as MinIO and R2 are a separate catalog row. The gate can reach them, and Add your own API is how one gets added.

Turning it off

ekka gate grant list                          # find the grant
ekka gate grant revoke <grant-id>             # the next attempt is refused, live
ekka api disconnect s3                        # remove the connection from this machine

Revoking the grant stops the agent. Disconnecting removes the credential from this machine's vault. Either is enough on its own, and rotating the key in AWS stops it at the other end.