Skip to main content

Connecting your Azure subscription(s)

This is the complete, do-it-once setup to let the platform scan your Azure for misconfigurations and compliance gaps. It is agentless and read-only: you never give us the password to a human account — you create a read-only Entra (Azure AD) service principal and grant it the built-in Reader role over the subscription(s) you want scanned. Reader means we can read every resource's configuration and metadata, change nothing, and read none of your data.

Unlike AWS — where we assume a role cross-account and store no secret — Azure requires a credential. You create an app registration with a client secret and paste it into the console once. From that moment it is write-only on our side:

  • stored encrypted in AWS Secrets Manager under a dedicated KMS key;
  • readable only by an isolated credential broker (a Lambda), never by a scanner or worker;
  • the broker mints each scan a short-lived (~1 hour) read-only token — the durable secret never reaches a scanner, is never returned by any API, and is never shown to you again.

:::info What we can and cannot see The service principal holds the built-in Reader role — configuration and metadata across the subscription. No write access. No reading your data (no blob/file contents, no database rows) — only how your resources are configured. That is the entire scope; nothing is hidden. :::

:::caution One-time caveat — the secret expires An Azure client secret has a maximum lifetime of 24 months; our onboarding script sets a 2-year secret. When it eventually expires you simply re-run the credential step and paste the new secret — the app registration and its role assignments persist, so this is a quick re-credential, not a full redo. :::


Before you start

From the platform (your console → CloudConnect Azure account), click Add account. When the setup is done you'll paste four values back — keep them handy as you go:

ValueWhat it is
Tenant IDYour Entra (Azure AD) directory ID.
Client ID (App ID)The application ID of the app registration you create.
Client SecretThe 2-year secret you create — the one we store encrypted and never show again.
Subscription ID(s) (optional)An optional narrowing filter. Left blank, the scan covers every subscription the Reader identity can see. Scope is controlled by where you assigned Reader (e.g. a management group vs. a single subscription).

Behind the scenes this is the API call POST /org/azure/accounts (your UI does it for you); the account is created in state pending until you finish the steps below and validate.


Create the read-only service principal

You have two paths — a scripted one and a portal click-through. Both produce the same thing: an app registration named S.E.T-system-CSPM, a service principal, a 2-year client secret, and the Reader role on each subscription you name.

Path A — Azure CLI (onboard.sh)

We provide the script onboard.sh. It creates the app registration, the service principal, a 2-year client secret, assigns Reader on each named subscription, and prints the four values to paste.

You must be signed into the Azure CLI as someone who can create app registrations and assign roles — i.e. Owner or User Access Administrator on the subscription(s).

onboard.sh
#!/usr/bin/env bash
set -euo pipefail
APP_NAME="S.E.T-system-CSPM"
# usage: ./onboard.sh <subscription-id> [<subscription-id> ...]
APP_ID=$(az ad app create --display-name "$APP_NAME" --query appId -o tsv)
az ad sp create --id "$APP_ID" >/dev/null
SECRET=$(az ad app credential reset --id "$APP_ID" --years 2 --query password -o tsv)
TENANT_ID=$(az account show --query tenantId -o tsv)
for SUB in "$@"; do
az role assignment create --assignee "$APP_ID" --role "Reader" --scope "/subscriptions/$SUB" >/dev/null
done
# prints: Tenant ID, Client ID, Client Secret, Subscription(s)

Run it with the subscription ID(s) you want in scope:

./onboard.sh <subscription-id> [<subscription-id> ...]

When it finishes it prints your Tenant ID, Client ID, Client Secret, and the Subscription(s) it assigned Reader on. Copy all four.

Path B — Azure Portal (click-through)

If you'd rather not use the CLI, do the same three things in the portal:

  1. Create the app registration. Microsoft Entra ID → App registrations → New registration. Name it S.E.T-system-CSPM and register it. On its Overview page, copy the Application (client) ID and Directory (tenant) ID.
  2. Create the client secret. In that app, Certificates & secrets → New client secret. Set the expiry to the longest option (up to 24 months), create it, and copy the secret value now — the portal shows it only once.
  3. Assign the Reader role. For each subscription you want scanned, open Subscriptions → (your subscription) → Access control (IAM) → Add → Add role assignment → Reader, then assign it to the S.E.T-system-CSPM app. (Assign at a management group instead of a subscription to cover everything beneath it in one assignment.)

Paste the values back

In the platform, on the account you added, paste the four values and save:

  • Tenant ID
  • Client ID (App ID)
  • Client Secret
  • Subscription ID(s) — optional; leave blank to scan every subscription the Reader identity can see.

That's the whole connection. Now validate.


Validate access

Before any scan, confirm the credential works. In the platform click Validate on the account (API: POST /org/azure/accounts/{id}/validate). We do a live token mint through the credential broker and report back:

  • validated ✓ — the token minted; the account is ready to scan.
  • invalid ✗ — with the reason (bad tenant, bad client ID, or bad/expired secret). Fix and re-validate.

Check overall readiness any time with the status endpoint (GET /org/azure/status{ enabled, validated_accounts, can_run }).


Run your first scan

Once at least one account is validated:

  • Platform: Cloud → Run scan.
  • API: POST /org/scans { "module": "azure" }.

The scan runs one read-only pass and returns when done. It is gated on a validated account (you'll get a 409 if none is validated yet), and the normal one-scan-per-14-days cooldown applies (independent of the other modules).

When it finishes you'll have:

  • Findings — the failures, grouped by issue with the affected resources listed and a "5 of 20 remaining" rollup.
  • Full posture — every pass and fail (GET /org/azure/results), filterable by service, severity, and subscription.
  • Compliance — pick any framework (GET /org/azure/frameworks lists them) and get an overall score plus a control-by-control breakdown (GET /org/azure/compliance?framework=CIS-Azure-2.1). One scan reports against every framework — CIS Azure, ISO 27001, SOC 2, NIST, PCI, and more. The framework is a view, never a re-scan.

Fix, then prove it's fixed

Azure findings use the same lifecycle as the rest of the platform, tracked per resource:

  1. Mark a finding In Progress / Resolved / Accepted Risk / False Positive.
  2. Fix it in Azure.
  3. Rescan. Resolution is confirmed by the scan, not by the click: a finding you marked Resolved closes when the next scan no longer sees it; a fix you didn't triage auto-closes after 2 consecutive clean scans. If a closed issue comes back it reopens (regression). Fix 15 of 20 affected resources and exactly those 15 close — the other 5 stay open.

A finding that keeps showing up across scans is flagged recurring so you can spot what isn't sticking.


Troubleshooting

SymptomCause / fix
Validate returns invalid (bad secret)The client secret is wrong or was mistyped. Re-run the credential step (a new secret) and paste it.
Validate returns invalid (bad tenant / client)Wrong Tenant ID or Client ID. Re-copy both from the app registration's Overview page.
onboard.sh fails on role assignmentYou're not allowed to assign Reader. Sign in as Owner or User Access Administrator on the subscription and re-run.
Was working, now invalidThe secret expired (max lifetime 24 months). Re-run the credential step and paste the new secret — the app registration and role assignments persist, so it's a quick re-credential.
"Can you see our data?"No. Reader role only — configuration and metadata. No writes, no data reads (no blob/file/database contents).

What we never expose

The scanning engine is white-labeled end to end. It isn't named in your findings (the engine's name and links are scrubbed; evidence source reads cloud_cspm), and in your own Azure Activity Log the scanner's calls are attributed to our service principal identity by its name — never the underlying tool. You see our service, nothing else.