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¶
It asks for the credential at a prompt. Paste the key pair joined by a colon:
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¶
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-Typeit 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.