Attestkeep docs

SIEM export

Your SOC watches the SIEM, not this console. SIEM export sends Attestkeep's security events there as they happen — refused admissions, deny-list hits, runtime events, policy and triage changes, evidence downloads, failed sign-ins — so they sit on the same timeline as everything else you collect.

Destinations are set up in the console, Settings › SIEM export. Everyone who signs in can see them and how each one is doing; adding, changing, testing and removing one is an administrator's.

Nothing leaves unless you add a destination. Events go only where you point them, from your cluster to your SIEM. Without a destination nothing is exported, and adding one changes no admission decision.

The event

Every event is one JSON object, schema attestkeep.event/v1. Each is a record the console already shows, and carries a reference to it.

FieldMeaning
timeWhen it happened, RFC 3339 UTC with milliseconds. For a runtime event, when the detector saw it. Always present.
typeOne of the types below. Always present.
severityinfo, low, medium, high or critical. Always present.
clusterThe chart's clusterName. Always present.
namespace, podWhere it happened; empty for a cluster-wide event such as a policy change.
workload_kind, workload_nameThe workload an admission was counted against: the Deployment above a Deployment's ReplicaSet, the CronJob above a Job, Pod for a pod nobody owns.
image, digestThe image reference and its digest.
policyThe policy that decided an admission, the runtime rule that decided a Falco event, or the policy a change was made to.
actorWho: the console account's name as the audit log shows it, or the Kubernetes username as the admission ledger holds it; a runtime policy is policy:<rule>. A destination set to pseudonymous actor names gets user:<account id> and, for a Kubernetes username that is not a system: identity, k8s-user:<first 16 hex characters of its SHA-256>, as in the evidence package; a record written before account ids were kept reads user:unresolved.
outcomedenied, allowed, warned, success, failure, stopped, taken_down, blocked, pending, restored, found, expired, or a runtime rule's action.
reasonThe sentence Attestkeep recorded, at most 1,000 characters.
referenceThe record it came from, kind:id. Unique per event and the same when an event is sent again: drop duplicates by it. Always present.
schemaattestkeep.event/v1. Always present.

An event never carries an SBOM, a list of findings, a credential, licence data, or what was typed in a failed sign-in.

Event types

TypeWhenSeverity
admission.deniedA pod was refused.high
admission.allowedA pod was admitted. Off unless you tick it: it is most of the ledger.info
admission.break_glassA pod was admitted under an open break-glass.high
denylist.deniedA deny-list entry matched a pod: denied where the policy enforces the list, warned (medium) where it audits it.high
denylist.entry_added, denylist.entry_removedAn entry was added or lifted.medium
denylist.whatif_runSomebody ran What if for a deny-list entry.info
denylist.takedownAn administrator took down a workload a deny-list entry catches. Outcome taken_down, blocked (a PodDisruptionBudget kept the pods), failed, or pending. A refused request (the chart key off, no admin role, a namespace admission does not review, a changed replica count) is not sent.high
denylist.restoredA workload scaled to zero by a take down was put back. A refused restore is not sent.medium
scan.finding_newA scan reports a CRITICAL finding.critical
scan.kevA scan first sees a finding on CISA's Known Exploited Vulnerabilities list, on the image's first scan or a later one.critical
runtime.eventYour Falco reported an event (severity from its priority).info to critical
runtime.pod_stoppedA runtime policy stopped a pod.high
policy.changedA policy was created, changed or deleted, or break-glass was closed.medium
policy.break_glass_openedBreak-glass was opened.high
triage.decided, triage.expiredA finding was triaged or a triage withdrawn; an accepted risk lapsed.low
evidence.generated, evidence.downloadedAn evidence package was generated or downloaded.info
auth.login_failed, auth.role_changedA sign-in failed; a user's role changed.medium

A change the server refused is sent too, with outcome failure: an attempt to change a control is worth seeing.

Findings are sent once, when first seen. Attestkeep records the first scan that reported each finding of an image (digest, advisory, package and version). scan.finding_new is sent for that scan only; a rescan that reports the same finding sends nothing. scan.kev is sent once, by the first scan that sees the finding on the KEV list — often a later scan, since a CVE usually joins the list after the image was scanned. Findings that existed before 1.4.0 count as already seen.

Example

