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

# Azure

> Connect Azure with a read-only service principal so subscription layout, role assignments, NSG rules, encryption, TLS, Sentinel, backup, redundancy, and autoscale evidence stays current automatically.

The Azure integration connects your Azure tenant to Keldyn's continuous-evidence engine. You create a read-only app registration in your own directory, assign three built-in Azure roles, and paste the Tenant ID, Client (App) ID, and Client Secret into Keldyn. Once connected, Keldyn reads subscription layout, role assignments, network security group rules, encryption and TLS settings, Microsoft Sentinel alerts and incidents, backup configuration, redundancy, and autoscale activity on a schedule, and turns them into live evidence for the related SOC 2 controls. For identity, MFA, access reviews, and PIM evidence, use the separate [Microsoft Entra ID](/integrations/microsoft-entra-id) integration.

<Note>
  Integrations and automated evidence are typically managed by workspace admins.
  See [Evidence & audits](/evidence-and-audits) for how automated evidence fits
  alongside manual evidence.
</Note>

## What it's used for

Keldyn uses the data it reads from Azure to keep infrastructure evidence current. Each refresh updates the evidence and freshness status shown on the integration's **Controls covered** table.

The integration contributes evidence to these SOC 2 controls:

| Control                                     | Topic                                                                                                       | Coverage |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------- |
| **Segregated change environments**          | Subscription and resource-group layout showing production separated from a named non-production environment | Full     |
| **Boundaries of confidential data**         | Azure RBAC role assignments (account IDs; names if Graph access is granted)                                 | Full     |
| **Production environment restriction**      | Who holds access to production resources                                                                    | Full     |
| **Firewalls at access points**              | Network security group rules, including Azure's default deny rules                                          | Full     |
| **Critical data encryption at rest**        | Storage and SQL encryption-at-rest settings                                                                 | Full     |
| **Encryption in transit**                   | Minimum TLS version and HTTPS-only settings on storage, SQL, and App Service                                | Full     |
| **Network monitoring alerts**               | Microsoft Sentinel alert rules and incidents (status and owner), where Sentinel is in use                   | Full     |
| **System redundancy**                       | Storage SKU and SQL zone-redundancy / high-availability settings                                            | Full     |
| **Backup configuration and schedule**       | Azure Backup jobs completing on schedule                                                                    | Full     |
| **Backup policy**                           | Azure Backup policies (schedule and retention)                                                              | Full     |
| **Backup restoration tests**                | Azure Backup restore-job history                                                                            | Full     |
| **Auto-scaling configuration**              | Autoscale settings plus activity-log scale events                                                           | Full     |
| **Asset inventory**                         | Discovered subscriptions and resource groups                                                                | Partial  |
| **Data register**                           | Resource locations from the same inventory                                                                  | Partial  |
| **Segregation of duties**                   | Role-assignment snapshot                                                                                    | Partial  |
| **Privileged-access records**               | Broad roles such as Owner, Contributor, and User Access Administrator                                       | Partial  |
| **Cryptography policy / retention records** | Encryption and TLS settings as supporting input                                                             | Partial  |
| **Incident register / RCA**                 | Sentinel incidents as input; your register and RCA records remain the sources                               | Partial  |
| **DR test report**                          | Restore-job history as supporting input; the DR test report remains the source                              | Partial  |

<Info>
  **Full** coverage means the data is the artifact the control asks for.
  **Partial** coverage means the data usefully contributes but does not, on its
  own, replace everything the control requires. Keldyn labels partial coverage
  in the auto-generated evidence so it isn't mistaken for complete coverage.
</Info>

<Note>
  **Segregated change environments** is full only when the stored layout shows
  both production and a named non-production environment (from a name or an
  `Environment` / `environment` / `Env` tag). Resources Keldyn cannot classify
  default to production and are not treated as a fail. **Network monitoring
  alerts** applies where Microsoft Sentinel is onboarded; without it, that
  control is evidenced elsewhere and is not treated as a sync failure.
  **System redundancy** reflects configuration, not a tested failover.
  **Auto-scaling** stays unknown until Keldyn has seen at least one scale event
  in the activity log (Azure retains about 90 days).
</Note>

## Before you begin

