Skip to content

Audit and retention

Every request that goes through the proxy leaves a row, and every control-plane action leaves an event. Here's how to search them in Auditoría (Audit), how to cross-reference them with the cluster's native audit log, and how long they're kept.

Search cluster requests

  1. Open Auditoría. The Peticiones a los clusters (Requests to clusters) tab is selected.
  2. Fill in the filters you need:

    Filter What it narrows
    Sujeto (Subject) A person or a bot.
    Cluster A cluster.
    Namespace An exact namespace.
    Verbo (Verb) get, list, watch, create, update, patch, delete, deletecollection, or proxy.
    Recurso (Resource) For example pods or secrets.
    Credencial (id) (Credential (id)) The id of a credential (you can see it in Credenciales (Credentials)).
    Periodo (Period) Última hora (Last hour), Últimas 24 h (Last 24 h), Últimos 7 días (Last 7 days), or Últimos 30 días (Last 30 days). Takes priority over Desde (From) and Hasta (To).
    Desde / Hasta A date range.
    Incluir descubrimiento (Include discovery) Also shows rows with no resource.
  3. Click Buscar (Search). Results come 50 at a time, most recent first.

By default, rows with no resource are hidden: discovery (/api, /apis, /version, /openapi), which kubectl does on every command, and also the requests kubelatch rejects before they reach the cluster. Those include authentication failures (no token, unknown, revoked, or expired token, the 401) and the 403s for a disabled account, a credential for another cluster, or no permissions. To see them, check Incluir descubrimiento.

Rows for a 401 have no subject or credential, only the token's prefix: they don't show up if you filter by Sujeto or Credencial (id), and the person who owns the token doesn't see them in their Mi actividad (My activity). Search by date and cluster instead.

A person without the admin role sees their own rows in Inicio (Home): My activity.

What's in each row

The table shows date, subject, cluster, action, resource, status, and duration. Click a row to see the Detalle de la petición (Request detail):

Field What it is
Audit-ID The row's id. It's the same one the cluster receives.
Credencial (Credential) The id and the klt_… prefix. On an authentication failure, only the prefix with (rechazada) (rejected).
Petición (Request) Method, path, and query string. On an exec, the query carries command=: what the person typed.
Verbo / grupo / versión (Verb / group / version) How Kubernetes interprets it.
Grupos suplantados (Impersonated groups) The kubelatch:… groups the proxy used to act on the subject's behalf.
IP de origen (Source IP), User-Agent Where it came from. Behind an Ingress this depends on KUBELATCH_TRUSTED_PROXIES (Install).
Stream (upgrade) Whether it was an SPDY or WebSocket upgrade.
Estado (Status), Duración (Duration), Fin (End), Error Filled in once it finishes. An open stream shows en curso (in progress).

Statuses worth recognizing:

  • 499 with cliente desconectado (client disconnected): the client hung up before receiving a response, for example a Ctrl-C.
  • 403 with stream cortado… (stream cut…): a revocation (of a credential, an account, or a permission) cut the stream before the cluster responded. If it was already open, the row keeps its 101 or 200 with that same error.
  • A stream cut by a kubelatch restart ends with the error kubelatch reiniciando (kubelatch restarting).

Authentication failures are logged at most once per IP every 10 s. Proxy policy 400s (paths with .. or %, Impersonate-* headers) don't leave a row, but the response still carries the Audit-ID header.

exec, attach, and port-forward

These are recognized by the subresource, not the verb. kubectl uses get over WebSocket and create over SPDY for the same action. The Acción (Action) column already translates this: exec, attach, port-forward, or logs.

To find them, filter by Recurso pods and look at the Acción column. The Verbo filter doesn't help here.

Cross-reference with the cluster's native audit log

Every proxy response, including errors, carries the Audit-ID header (kubectl -v=8 shows it). It's the row's id and the same auditID the API server writes to its own audit log.

  1. Copy the Audit-ID from the row's detail.
  2. Look it up in your provider's native audit log (CloudWatch on EKS, Cloud Logging on GKE, Azure Monitor on AKS) or in the API server's audit log file.

Keep the provider's native audit log turned on. Anything done with a ServiceAccount token obtained from within a pod doesn't go through kubelatch and is only recorded there.

The control plane

The Plano de control (Control plane) tab lists every administration action and every login attempt: date, actor, action, target, IP, and details. Actions with no actor (the CLI, automatic GitHub offboarding, failed attempts with unknown logins) show up as CLI / anónimo (CLI / anonymous).

Common actions: login.success, login.failure (with reason, for example password_disabled), user.create, bot.create, user.disable, user.update, link.reset, link.complete, github.link, github.unlink, user.break_glass, password.set, cluster.create, cluster.tokens, cluster.delete, grant.create, grant.revoke, credential.issue, credential.revoke, ci.trust_rule.create, ci.trust_rule.delete, and ci.exchange.failure.

A useful signal: several login.failure events in a row from the same IP.

Retention

KUBELATCH_AUDIT_RETENTION sets how long requests and control-plane events are kept. It defaults to 90 days (90d). It accepts days (Nd) or a Go duration, with a one-day minimum. 0 or 0d disables deletion.

A periodic job deletes whatever is past retention every hour; the first pass runs one minute after startup. The log says how many rows it deleted (retention: rows deleted) or whether it failed (retention: pass failed).

The same job deletes already-spent CI jtis one hour after their token expires, regardless of the retention setting. With 0, the job doesn't run and only the exchange itself deletes them.

Nobody else can modify or delete rows: see Immutable audit log.

Personal data

Rows store the IP, the login, the User-Agent, and the query string (the command= of each exec). The control plane stores the IP and login of each login attempt. The purpose is security and traceability of cluster access. The retention period is the answer to "how long do you keep this".

If you need to keep more than you want in the database, export to immutable storage before the retention job deletes it: pg_dump -t audit_events -t control_events, or GET /api/audit and GET /api/control-events (HTTP API).

Size

Each request is a row of around 1 KB, and kubectl makes several per command, not counting discovery. As a reference point, 50 active people generate a few hundred MB over 90 days.

To include the audit log in your backups, see Upgrades and backups.