> ## Documentation Index
> Fetch the complete documentation index at: https://opensre.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Azure Monitor

> Connect Azure Monitor Log Analytics so OpenSRE can pull KQL log evidence

## Overview

OpenSRE queries Azure Monitor Log Analytics through the public Query REST API. Each query is bounded by a `take` clause so result sets stay within a safe row limit.

## Prerequisites

* Azure subscription with at least one **Log Analytics Workspace** collecting logs
* A **Microsoft Entra ID (Azure AD) app registration** authorized to query the workspace
* The **Log Analytics Reader** role granted on the workspace (or its resource group / subscription) to the app's service principal
* Network access from the OpenSRE environment to `https://api.loganalytics.io` (or the sovereign cloud equivalent) over HTTPS

## Setup

```bash theme={null}
opensre integrations setup azure
```

That writes the workspace id, bearer token, and optional fields to the store, keyring, and project `.env` in one pass. You can still set the same values by hand.

### Option 1: Environment variables

Add to your `.env`:

```bash theme={null}
AZURE_LOG_ANALYTICS_WORKSPACE_ID=00000000-0000-0000-0000-000000000000
AZURE_LOG_ANALYTICS_TOKEN=<azure-ad-bearer-token>
AZURE_LOG_ANALYTICS_ENDPOINT=https://api.loganalytics.io
AZURE_TENANT_ID=<azure-ad-tenant-id>          # optional, informational
AZURE_SUBSCRIPTION_ID=<azure-subscription-id> # optional, informational
AZURE_MAX_RESULTS=100                          # optional, capped at 200
```

| Variable                           | Default                       | Description                                                                                          |
| ---------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------- |
| `AZURE_LOG_ANALYTICS_WORKSPACE_ID` | —                             | **Required.** Log Analytics Workspace ID (GUID) from the Azure portal                                |
| `AZURE_LOG_ANALYTICS_TOKEN`        | —                             | **Required.** Microsoft Entra ID OAuth2 bearer token with `Data.Read` on the workspace               |
| `AZURE_LOG_ANALYTICS_ENDPOINT`     | `https://api.loganalytics.io` | Override for sovereign clouds (for example `https://api.loganalytics.azure.us` for Azure Government) |
| `AZURE_TENANT_ID`                  | —                             | Microsoft Entra ID tenant ID (informational; useful for multi-tenant audits)                         |
| `AZURE_SUBSCRIPTION_ID`            | —                             | Azure subscription ID (informational)                                                                |
| `AZURE_MAX_RESULTS`                | `100`                         | Per-query row cap; OpenSRE clamps to a hard maximum of `200`                                         |

### Option 2: Persistent store

Credentials are persisted to `~/.opensre/integrations.json` with `0o600` permissions:

```json theme={null}
{
  "version": 1,
  "integrations": [
    {
      "id": "azure-prod",
      "service": "azure",
      "status": "active",
      "credentials": {
        "workspace_id": "00000000-0000-0000-0000-000000000000",
        "access_token": "<azure-ad-bearer-token>",
        "endpoint": "https://api.loganalytics.io",
        "tenant_id": "<azure-ad-tenant-id>",
        "subscription_id": "<azure-subscription-id>",
        "max_results": 100
      }
    }
  ]
}
```

## Credentials

### 1. Find the Workspace ID

1. In the Azure portal, open **Log Analytics workspaces** and select your workspace.
2. On the workspace **Overview** page, copy **Workspace ID** (a GUID).

### 2. Register an Azure AD application

1. Open **Microsoft Entra ID** → **App registrations** → **New registration**.
2. Give the app a name (for example `opensre-log-analytics`) and register it as a single-tenant app.
3. From the app's **Overview** page, copy the **Application (client) ID** and the **Directory (tenant) ID**.
4. Open **Certificates & secrets** → **New client secret**, copy the **secret value** (it is shown only once).

### 3. Grant `Log Analytics Reader` on the workspace

1. Open the Log Analytics workspace in the portal.
2. Go to **Access control (IAM)** → **Add** → **Add role assignment**.
3. Pick the **Log Analytics Reader** role and assign it to the service principal created above.

### 4. Obtain a bearer token (client credentials flow)

