---
name: azion-stream-request-and-waf-records-to-a-siem
description: >-
  Send every request to an application, with the WAF fields of the same request, to a SIEM in one log line, and confirm the delivery.
---

# Stream request and WAF records to a SIEM

You send every request to an application, with the WAF fields of the same request, to a security information and event management (SIEM) platform from Azion Console or the Azion API. To send only the requests WAF analyzed, refer to [Stream WAF events to a SIEM](/en/documentation/guides/application-security/firewall-and-waf/integrate-siems/).

A [Data Stream](/en/documentation/platform/data-stream/) stream on the *Applications* data source, shaped by the *Applications + WAF Event Collector* preset, carries the request, the response, and the client address with the WAF score, matches, and block flag of the same request. One log line then answers a question about one request, whether WAF flagged it or not. The cost is volume: the preset sends 51 keys, the most of the five presets, and Data Stream is billed on requests and data transfer.

```mermaid
%%{init: {"layout": "dagre", "themeVariables": {"fontSize": "13px"}, "flowchart": {"nodeSpacing": 12, "rankSpacing": 12, "padding": 6, "wrappingWidth": 70, "minNodeWidth": 40, "useMaxWidth": true}}}%%
flowchart TD
  Req["A request reaches the workload"] --> Source["Applications data source"]
  Source --> Filter["Workload filter: only the chosen workloads"]
  Filter --> Template["Template 184: request and WAF fields in one line"]
  Template --> Out["Connector: the SIEM's endpoint"]
  Out --> Siem["SIEM"]
  Out --> Rte["Real-Time Events records each send and its status"]
```

1. Each request to a chosen workload becomes an event of the *Applications* data source.
2. The workload filter keeps only the workloads you choose, and leaves the account's other streams active.
3. Template `184` renders each event as one log line with the request fields and the WAF fields.
4. The stream sends the lines to the SIEM's endpoint in batches, and Real-Time Events records each send with the status the endpoint returned.

---

## Prerequisites

