# Discovery Azure Health Events

# Introduction

The **Azure Service Health Events** plugin discovers service health events affecting the Azure subscriptions available to a registered application. Events are grouped by impacted region and converted into Pandora FMS agents and modules.

The plugin can:

- Query every subscription visible to the Service Principal.
- Retrieve Azure Service Health events through the Azure Resource Health API.
- Group events by impacted region.
- Create one agent per region or send every module to a single agent.
- Apply both Azure-side filters and local regular-expression filters.
- Identify new or updated events between executions.
- Keep a JSONL event log for subsequent searches.
- Detect regions that no longer appear in the query results.

# Requirements

- Pandora FMS with Discovery and support for uploading the `.disco` package.
- HTTPS connectivity from the Pandora FMS server to: 
    - `https://login.microsoftonline.com`
    - `https://management.azure.com`
- A registered Microsoft Entra ID application with a Service Principal.
- A valid client secret.
- Read access to every subscription that should be monitored.
- A valid agent group in the Discovery task definition. The `All` group is not valid.

# Azure configuration

A registered application must be created in Microsoft Entra ID, together with a client secret. The following values are required to configure the task:

- **Tenant ID**: Microsoft Entra ID tenant identifier.
- **Client ID**: identifier of the registered application.
- **Client secret**: value of the secret created for the application.

The plugin uses the OAuth 2.0 Client Credentials flow and requests a token for the following scope:

```text
https://management.azure.com/.default

```

# Permissions

The recommended approach is to assign the **Reader** role to the Service Principal on every subscription that should be monitored. At a minimum, a custom role must allow the application to list accessible subscriptions and read Service Health events, including `Microsoft.ResourceHealth/events/read`.

Sensitive details from some security advisories may be hidden from identities without elevated permissions. The plugin queries the event list but does not call the additional `fetchEventDetails` operation required to retrieve sensitive content.

# Discovery task configuration

The wizard contains four visible steps.

### 1. Task definition

This step configures the general Discovery task settings:

- Task name.
- Agent group.
- Execution interval.

A real Pandora FMS group must be selected. Do not use `All`, as the plugin rejects empty or non-positive group identifiers.

### 2. Azure credentials

<table id="bkmrk-field-required-descr"><thead><tr><th>Field</th><th>Required</th><th>Description</th></tr></thead><tbody><tr><td>**Tenant ID**</td><td>Yes</td><td>Microsoft Entra ID tenant.</td></tr><tr><td>**Client ID**</td><td>Yes</td><td>Identifier of the registered application.</td></tr><tr><td>**Client secret**</td><td>Yes</td><td>Application secret.</td></tr><tr><td>**API endpoint**</td><td>No</td><td>When empty, `https://management.azure.com` is used. Change it only for sovereign clouds or custom environments.</td></tr><tr><td>**Login endpoint**</td><td>No</td><td>When empty, `https://login.microsoftonline.com` is used. Change it only for sovereign clouds or custom environments.</td></tr></tbody></table>

### 3. Azure event query and filters

<table id="bkmrk-field-default-value-"><thead><tr><th>Field</th><th align="right">Default value</th><th>Description</th></tr></thead><tbody><tr><td>**Event history in days**</td><td align="right">`15`</td><td>Query period, from 1 to 365 days.</td></tr><tr><td>**Azure API filter**</td><td align="right">Empty</td><td>Expression sent to Azure through `$filter`.</td></tr><tr><td>**Subscription allow regexp**</td><td align="right">Empty</td><td>Expressions matched against the subscription ID and name.</td></tr><tr><td>**Region allow regexp**</td><td align="right">Empty</td><td>Regions accepted by the plugin.</td></tr><tr><td>**Service allow regexp**</td><td align="right">Empty</td><td>Impacted services accepted by the plugin.</td></tr><tr><td>**Event type allow regexp**</td><td align="right">Empty</td><td>Allowed event types.</td></tr><tr><td>**Status allow regexp**</td><td align="right">Empty</td><td>Allowed regional or general statuses.</td></tr><tr><td>**Level allow regexp**</td><td align="right">Empty</td><td>Allowed event levels.</td></tr><tr><td>**Event search allow regexp**</td><td align="right">Empty</td><td>At least one expression must match the complete event text.</td></tr><tr><td>**Event search deny regexp**</td><td align="right">Empty</td><td>Discards matching events.</td></tr><tr><td>**First run events are new**</td><td align="right">Disabled</td><td>When enabled, every event found during the first execution is treated as new.</td></tr></tbody></table>

### 4. Agents modules and execution

