Skip to main content

Azure

Rivia connects to an Azure subscription through a service principal that you create in your own tenant. Rivia has no Azure presence of its own, so there is nothing on our side for the principal to trust.

Every permission below is read-only. Nothing Rivia holds can create, modify or delete anything in your subscription.

:::tip The app can generate all of this for you Connections → Connect a cloud → Microsoft Azure produces a ready-to-run Cloud Shell script, CLI commands or Terraform, and takes the four values back. This page is the long form: the same steps, with the reasoning, for anyone who would rather read before running. :::

What Rivia asks for​

Four grants. Only the first two are required, and you can decline either optional one without breaking the connection. Declining costs you exactly the capability named, nothing else.

GrantScopeWhat it readsRequired
ReaderSubscriptionResource configuration and metadataYes
Storage Blob Data ReaderSubscriptionBlob contentsYes
AcrPullSubscription or registryContainer imagesOptional
Directory.Read.AllTenantUsers, groups, service principalsOptional

A note on the second one, because it deserves the scrutiny: Storage Blob Data Reader reads the contents of your storage, not just its configuration. That is how Rivia finds unprotected PII, PHI, card data and secrets sitting in blob containers. It is read-only, but it is the most sensitive thing on this page and you should treat it as such.

Directory.Read.All is the only tenant-wide grant. Everything else is scoped to the subscriptions you choose to connect.

1. Sign in​

az login

If you are working on a machine with no browser, use az login --use-device-code.

2. Create the service principal​

Replace <SUBSCRIPTION_ID> with the subscription you want Rivia to cover.

az ad sp create-for-rbac \
--name rivia-collector \
--role Reader \
--scopes /subscriptions/<SUBSCRIPTION_ID>

The output contains the credentials, and the password is shown once:

{
"appId": "…",
"displayName": "rivia-collector",
"password": "…",
"tenant": "…"
}

Keep it somewhere safe until you have handed the values over. If you lose it, run az ad sp credential reset --id <appId> to issue a new one.

3. Grant blob read access​

Reader covers configuration but not data. Without this, Rivia can list your storage accounts and containers but classifies nothing inside them, so data security findings come back empty rather than clean.

az role assignment create \
--assignee <APP_ID> \
--role "Storage Blob Data Reader" \
--scope /subscriptions/<SUBSCRIPTION_ID>

4. Optional grants​

Container image scanning​

Only needed if you want vulnerability scanning of images in Azure Container Registry.

az role assignment create \
--assignee <APP_ID> \
--role AcrPull \
--scope /subscriptions/<SUBSCRIPTION_ID>

Decline it and container image scanning is skipped. Everything else is unaffected.

Identity and directory analysis​

Only needed if you want Rivia to resolve identities: which named user or group holds a role, and which service principals exist in your tenant.

This one is a Microsoft Graph application permission, not an Azure role, so it is granted differently and needs an administrator to consent. Requiring consent is not the same as requiring write access: Directory.Read.All is read-only, and Microsoft's own description is "Allows the app to read data in your organization's directory, such as users, groups and apps."

Consenting requires Global Administrator, Privileged Role Administrator or Cloud Application Administrator. Azure RBAC roles such as Owner or User Access Administrator are not sufficient, because this is a directory permission rather than a subscription one.

In the portal: Entra ID → App registrations → rivia-collector → API permissions → Add a permission → Microsoft Graph → Application permissions → Directory.Read.All, then Grant admin consent.

Or from the CLI:

APP_ID=<APP_ID>
SP_OBJECT_ID=$(az ad sp show --id "$APP_ID" --query id -o tsv)
GRAPH_SP=$(az ad sp list \
--filter "appId eq '00000003-0000-0000-c000-000000000000'" \
--query "[0].id" -o tsv)
# Well-known app role id for Directory.Read.All
ROLE_ID=7ab1d382-f21e-4acd-a863-ba3e13f7da61

az rest --method POST \
--url "https://graph.microsoft.com/v1.0/servicePrincipals/$SP_OBJECT_ID/appRoleAssignments" \
--headers "Content-Type=application/json" \
--body "{\"principalId\":\"$SP_OBJECT_ID\",\"resourceId\":\"$GRAPH_SP\",\"appRoleId\":\"$ROLE_ID\"}"

If you decline this one, Azure role assignments still sync, so Rivia can still tell you that something holds Owner on a subscription. What it cannot do is resolve that principal to a named person or walk their group memberships, so identity risk and any attack path that runs through a human identity will be incomplete. The connection stays healthy and reports itself as degraded rather than failed.

5. Hand the values to Rivia​

Four values:

  • Tenant ID (tenant from step 2)
  • Client ID (appId from step 2)
  • Client secret (password from step 2)
  • Subscription ID

Rivia stores the secret encrypted, never in plain text and never in logs.

Connecting more than one subscription​

Create the service principal once, then repeat the role assignments for each additional subscription:

for SUB in <SUBSCRIPTION_ID_1> <SUBSCRIPTION_ID_2>; do
az role assignment create --assignee <APP_ID> --role Reader --scope "/subscriptions/$SUB"
az role assignment create --assignee <APP_ID> --role "Storage Blob Data Reader" --scope "/subscriptions/$SUB"
done

Each subscription becomes its own connection in Rivia, so you can see them separately and disconnect one without touching the others.

What Rivia collects​

Once connected, Rivia builds an inventory of resource groups, virtual machines, managed disks, networks and network security groups, storage accounts and blob containers, SQL servers and databases, key vaults, and RBAC role assignments and definitions. On top of that it runs configuration security checks, classifies data in blob storage, resolves effective permissions, and ingests cost data if you have a Cost Management export configured.

Verifying and revoking​

To see what the principal can reach:

az role assignment list --assignee <APP_ID> --all -o table

To revoke everything, delete the service principal. Access stops immediately.

az ad sp delete --id <APP_ID>