- An account user with the **Edit Data Stream** permission. For the permissions, refer to [Stream settings](/en/documentation/platform/data-stream/stream-settings/#permissions).
- A workload whose firewall applies a WAF rule set with a *Set WAF* rule. To build it, refer to [Apply a rule set to every request](/en/documentation/guides/application-security/firewall-and-waf/apply-rule-set/).
- An endpoint that your SIEM reads. The examples use an Apache Kafka cluster, with the host and port of its servers and one topic. For the other endpoints, refer to [Endpoints](/en/documentation/platform/data-stream/endpoints/).
- A [personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/) and the ID of the workload, for the API procedure.
- Access to Azion Console, for the Console procedure. Refer to [Access Azion Console](/en/documentation/guides/platform/account-and-billing/how-to-access-azion-console/).

The examples send the requests of the workload `<workload-id>` to the topic `azion.requests` on `kafka1.example.com:9092` and `kafka2.example.com:9092`. Replace them with your workload and endpoint.

---

## Create the stream

The stream takes its scope from a workload filter rather than sampling. A stream carries exactly one of the two, and saving an active stream with sampling, at any rate including `100`, deactivates every other stream on the account with no error. A filter holds up to 600 workloads, and a workload created later is not collected until you add it.

**Console**

To create the stream in Azion Console:

1. **Open Data Stream**

   Access [Azion Console](https://console.azion.com/) > **Data Stream**.

2. **Select + Stream**

3. **Name the stream**

   In the **General** section, enter a **Name**. For example: `requests-to-siem`.

4. **Select the Applications data source**

   In the **Input** section, select *Applications* in **Data Source**.

5. **Turn off Sampling**

   In the **Transform** section, turn off **Sampling** while **Option** is still *All Current and Future Workloads*.

6. **Choose the workload**

   Set **Option** to *Filter Workloads*. In **Available Workload**, select the workload and move it to **Chosen Workload**.

7. **Select the template**

   In the **Render Template** section, select *Applications + WAF Event Collector* in **Template**. The **Data Set** field shows the keys of each log line.

8. **Select the endpoint**

   In the **Output** section, select *Apache Kafka* in **Connector**. Enter `kafka1.example.com:9092,kafka2.example.com:9092` in **Bootstrap Servers** and `azion.requests` in **Kafka Topic**, and turn on **Enable Transport Layer Security (TLS)**.

9. **Keep the stream active**

   In the **Status** section, keep **Active** turned on.

10. **Select Save**

The Console shows `Your data stream has been created`. The stream appears in the **Data Stream** list with `workloads` in the **Source** column.

**API**

To create the stream with the API, send the `workloads` data source, which is *Applications* in the Console, with template `184`:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/stream/streams \
  --header 'Authorization: Token <personal-token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "requests-to-siem",
  "active": true,
  "inputs": [{ "type": "raw_logs", "attributes": { "data_source": "workloads" } }],
  "transform": [
    { "type": "filter_workloads", "attributes": { "workloads": [<workload-id>] } },
    { "type": "render_template", "attributes": { "template": 184 } }
  ],
  "outputs": [{
    "type": "kafka",
    "attributes": { "bootstrap_servers": "kafka1.example.com:9092,kafka2.example.com:9092", "kafka_topic": "azion.requests", "use_tls": true }
  }]
}'
```

The API answers `201` with `state` set to `executed` and the stored stream under `data`. Keep its `id`, which every later request on the stream uses. A stream with both `sampling` and `filter_workloads` is refused with `32007`, and one with neither with `32002`.

The stream starts sending one to two minutes after it is saved. Saving checks the format of each field and does not contact the endpoint, so a wrong address or topic shows only when the stream sends. For a SIEM with its own connector, select it in **Connector**, or send its `type` in `outputs[0]`: *Splunk* takes the HTTP Event Collector URL and token, *IBM QRadar* a URL, and *Elasticsearch* a URL and an encoded API key. A stream keeps one endpoint, and the API drops any second entry in `outputs` with no error. For every field, refer to [Endpoints](/en/documentation/platform/data-stream/endpoints/).

---

## Confirm the delivery

Real-Time Events records every send of a stream, delivered or not, with the status code the endpoint returned. A stream sends a batch every 60 seconds, or sooner when it reaches 2,000 log lines. A failed send does not stop the stream, and its lines are not sent again. Send a few requests to the workload, then wait about a minute.

**Console**

To find the sends in Azion Console:

1. **Open Real-Time Events**

   Access [Azion Console](https://console.azion.com/) > **Real-Time Events**.

2. **Select the Data Stream data source**

3. **Read the latest sends**

   Find the rows whose **Endpoint Type** matches your endpoint, and read their **Status Code** and **Streamed Lines**.

A **Status Code** of `200` means the endpoint accepted the batch.

**API**

To read the sends, query the `dataStreamedEvents` dataset, with a range that covers the activation of the stream:

```bash
curl --request POST \
  --url https://api.azion.com/v4/events/graphql \
  --header 'Authorization: Token <personal-token>' \
  --header 'Content-Type: application/json' \
  --data '{"query":"query { dataStreamedEvents(limit: 20, filter: {tsRange: {begin: \"2030-01-01T10:00:00\", end: \"2030-01-01T11:00:00\"}}, orderBy: [ts_DESC]) { ts endpointType statusCode streamedLines dataStreamed } }"}'
```

The API answers `200` with one record per send, the latest first. Each record carries the type of your endpoint in `endpointType`:

```json
{"data":{"dataStreamedEvents":[{"ts":"<time>","endpointType":"<endpoint-type>","statusCode":200,"streamedLines":<lines>,"dataStreamed":<bytes>}]}}
```

An empty `dataStreamedEvents` list means the stream has not sent in the range.

A status other than `200` is the answer of the endpoint, and `503` means Data Stream found the endpoint unavailable. For the causes, refer to [Troubleshoot Data Stream](/en/documentation/platform/data-stream/troubleshooting/).

At the SIEM, each log line carries the keys of the template, named after its variables. These keys tie the security decision to the request:

- `request_id` identifies the request, and `remote_addr`, `host`, `request_uri`, and `status` describe it.
- `waf_score` and `waf_match` hold the score of the request and the infractions it matched.
- `waf_block` reads `1` when WAF blocked the request. While `waf_learning` reads `1`, WAF blocks no request, whatever `waf_block` reads.

The SIEM receives one line per request to the workload, each with its WAF fields. The SIEM keeps the lines for as long as you configure it to.

---

## Next steps

- [Stream WAF events to a SIEM](/en/documentation/guides/application-security/firewall-and-waf/integrate-siems.md): Send only the requests WAF analyzed, with the attack family and action of each.
- [Data sources and variables](/en/documentation/platform/data-stream/data-sources-and-variables.md#applications): What each variable of the Applications data source holds, and which preset carries it.
- [Endpoints](/en/documentation/platform/data-stream/endpoints.md): The fields of every endpoint a stream sends to, with their bounds and API names.
- [Data Stream best practices](/en/documentation/platform/data-stream/best-practices.md#use-the-applications--waf-event-collector-preset-to-feed-a-siem): When the combined preset is worth its volume, and how to send fewer variables.
- [Prepare regulated web applications for security audits](/en/documentation/use-cases/secure-applications-and-networks/prepare-regulated-web-applications-for-security-audits.md): An audit setup that exports every request and WAF event to a destination the team keeps.
- [Troubleshoot Data Stream](/en/documentation/platform/data-stream/troubleshooting.md): What to change when a send returns a status other than 200.