<table id="bkmrk-field-default-value--1"><thead><tr><th>Field</th><th align="right">Default value</th><th>Description</th></tr></thead><tbody><tr><td>**Create agent per impacted region**</td><td align="right">Enabled</td><td>Creates one agent per region. When disabled, **Target agent** is used.</td></tr><tr><td>**Target agent**</td><td align="right">`Azure Service Health Events`</td><td>Single agent used when agents are not created per region.</td></tr><tr><td>**Agent prefix**</td><td align="right">`Azure Service Health `</td><td>Prefix for regional agents.</td></tr><tr><td>**Module prefix**</td><td align="right">Empty</td><td>Prefix added to final module names.</td></tr><tr><td>**State modules**</td><td align="right">Enabled</td><td>Creates the `Connection` module.</td></tr><tr><td>**Event count modules**</td><td align="right">Enabled</td><td>Creates the five event counter modules.</td></tr><tr><td>**Event detail modules**</td><td align="right">Enabled</td><td>Creates `Events` and `New events`.</td></tr><tr><td>**Maximum event detail length**</td><td align="right">`16000`</td><td>Maximum size of detail modules. The effective minimum is 1000 characters.</td></tr><tr><td>**Modules allow regexp**</td><td align="right">Empty</td><td>Only creates modules whose final name matches.</td></tr><tr><td>**Modules deny regexp**</td><td align="right">Empty</td><td>Discards modules whose final name matches.</td></tr><tr><td>**Write event log**</td><td align="right">Enabled</td><td>Enables the JSONL event log.</td></tr><tr><td>**Maximum event log size**</td><td align="right">`20`</td><td>Rotates the log when it reaches this size.</td></tr><tr><td>**HTTP timeout**</td><td align="right">`30`</td><td>Maximum time per request. Zero or negative values are replaced with 30 seconds.</td></tr><tr><td>**Maximum retries**</td><td align="right">`2`</td><td>Retries for HTTP 429 and transient Azure errors.</td></tr><tr><td>**Verify SSL certificates**</td><td align="right">Enabled</td><td>Keep enabled in production.</td></tr><tr><td>**Proxy URL**</td><td align="right">Empty</td><td>Optional HTTP or HTTPS proxy.</td></tr><tr><td>**Mock Azure API URL**</td><td align="right">Empty</td><td>Reserved for testing and must remain empty in production.</td></tr></tbody></table>

# Filters

### Azure-side filter

**Azure API filter** is sent directly to the API and reduces the number of events returned by Azure. The official documentation shows expressions based on service and region, for example:

```text
service eq 'Virtual Machines' or region eq 'West US'

```

The plugin does not validate or modify this expression. Syntax that Azure does not accept causes the corresponding subscription request to return an error.

### Local event filters

All remaining filters are evaluated locally after the events have been downloaded. Each textarea accepts one regular expression per line:

```text
^West Europe$
^Spain Central$

```

Matching is case-insensitive. Empty lines and lines beginning with `#` are ignored.

Allow filters behave as follows:

- When empty, every value is accepted.
- When expressions are configured, at least one must match.

**Event search allow regexp** searches the subscription, tracking ID, title, summary, status, level, type, subtype, service and region fields. **Event search deny regexp** searches the same fields and takes precedence when excluding an event.

### Module filters

**Modules allow regexp** and **Modules deny regexp** are applied to the final module name after prefixes and, in single-agent mode, the region name have been added.

If a module matches both allow and deny filters, deny takes precedence.

Example that keeps connection and counter modules only:

```text
Connection$|events count$

```

# Generated Agents and Modules

### One agent per region

When **Create agent per impacted region** is enabled, the name follows this format:

```text
<Agent prefix><Impacted region>


```

Example:

```text
Azure Service Health West Europe


```

### Single agent

When the option is disabled, every module is assigned to **Target agent**. The region is included in each module name to prevent collisions:

```text
West Europe Events count
Spain Central Events count


```

When **Module prefix** is also configured, it appears before the region.

## Generated modules

Every module is assigned to the `Azure Service Health Events` module group.

<table id="bkmrk-module-pandora-modul"><thead><tr><th>Module</th><th>Pandora module type</th><th>Data</th></tr></thead><tbody><tr><td>`Connection`</td><td>`generic_proc`</td><td>`1` when the region appears in the current query and `0` after it disappears.</td></tr><tr><td>`Events count`</td><td>`generic_data`</td><td>Number of unique events affecting the region.</td></tr><tr><td>`New events count`</td><td>`generic_data`</td><td>Number of new or updated events since the previous execution.</td></tr><tr><td>`Active events count`</td><td>`generic_data`</td><td>Events whose regional or general status is `Active`.</td></tr><tr><td>`Critical events count`</td><td>`generic_data`</td><td>Events with the `Critical` level.</td></tr><tr><td>`Warning events count`</td><td>`generic_data`</td><td>Events with the `Warning` level.</td></tr><tr><td>`Events`</td><td>`generic_data_string`</td><td>Details of every matching event.</td></tr><tr><td>`New events`</td><td>`generic_data_string`</td><td>Details of new or updated events; returns the integer `0` when no updates are available.</td></tr></tbody></table>

Detail modules include the title, tracking ID, subscription, status, level, type, subtype, timestamps, service, region and summary whenever available. If the text exceeds the configured limit, it is truncated and the module indicates that the complete content is available in the JSONL log.