```bash theme={null}
curl -s -X POST \
  "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=$AZURE_CLIENT_ID" \
  -d "client_secret=$AZURE_CLIENT_SECRET" \
  -d "scope=https://api.loganalytics.io/.default" \
  | jq -r '.access_token'
```

Set the resulting token as `AZURE_LOG_ANALYTICS_TOKEN`. Tokens expire (usually after 60 minutes) — see the **Token rotation** note in [Security](#security).

## Tools

OpenSRE exposes one tool against an Azure Monitor workspace:

### `query_azure_monitor_logs`

`POST`s a KQL query to `<endpoint>/v1/workspaces/<workspace_id>/query` and returns the first table flattened into row dicts.

Arguments the planner supplies:

| Argument             | Default                                                    | Description                                                    |
| -------------------- | ---------------------------------------------------------- | -------------------------------------------------------------- |
| `query`              | `AppTraces \| order by TimeGenerated desc \| take <limit>` | KQL query text                                                 |
| `time_range_minutes` | `60`                                                       | Sent as the `timespan` (`PT<N>M`)                              |
| `limit`              | `50`                                                       | Per-query row cap; clamped to `max_results` (hard limit `200`) |

OpenSRE always appends a `| take <limit>` clause when one is missing, so the workspace never returns more rows than the configured cap. `AZURE_MAX_RESULTS` defaults to `100` and is hard-capped at `200`.

## Verify

```bash theme={null}
opensre integrations verify azure
```

Expected output:

```
SERVICE   SOURCE      STATUS   DETAIL
azure     local env   passed   Configured for Azure Log Analytics workspace 00000000-0000-0000-0000-000000000000 via https://api.loganalytics.io.
```

The verify step is a credential-shape check — it does not call the workspace. To exercise the live path, point OpenSRE at a synthetic alert that names `azure` as the source and inspect the resulting evidence.

## Troubleshooting

| Symptom                                             | Fix                                                                                                                                                                                                       |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **401 Unauthorized**                                | Token is missing, expired, or scoped to the wrong audience. Regenerate with `scope=https://api.loganalytics.io/.default` and confirm the service principal has **Log Analytics Reader** on the workspace. |
| **403 Forbidden**                                   | The token is valid but the principal lacks `Data.Read`. Re-check the role assignment on the workspace (or its parent resource group).                                                                     |
| **Empty result set**                                | Either the KQL `where` filter excludes everything or the workspace has no data in the requested timespan. Run the same query in **Logs** in the portal to confirm.                                        |
| **Wrong endpoint / DNS error**                      | Sovereign clouds use a different host (for example `https://api.loganalytics.azure.us` for US Government, `https://api.loganalytics.azure.cn` for China). Set `AZURE_LOG_ANALYTICS_ENDPOINT` accordingly. |
| **`Missing workspace_id` / `Missing access_token`** | One or both required credentials are absent. Confirm both env vars (or both fields in the persistent store) are populated.                                                                                |

## Security

* Use a **dedicated app registration** for OpenSRE — do not reuse a personal token or a broadly-scoped service principal.
* Grant only **Log Analytics Reader** on the workspace; OpenSRE only needs read access to query data.
* Keep the client secret out of source control — store it in `.env` or in a secret manager and only export it long enough to mint a token.
* **Rotate the bearer token** before its 60-minute expiry. Long-lived deployments should re-mint the token from the client secret on a schedule rather than pasting a static token into `.env`.
* The integration is **read-only**: OpenSRE only issues `POST /v1/workspaces/<id>/query` requests with a `take`-bounded KQL string.

## Extras

### Example KQL queries

Recent application errors:

```kql theme={null}
AppTraces
| where SeverityLevel >= 3
| where TimeGenerated > ago(15m)
| project TimeGenerated, OperationName, Message, AppRoleName
| order by TimeGenerated desc
| take 50
```

Error count by severity over the last hour:

```kql theme={null}
AppTraces
| where TimeGenerated > ago(1h)
| summarize count() by SeverityLevel
| order by SeverityLevel desc
```

Failed dependency calls correlated with a request id:

```kql theme={null}
AppDependencies
| where Success == false
| where TimeGenerated > ago(30m)
| project TimeGenerated, Name, ResultCode, DurationMs, OperationId
| order by TimeGenerated desc
| take 50
```
