Microsoft Defender for Cloud (Azure Security Center) — Integration Setup
Note: This guide covers Microsoft Defender for Cloud — Azure's cloud security posture management / workload protection product (formerly "Azure Security Center"). It is a separate integration from Microsoft Defender for Endpoint (EDR). If you're looking to connect endpoint/device telemetry, see integration-setup-defender.md instead.
Prerequisites
- An Azure subscription with Microsoft Defender for Cloud enabled
- Ability to assign Azure RBAC roles on the subscription (and, self-hosted, to register an Azure AD app)
- CMDash Essentials tier or above
How CMDash connects
Defender for Cloud uses CMDash's Microsoft app registration with an app-only token (the client-credentials grant, scope https://management.azure.com/.default); what the token may read is decided by the Azure role you assign to the app on your subscription. Which directory is read depends on how the deployment runs its Microsoft integrations; see How CMDash connects to Microsoft.
- CMDash SaaS (per directory): available once CMDash's Microsoft apps are registered. Until then Connect answers that the Microsoft app registration is not set up on this deployment. Once it is: (1) Integrations → Microsoft Defender for Cloud → Connect, enter the Subscription ID, sign in as an active Global Administrator or Privileged Role Administrator and accept the permissions for your organisation — this creates the CMDash enterprise application in your directory; (2) on the subscription, Access control (IAM) → Add role assignment → Security Reader, assigned to the CMDash enterprise application. Until step 2 is done the connection shows Unhealthy (HTTP 403). After you assign the role, it recovers by itself: CMDash re-checks an Unhealthy connection every 30 minutes with a newly minted token and marks it Active once the check passes (Azure can take a few minutes to apply a new role assignment), and scheduled syncs resume. Sync now on the integration's page retries sooner, each time with a newly minted token; if a sync has already failed on it, it stays Unhealthy until a sync succeeds. Commercial cloud only for now (not GCC High or DoD). What CMDash checks and records is described once, in the Entra ID guide.
- Self-hosted (single directory): Steps 1–4 below.
Step 1 (self-hosted): Register an Azure AD App
- Go to Azure Portal → App registrations.
- Click New registration.
- Name:
CMDash Integration. - Supported account types: Single tenant.
- Redirect URI: leave blank — a single-directory connection has no sign-in step.
- Click Register, then copy the Application (client) ID and Directory (tenant) ID from the Overview page.
Step 2 (self-hosted): Grant the App Read Access to Azure Resource Manager
Unlike Microsoft Graph integrations, Defender for Cloud's assessment and alert data is served from the Azure Resource Manager (ARM) API, which is authorized via Azure RBAC role assignment, not the API Permissions blade. No API permission is needed: CMDash's token is app-only, so a delegated permission such as user_impersonation would do nothing.
- Go to the target Subscription → Access control (IAM) → Add role assignment.
- Assign the Security Reader role (minimum) to the
CMDash Integrationapp registration. Read-only sync only requires Security Reader; CMDash writes nothing to Azure.
Step 3 (self-hosted): Create a Client Secret
- Go to Certificates & secrets → New client secret.
- Description:
CMDash. Expiry: 24 months (set a calendar reminder to rotate). - Copy the Value immediately — it will not be shown again.
Step 4 (self-hosted): Configure the deployment, then connect
The tenant id, client id and secret are server settings, not fields in the connect dialog.
- Set
AZURE_TENANT_ID,AZURE_CLIENT_IDandAZURE_CLIENT_SECRETin the API's environment (leaveAZURE_MULTI_TENANTunset) and restart the API. - In CMDash, navigate to Integrations, find Microsoft Defender for Cloud and click Connect.
- Enter the Subscription ID (the Azure subscription whose assessments/alerts you want synced) — the one setting this connector reads.
- Click Save & Test Connection.
What Syncs
| Data Type | API | Sync Frequency |
|---|---|---|
| Vulnerabilities (unhealthy security recommendations) | GET /subscriptions/{id}/providers/Microsoft.Security/assessments | Every 4 hours by default (configurable per connection) |
| Incidents (security alerts) | GET /subscriptions/{id}/providers/Microsoft.Security/alerts | Every 4 hours by default (configurable per connection) |
Only assessments whose properties.status.code is Unhealthy are imported as vulnerabilities — passing/healthy recommendations are not synced. Both endpoints are paginated via ARM's nextLink and capped at 2,000 records per sync.
Troubleshooting
- 401 Unauthorized: Self-hosted: the client secret behind
AZURE_CLIENT_SECRETmay have expired. SaaS: the CMDash app was removed from your directory — reconnect. - 403 Forbidden: The app registration's service principal does not have the Security Reader (or higher) role assigned on the subscription. Check Subscription → Access control (IAM) → Role assignments.
- No findings returned: Confirm Microsoft Defender for Cloud is actually enabled (a plan is turned on) for the resource types in this subscription — Defender for Cloud in "Free tier" only produces basic recommendations, not the full assessment set.
- Connection shows UNHEALTHY: The health check queries the assessments endpoint for a single result; a persistent failure usually indicates an expired secret or a revoked role assignment.
Rate Limits & Sync Behavior
| Setting | Value |
|---|---|
| Sync frequency | Every 4 hours by default (syncInterval is configurable per connection) |
| First sync | Historical unhealthy assessments and alerts visible to the app's role assignment |
| Pagination cap | 2,000 records per data type, per sync |
| Rate limit handling | Every outbound request is paced through CMDash's shared per-tenant token bucket for this provider (#507) |
| Failed sync retry | Job queue retries 3 times with exponential backoff (starting at 30s) — see docs/developers/dead-letter.md |
Credential Rotation
- CMDash SaaS: there is nothing on your side to rotate; CMDash rotates its own app's secret.
- Self-hosted: Azure AD client secrets expire (max 24 months). The secret is a server setting (
AZURE_CLIENT_SECRET), shared by every CMDash Microsoft integration, and CMDash does not warn before it expires — keep a calendar reminder.
To rotate before expiry (self-hosted):
- Go to App registrations → CMDash Integration → Certificates & secrets → New client secret.
- Copy the new Value immediately.
- Update
AZURE_CLIENT_SECRETin the API's environment and restart the API. - Once a sync succeeds, delete the old secret in Azure.
Multiple Instances / Multi-Site
Each connection reads a single Azure subscription, and a CMDash workspace holds one Defender for Cloud connection. To change which subscription is read, edit the connection's Subscription ID (the app needs the Security Reader role on the new subscription). Reading several subscriptions at once is not supported yet; each would need its own CMDash workspace.
Compliance Framework Coverage
The Microsoft Defender for Cloud integration provides evidence for the following controls. Coverage is automatically mapped when data is synced.
| Framework | Control | Description |
|---|---|---|
| PCI DSS | 2.2 | Secure configuration standards — unhealthy assessment findings map to configuration-hardening evidence |
| PCI DSS | 11.3 | Vulnerability/misconfiguration scanning — Defender for Cloud assessments |
| HITRUST | 06.d | Configuration management — cloud resource posture findings |
| CMMC L2 | RA.2.141 | Vulnerability/posture scanning — assessment findings mapped to scanning evidence |
| SOC 2 | CC7.1 | Threat detection — Defender for Cloud alerts feed the threat-detection evidence bucket |