<Steps>
  <Step title="Use an Azure subscription Owner or User Access Administrator">
    You need permission to create an [app registration](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade)
    in Microsoft Entra ID and to assign roles on each subscription you want
    evidenced. Application Developer (or a Global / Application Administrator)
    can create the app; Owner or User Access Administrator can assign the roles.
  </Step>

  <Step title="Decide which subscriptions to include">
    Assign the read-only roles at **subscription** scope (or at a management
    group that contains those subscriptions). A role assigned only on a
    resource group is not enough — connect fails if the app can see no
    subscriptions.
  </Step>

  <Step title="Keldyn only ever reads">
    Use the three built-in read-only roles below. Keldyn never deploys,
    changes configuration, or writes to your tenant. Do not assign Owner or
    Contributor to the Keldyn app.
  </Step>
</Steps>

## Set up the integration

Create a dedicated app registration in **your** Azure tenant, then paste its
credentials into Keldyn. There is no OAuth redirect and no Keldyn-owned Azure
account.

<Steps>
  <Step title="Create an app registration">
    In the [Azure portal](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade),
    open **Microsoft Entra ID → App registrations → New registration**.

    1. Name the app something stable, such as `KeldynEvidence`.
    2. Supported account types: **Accounts in this organizational directory only** (single tenant).
    3. Leave **Redirect URI** empty. This is a service principal (client credentials), not a signed-in user flow.
    4. Select **Register**.

    From the app **Overview**, copy:

    | Azure label             | Paste into Keldyn as |
    | ----------------------- | -------------------- |
    | Directory (tenant) ID   | **Tenant ID**        |
    | Application (client) ID | **Client (App) ID**  |

    Both values are GUIDs.
  </Step>

  <Step title="Create a client secret">
    On the same app, open **Certificates & secrets → Client secrets → New client secret**.

    1. Add a description such as `keldyn-evidence`.
    2. Choose an expiry (12 or 24 months is typical). Put a reminder on your calendar — an expired secret marks the connection **Reauth required**.
    3. Copy the secret **Value** immediately. Azure will not show it again.

    That value is **Client Secret** in Keldyn. Do not upload a certificate; Keldyn only accepts a client secret.
  </Step>

  <Step title="Assign the three read-only roles">
    Repeat this for **every subscription** that should appear in evidence (or assign once at a management group that contains them).

    Open **Subscriptions →** the subscription **→ Access control (IAM) → Add → Add role assignment**. Assign these [built-in roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) to the `KeldynEvidence` **application** (search Members by the app name, not a user):

    | Role                          | What it lets Keldyn read                                                                                                 |
    | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
    | **Reader**                    | Subscriptions, resource groups, role assignments, NSGs, storage, SQL, App Service TLS, autoscale settings, activity logs |
    | **Backup Reader**             | Recovery Services vault policies and backup / restore jobs                                                               |
    | **Microsoft Sentinel Reader** | Sentinel onboarding state, alert rules, and incidents                                                                    |

    Connect probes the Azure subscriptions list. If the app can see none, Keldyn rejects the credentials and tells you to assign Reader at subscription scope.
  </Step>

  <Step title="Optional: resolve account IDs to names">
    Role assignments always store principal object IDs, which is enough for the access controls. To also show display names:

    1. On the app, open **API permissions → Add a permission**.
    2. Choose **Microsoft Graph → Application permissions**.
    3. Add **Directory.Read.All**.
    4. Select **Grant admin consent** for your tenant.

    Without this permission, only the directory-name fetch shows **Access required**. Role assignments and every other source continue to refresh.
  </Step>

  <Step title="Connect in Keldyn">
    In the Keldyn web app, go to **Integrations** and select **Azure**. Paste **Tenant ID**, **Client (App) ID**, and **Client Secret**, then select **Connect**.

    Keldyn mints an Azure Resource Manager token with those credentials, confirms at least one subscription is visible, and stores the secret encrypted. The secret is never shown again — the form displays `[redacted]`. Use **Update credentials** when you rotate the secret (Tenant ID and Client ID stay the same).
  </Step>

  <Step title="Run the first sync">
    Select **Sync now** to pull evidence immediately, or wait for the scheduled refresh. **Controls covered** and **Evidence sources** then show what was collected and how fresh it is.
  </Step>
</Steps>

<Tip>
  From the integration detail page, **Controls covered** shows whether Azure is
  actively feeding each control and whether the control is satisfied.
  **Evidence sources** shows each data fetch, the controls it covers, and its
  freshness.
</Tip>

<Warning>
  Disconnecting in Keldyn does not delete the app registration or revoke the
  secret in Azure. Rotate or delete the client secret in the Azure portal when
  you no longer want the principal to have access.
</Warning>

## What data Keldyn collects and why

