Prove what the agent read?
Every call, written down first.
A few weeks after an agent was given access to some production data, someone asked a fair question: what did it actually read? The honest answer, after a morning of looking, was that we didn't know.
Today
The cloud keeps access logs for storage. On one of the clouds they had to be switched on per bucket, and they hadn't been. On the other they were on, and I queried them in the console's log explorer. They arrive with a delay, and what they record is a request: this principal read this object at this time.
That is a lot less than the question. It told me the agent's key had touched a set of objects. It didn't say which question it had been answering, how many rows it took out of each file, or what it sent back to the person who asked it. A log line that says a door was opened is not the same as knowing what came through it.
- Cloud consolefind access logs
- Cloud consolelogs were off
- Log queryprincipal read prefix
- Meetingwe don't know
The logs did what they were built for, which is auditing access to storage. Nobody did anything wrong. The shared assumption was that the record of what an agent read can be reconstructed afterwards, from the outside, by the storage.
Ideal
So I asked who actually knows what the agent read. Not the storage. The storage saw requests for bytes. The thing that knew was whatever stood between the agent and the data at the moment it answered. It saw the question. It decided whether the rules allowed it, and which rule. It picked the rows. It measured the answer. At that moment it knew everything the auditor would later want, and in most setups it then threw it away.
So write it down there, at that moment, and before the answer leaves. The order matters. If the record is written after the answer is sent, a crash between the two leaves an answer with no record, which is the one case an audit is for. Written first, the worst case is a record of an answer that never arrived.
And write down what was decided, not what was sent. The rows themselves shouldn't go into the log, or the log becomes a second copy of exactly the data the rules were protecting.

That is the list of sessions, and each one opens to its calls, one by one. In the code every call, allowed or denied, is appended to a file for that agent and that session before the answer is handed back, and the append is synchronous, so a process that is killed still has everything it answered. Each record holds the time, the tool, the arguments, the object, the decision, the step and rule that decided it, how many rows and bytes the answer held, and how long it took. The rows themselves are never stored. There is a setting for how long records are kept, 30 days by default, but nothing deletes an old session file yet, so today they stay until I remove them.
Where it stops
This covers what an agent read through this door. If the same agent also holds a key of its own, what it reads with that key is back to the storage's logs. The record is only complete if the door is the only way in, and nothing in the app can enforce that on its own.
The files also live on the machine running the app. That is fine for one person asking what their agent did. An organisation that wants these records in one central place will have to ship them there, and I haven't built that part.
Every call, written down first.