Resource & Metric Collection
Prepare Azure for KubeSense — an App Registration with read-only roles, and optionally workload identity instead of a client secret. Common to both the Single and Multi Subscription paths.
Overview
KubeSense observes your Azure estate using read-only credentials. It discovers your resources across Azure services, keeps that inventory current, and pulls metrics for them from Azure Monitor — so the cloud estate appears alongside the Kubernetes telemetry KubeSense already collects.
Nothing is created, changed or deleted in your subscriptions. Every call KubeSense makes
is an ARM list/get or an Azure Monitor metrics read.
The steps on this page are common to both paths. Then choose one:
Single Subscription Setup
Multi-Subscription Setup
| Single Subscription | Multi Subscription | |
|---|---|---|
| Use it when | You have one subscription, or want to add a few by hand | Your estate spans many subscriptions |
| Access granted at | The subscription | Management groups, or named subscriptions |
| Subscriptions added later | You add each one | Enrolled automatically |
| Extra steps | None | A discovery preview you approve before anything is created |
The Multi Subscription path works because Azure RBAC inherits down the management-group
tree: a single Reader assignment at a management group covers every subscription
beneath it, including subscriptions created later. There is nothing to deploy into each
subscription — no per-subscription bootstrap, no stack to roll out, and no callback for
KubeSense to receive.
How KubeSense authenticates
| Mode | Use it when | What is stored |
|---|---|---|
| Client secret | Anywhere. The default, and the only option on the Single Subscription path. | The secret, encrypted at rest |
| Workload identity | The KubeSense controller runs on AKS. Multi Subscription only. | Nothing — the pod authenticates as its own identity |
The client secret is the part that will eventually bite you: Azure expires secrets on a 6–24 month clock set by tenant policy, and does not report the expiry date over its API. When a secret lapses, collection stops for every subscription that credential owns, at once. Workload identity has no secret and never expires — where the controller runs on AKS, prefer it. Otherwise record the expiry date in KubeSense so it can warn you.
Prerequisites
- Permission to create an App Registration in your Entra ID tenant
- Permission to create role assignments on the scopes you want observed —
OwnerorUser Access Administratoron those subscriptions or management groups - The
azCLI signed in, or the Azure portal if your policy forbids CLI changes - Administrator access to the KubeSense dashboard
The dashboard ships the setup for you: On the App Registration screen, "Get the setup script" offers both a shell script that runs as-is in Azure Cloud Shell and a Terraform module. Either performs Step 1 below. Neither is required — Step 1 can be done entirely in the portal.
Step 1 — Create the App Registration and grant read access
Two roles are needed, both Azure built-ins and both read-only:
| Role | Why it is needed |
|---|---|
| Reader | Discovers your resources — every Azure service KubeSense collects. |
| Monitoring Reader | Reads metrics from Azure Monitor. Without it KubeSense can see your resources but cannot chart them. |
With the setup script (recommended)
Run it in Azure Cloud Shell, where the az CLI is preinstalled and already signed in.
Upload it with Cloud Shell's Upload button, then:
chmod +x kubesense-azure-setup.sh
# Preferred — one management group covers its whole subtree:
./kubesense-azure-setup.sh --management-groups <MANAGEMENT-GROUP-ID>
# Or name subscriptions explicitly:
./kubesense-azure-setup.sh --subscriptions <SUB-ID-1>,<SUB-ID-2>The script creates the App Registration and its service principal, grants Reader and
Monitoring Reader on each scope, then creates a client secret and prints the values the
connection screens ask for. Re-running is safe: an existing App Registration and service
principal are reused rather than duplicated, and an assignment that already exists is
reported and skipped.
Prefer a management group over a subscription list: An assignment at a management group covers subscriptions added to it later, so a new subscription is enrolled with no action from you. A subscription list has to be edited every time your estate changes.
Or with Terraform
# terraform.tfvars
management_group_ids = ["mg-production"]terraform init
terraform apply
terraform output -raw client_secretIt creates the same App Registration and the same two read-only role assignments, and outputs the same values — including the secret's expiry date, which Terraform knows exactly and you would otherwise copy from the portal by hand.
One difference worth knowing before you choose: Terraform stores the generated client secret in its state file in plaintext. That is inherent to the resource, not something the module can avoid, so anyone who can read your state backend can read the credential. The script prints the secret once and stores it nowhere, which is why it is the recommended path wherever policy forbids secrets in state.
Doing it by hand
- Entra ID → App registrations → New registration. Name it
kubesense-collector. Note the Directory (tenant) ID and Application (client) ID from the Overview page. - Certificates & secrets → New client secret. Copy the Value — not the Secret ID — and note the expiry date.
- On each management group or subscription: Access control (IAM) → Add role
assignment, and assign both Reader and Monitoring Reader to the
kubesense-collectorservice principal.
Copy the secret's Value, not its Secret ID: The two look alike, sit next to each other, and only one works. This is the single most common Azure setup mistake.
Step 2 — (Optional) Use workload identity instead of a secret
Skip this if you are using a client secret, or if the controller does not run on AKS. Workload identity is available on the Multi Subscription path only. It requires three things.
1. A federated credential on the App Registration, bound to your AKS cluster's OIDC issuer and the controller's namespace and service account:
az aks show -n <cluster> -g <rg> --query oidcIssuerProfile.issuerUrl -o tsv
az ad app federated-credential create --id <APP-OBJECT-ID> --parameters '{
"name": "kubesense-controller",
"issuer": "<AKS-OIDC-ISSUER-URL>",
"subject": "system:serviceaccount:kubesense:kubesense-controller",
"audiences": ["api://AzureADTokenExchange"]
}'2. The controller pod labelled for workload identity, so AKS projects a token into it:
metadata:
labels:
azure.workload.identity/use: "true"3. Reader and Monitoring Reader on the scopes, exactly as in Step 1 — the roles sit
on the same service principal either way.
KubeSense reads the projected token from AZURE_FEDERATED_TOKEN_FILE and exchanges it for
an ARM token. If that variable is unset the controller reports it explicitly rather than
failing quietly; the usual cause is the missing pod label.
What gets collected
Every Azure resource type KubeSense discovers, and every Azure Monitor metric it collects for each, is listed in the Azure resource and metric reference.
Next
Azure is ready. Connect it:
- Single Subscription Setup — one subscription, added by hand
- Multi-Subscription Setup — every subscription under a management group, enrolled automatically