Keldyn requests **read-only** access and never writes to your Azure tenant. It collects only the data below, and only to build control evidence.

| Data collected                           | What it contains                                                                                                           | Why Keldyn collects it                                                                       | Refresh |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------- |
| **Subscriptions and resource groups**    | Subscription and resource-group names, locations, and environment classification from name or tags                         | Evidences segregated change environments, and supports the asset inventory and data register | Daily   |
| **Role assignments**                     | Who holds which Azure RBAC role, on which scope, including conditions                                                      | Shows who can access production resources                                                    | Daily   |
| **Directory listing**                    | Display name, type, and sign-in name for each principal object ID on a role assignment                                     | Resolves account IDs to names when Graph `Directory.Read.All` is granted                     | Daily   |
| **Network security group rules**         | Custom and default NSG rules: direction, access, protocol, source, destination, and ports                                  | Evidences that access points only allow intended traffic, including default deny             | Daily   |
| **Database and storage encryption**      | Whether each storage account and SQL database is encrypted at rest, plus a customer-managed key reference when one is used | Evidences encryption at rest                                                                 | Daily   |
| **TLS / HTTPS settings**                 | Minimum TLS version and HTTPS-only flags on storage, SQL servers, and App Service                                          | Evidences encryption in transit                                                              | Daily   |
| **Sentinel alert rules and incidents**   | Enabled alert rules plus incidents (status, owner, classification, open/close times), only when Sentinel is onboarded      | Evidences that threats are detected and assigned                                             | Hourly  |
| **Backup policies and jobs**             | Backup policy schedule and retention, plus backup-job history                                                              | Evidences backup configuration, schedule, and policy                                         | Daily   |
| **Backup restore jobs**                  | Restore-job history: status, start/finish times, and source recovery point                                                 | Evidences that restores have been tested                                                     | Daily   |
| **Redundancy settings**                  | Storage SKU (LRS vs GRS/ZRS/GZRS) and SQL zone-redundancy / high availability                                              | Evidences that production data is replicated                                                 | Daily   |
| **Autoscale settings and activity logs** | Autoscale min/max/default capacity, plus scale-up and scale-down events from the activity log                              | Evidences that capacity is configured to adjust and actually does so                         | Hourly  |

<Note>
  Azure Activity Log retains about 90 days. Keldyn therefore **accumulates**
  scale events across refreshes rather than replacing them, so evidence can
  cover an audit period longer than Azure's own retention window. The first
  sync after connecting shows only what Azure still holds.
</Note>

### Authentication

Keldyn authenticates as **your** Entra app registration using the OAuth 2.0
client-credentials flow (service principal). On each connect and each refresh
it mints a short-lived Azure Resource Manager token (`https://management.azure.com/.default`)
and, when resolving names, a Microsoft Graph token
(`https://graph.microsoft.com/.default`). Those tokens are not stored — the
client secret is the long-lived credential, stored encrypted. Disconnecting
does not revoke the app in Azure.

## Troubleshooting "Access required"

A control shows **Access required** when the service principal cannot read the matching data. Common causes include:

* **Reader** is missing, or assigned only on a resource group. Connect itself fails if no subscriptions are visible.
* **Backup Reader** is missing — backup policy, job, and restore-test sources fail; everything else continues.
* **Microsoft Sentinel Reader** is missing — Sentinel sources fail with Access required. This is different from Sentinel not being in use: if no workspace has Security Insights onboarded, that source succeeds with empty records and **Network monitoring alerts** is evidenced elsewhere.
* Graph **Directory.Read.All** is missing or admin consent was not granted — only the directory-name source fails. Role assignments still list object IDs.
* The client secret expired or was rotated in Azure without **Update credentials** in Keldyn. The connection shows **Reauth required**.

Create a new secret on the same app, select **Update credentials**, paste the same Tenant ID and Client ID with the new secret, then run **Sync now**. Controls not affected by the missing role continue to refresh normally.

## Keeping evidence current

Keldyn refreshes most Azure evidence automatically each day. Sentinel and autoscale/activity-log evidence refresh hourly so they stay fresher than the daily sources. Evidence that hasn't refreshed within its expected cadence is marked **stale**, and failed pulls are marked **failed** so you can spot gaps. You can also trigger an immediate refresh at any time with **Sync now**.

## Next steps

<Card title="Evidence & audits" icon="clipboard-check" href="/evidence-and-audits" arrow={true}>
  Learn how automated integration evidence works alongside manual evidence and
  audits.
</Card>