{"time":"2026-10-25T09:30:00.123Z","type":"admission.denied","severity":"high",
 "cluster":"prod-eu-1","namespace":"prod","pod":"api-7c9f5-x2k",
 "workload_kind":"Deployment","workload_name":"api",
 "image":"ghcr.io/acme/api:1.24.3","digest":"sha256:9f2a…","policy":"baseline",
 "actor":"system:serviceaccount:kube-system:replicaset-controller","outcome":"denied",
 "reason":"denied by deny list entry 30: digest sha256:9f2a…",
 "reference":"admission:812","schema":"attestkeep.event/v1"}

What each destination sends

DestinationForHow
HTTP (JSON)Google SecOps, Sumo Logic, Exabeam, any HTTP collectorAn HTTPS POST per batch: a JSON array, or one event per line. Optional gzip, two optional request headers for the collector's key, and an optional HMAC signature.
Splunk HECSplunk; CrowdStrike Falcon LogScaleHEC events with time, host (the cluster), source attestkeep, sourcetype attestkeep:event and an optional index.
SyslogQRadar, ArcSight, Wazuh, Graylog, Securonix, LogsignRFC 5424 over TLS (plain TCP for a receiver without TLS), with a CEF, LEEF or JSON body.
ElasticsearchElastic SecurityThe bulk API into an index or data stream, with an API key. Every document carries @timestamp.
Microsoft SentinelMicrosoft SentinelThe Logs Ingestion API through a data collection rule, with an Entra application.

Every destination must be reachable from the operator. Loopback and link-local addresses — the cloud metadata service among them — are refused; addresses inside your cluster and network are allowed. HTTP destinations must use https://; a receiver with a certificate from your own CA takes that CA in the form, added to the system roots. A redirect is followed only to the same scheme and host, at most three times, and never to a loopback or link-local address. Tokens, keys and secrets are stored encrypted with the installation's data key and never shown again: leave a field empty to keep it, or choose Replace.

Changing where a destination points removes its credentials. When an edit changes the URL, the endpoint, the syslog receiver, or for Sentinel the tenant, rule or stream, the stored token, key or secret is removed, so it is never sent to the new place unless you enter it there. The destination then reads Credentials required and sends nothing until they are entered; the audit log records which fields changed and the old and new host.

The HMAC signature, when you set a secret, is the header X-Attestkeep-Signature: sha256=<hex>: HMAC-SHA256 of the request body exactly as sent (after gzip when gzip is on). Compute it over the bytes you received.

Setting up your SIEM

Splunk

Enable HTTP Event Collector (Splunk Enterprise: Settings › Data Inputs › HTTP Event Collector › Global Settings; it is on by default on Splunk Cloud Platform) and create a token with the index it may write to. In Attestkeep: Splunk HEC, the endpoint https://<splunk>:8088/services/collector/event, the token, sent as Splunk. Search with sourcetype="attestkeep:event". Splunk's reference: Format events for HTTP Event Collector.

CrowdStrike Falcon LogScale

Create an ingest token for the repository. In Attestkeep: Splunk HEC, the endpoint https://<logscale>/api/v1/ingest/hec, the token, sent as Bearer. The event arrives as a JSON object, so its fields are searchable without a parser. Reference: Ingesting with HTTP Event Collector.

Microsoft Sentinel

Create a custom table Attestkeep_CL and a data collection rule whose stream (for example Custom-Attestkeep_CL) declares these columns: TimeGenerated (datetime) and, as strings, event_type, time, severity, cluster, namespace, pod, workload_kind, workload_name, image, digest, policy, actor, outcome, reason, reference, schema, with the transformation source. Register an Entra application with a client secret and give it the Monitoring Metrics Publisher role on the DCR. In Attestkeep: Microsoft Sentinel, the DCR's logs ingestion endpoint (or the data collection endpoint), the DCR's immutable id, the stream, the tenant id, the client id and the client secret. The event's type is sent as event_type because Type is a reserved column name. The Azure public cloud is supported. Reference: Logs Ingestion API in Azure Monitor.

IBM QRadar

