Exec Session Recording
How iddio captures every byte of kubectl exec and attach sessions. Connection hijacking, bidirectional stream recording, and forensic-quality replay — transparent to the agent.
Why Record Exec Sessions
When an AI agent runs kubectl exec -it pod -- /bin/sh, it gets an interactive shell inside a running container. This is a T4 (break-glass) operation for good reason: the agent has direct, unrestricted access to the container’s filesystem, processes, and network.
A one-line audit log entry — “claude-code executed exec on pod api-7d4b8f6c9” — tells you the exec happened, but not what the agent did inside the session. Session recording captures every byte: every command typed, every output returned, every control character sent.
How Exec Works in Kubernetes
kubectl exec uses HTTP protocol upgrade. The initial request is a normal HTTPS request to the Kubernetes API server:
GET /api/v1/namespaces/payments/pods/api-7d4b8f6c9/exec?command=/bin/sh&stdin=true&stdout=true&tty=true
Connection: Upgrade
Upgrade: SPDY/3.1
The API server responds with 101 Switching Protocols, and the connection upgrades to a bidirectional stream. From this point, raw bytes flow in both directions: stdin from the client, stdout/stderr from the container.
Connection Hijacking
Iddio intercepts the upgrade by hijacking the HTTP connection:
func (p *Proxy) handleExec(w http.ResponseWriter, r *http.Request) {
// Classify and enforce — this is T4 break-glass
// ...
// Hijack the client connection
hijacker, _ := w.(http.Hijacker)
clientConn, clientBuf, _ := hijacker.Hijack()
defer clientConn.Close()
// Connect to the real API server
upstreamConn, _ := tls.Dial("tcp", p.clusterURL, p.tlsConfig)
defer upstreamConn.Close()
// Forward the upgrade request
r.Write(upstreamConn)
// Bidirectional stream copy with recording
p.relayWithRecording(clientConn, upstreamConn, clientBuf, session)
}
After hijacking, iddio holds both ends of the connection: the agent’s TCP socket and the upstream cluster’s TCP socket. It relays bytes between them while capturing a copy.
Bidirectional Stream Recording
The recording captures both directions simultaneously:
func (p *Proxy) relayWithRecording(
client, upstream net.Conn,
clientBuf *bufio.ReadWriter,
session *ExecSession,
) {
done := make(chan struct{}, 2)
// Client → Upstream (stdin)
go func() {
defer func() { done <- struct{}{} }()
buf := make([]byte, 32*1024)
for {
n, err := clientBuf.Read(buf)
if n > 0 {
session.RecordStdin(buf[:n])
upstream.Write(buf[:n])
}
if err != nil { return }
}
}()
// Upstream → Client (stdout/stderr)
go func() {
defer func() { done <- struct{}{} }()
buf := make([]byte, 32*1024)
for {
n, err := upstream.Read(buf)
if n > 0 {
session.RecordStdout(buf[:n])
client.Write(buf[:n])
}
if err != nil { return }
}
}()
<-done
}
The recording tees every byte without modifying the stream. The agent and the container communicate normally — the recording is completely transparent.
Session File Format
Each exec session is saved as a JSONL file with timestamped entries:
{"t": "2026-02-09T10:15:30.001Z", "d": "stdin", "b": "bHMgLWxhCg=="}
{"t": "2026-02-09T10:15:30.050Z", "d": "stdout", "b": "dG90YWwgMjQK..."}
{"t": "2026-02-09T10:15:31.200Z", "d": "stdin", "b": "Y2F0IC9ldGMvcGFzc3dk"}
{"t": "2026-02-09T10:15:31.250Z", "d": "stdout", "b": "cm9vdDp4OjA6..."}
t— timestamp with millisecond precisiond— direction:stdinorstdoutb— base64-encoded raw bytes
Base64 encoding preserves control characters, terminal escape sequences, and binary data without JSON escaping issues.
Forensic Replay
The iddio session replay command replays a recorded session in real-time (or at configurable speed):
iddio session replay --id exec_a1b2c3 --speed 2x
This reconstructs the terminal output exactly as it appeared during the original session, including colors, cursor movement, and timing. It’s forensic-quality: an auditor can see exactly what the agent did and what the container returned.
Audit Log Integration
Each exec session generates an audit event that links to the session recording:
{
"timestamp": "2026-02-09T10:15:30Z",
"agent": "claude-code",
"method": "GET",
"path": "/api/v1/namespaces/payments/pods/api-7d4b8f6c9/exec",
"tier": 4,
"decision": "allow",
"session_type": "exec",
"session_id": "exec_a1b2c3",
"session_file": "~/.iddio/sessions/exec_a1b2c3.jsonl",
"hash": "a3f8c2...",
"prev_hash": "9e8d7c..."
}
The session file reference lets you jump from the audit log entry directly to the full recording.
Try It Yourself
Iddio is open source. Deploy a zero-trust command proxy for your AI agents in minutes.