Add a log source that receives syslog over TLS (not verified against IBM's documentation; confirm the log source setup on your side). In Attestkeep: Syslog, the receiver's host:port, body LEEF. Events arrive as LEEF:1.0|Attestkeep|Attestkeep|<version>|<type>| with tab-separated attributes: devTime (epoch milliseconds), sev (1–10), cat (the type), usrName (the actor), policy, and cluster, namespace, pod, workloadKind, workloadName, image, digest, outcome, reason, reference. IBM's guide defines no escaping for attribute values; Attestkeep writes a tab, CR or LF inside a value as a space (not verified against QRadar; confirm on your side). Reference: IBM's Log Event Extended Format (LEEF) guide.

ArcSight, Logsign, Securonix, Graylog

A syslog receiver over TLS. In Attestkeep: Syslog, body CEF. Events arrive as CEF:0|Attestkeep|Attestkeep|<version>|<type>|<name>|<severity 0–10>| with rt, cat, outcome, reason, suser, deviceExternalId (the cluster), flexString1 (the workload) and cs1–cs6 labelled namespace, pod, image, digest, policy and reference. Reference: Implementing ArcSight Common Event Format.

Wazuh

Add a syslog listener to the manager's ossec.conf, with the operator's address in allowed-ips:

<remote>
  <connection>syslog</connection>
  <port>514</port>
  <protocol>tcp</protocol>
  <allowed-ips>10.0.0.0/8</allowed-ips>
</remote>

The listener does not speak TLS, so in Attestkeep choose Syslog, Plain TCP on, framing one message per line, body JSON: Wazuh's JSON decoder reads the event's fields. Use it inside your own network only. Wazuh's documentation does not state the TCP framing it expects; one message per line is our choice for a line reader, not verified against Wazuh — if events do not arrive, check the framing first. Reference: Wazuh syslog collection.

Without a destination, a Wazuh agent on the nodes can also read the operator pods' container log files, where each line is an attestkeep.log/v1 JSON object behind the container runtime's own prefix. Wazuh's JSON decoder skips such a prefix with offset="after_prematch" (JSON decoder); test a line from your nodes with wazuh-logtest before writing rules.

Elastic Security

Create an API key with create_doc (or create, index, write) on the target, and auto_configure or create_index if the index or data stream should be created on the first write; a data stream needs a matching index template. In Attestkeep: Elasticsearch, the cluster's base URL, the key's encoded value, and the index or data stream (default attestkeep-events). Reference: Bulk API.

Google SecOps

Create a webhook feed (Settings › Feeds › Add new, source type Webhook, split delimiter \n), generate its secret key, and create an API key. In Attestkeep: HTTP (JSON), the feed URL, body one event per line, header 1 X-goog-api-key with the API key, header 2 X-Webhook-Access-Key with the feed's secret. Reference: Set up a SIEM webhook.

Sumo Logic

Create an HTTP Logs and Metrics source. In Attestkeep: HTTP (JSON), body one event per line, gzip on, and either the source URL or the base URL with header x-sumo-token. The source URL carries its own access code; the token header keeps it out of the address. Reference: Upload logs to an HTTP source.

Exabeam

Create a Webhook Cloud Collector in JSON mode. In Attestkeep: HTTP (JSON), the collector's …/cloud-collectors/v1/logs/json URL, body JSON array, header Authorization with Bearer <token>. Reference: Exabeam's Webhook Cloud Collector.

What is sent, per destination

Test sends one event of type test through the destination as it is saved, whatever its filters and even when it is disabled, and shows the answer.

Delivery

Metrics: attestkeep_siem_events_total{target,outcome} with outcome delivered, failed or gave_up, and attestkeep_siem_lag_seconds{target}, the age of the oldest event a destination has not received. target is the destination's id.

Without a destination: OpenTelemetry

The operator's own logs (attestkeep.log/v1), traces and metrics can go to an OpenTelemetry collector with observability.otlp.endpoint (see Configuration), and from there to any SIEM the collector exports to. That stream is the operator's log, not the event schema above: the same decisions, written as log fields.

Configuration bundle

Settings › Backup exports SIEM destinations with the rest of the configuration, without their credentials and disabled. An HTTP (JSON) destination's URL is exported as scheme and host only, since the rest of it can be the collector's key; after an import, enter the full URL again. An import adds the ones not yet present, disabled; those that need a credential read Credentials required until it is entered. See backup and restore.

Who can do what

Every role that signs in can read the destinations and their status. Adding, changing, testing and removing one are administrator actions, filed in the audit log as siem_target_add, siem_target_update, siem_target_test and siem_target_remove.

GET    /api/v1/siem/targets
POST   /api/v1/siem/targets              {"kind":"splunkhec","name":"SOC Splunk","config":{"url":"https://…/services/collector/event","token":"…"},"types":[],"namespaces":[],"min_severity":"info","backfill_24h":true}
PUT    /api/v1/siem/targets/{id}         fields to change; config keys merge one by one (a key left out is kept, null clears it); an empty credential keeps the stored one, "clear_secrets":["hmac_secret"] drops one
DELETE /api/v1/siem/targets/{id}
POST   /api/v1/siem/targets/{id}/test

A field the server refuses comes back as 400 with {"error":"<field>: …","field":"<field>"}; a test the destination refused is 502 with its own words.