Prepare ADX/Kusto for TauGrid
ADX/Kusto is an optional platform data service. Platform teams provision its cluster, databases, Entra identities, federation, and database roles. Prepare those platform resources once; Portal, lifecycle recorder, and adx-mon are separate consumers. Their released charts manage the TauGrid/adx-mon schema objects that they own.
Provision the service
Choose an approved region, SKU, capacity, network path, retention policy, and cost owner. This CLI shape illustrates the required flags; choose SKU, capacity, and other values to match your own environment:
az extension add --name kusto
az kusto cluster create --resource-group <resource-group> \
--name <adx-cluster-name> --location <region> \
--sku name=<approved-sku> tier=<approved-tier> capacity=<instance-count> \
--enable-streaming-ingest false
for db in Metrics Logs CostTracking Audit; do
az kusto database create --resource-group <resource-group> \
--cluster-name <adx-cluster-name> --database-name "$db" \
--read-write-database location=<region> \
soft-delete-period=P31D hot-cache-period=P7D
done
Current Azure CLI Kusto extensions reject kind=ReadWrite; a read-write
database is implied instead by --read-write-database.
Metrics is needed by Portal Kusto views and lifecycle history. Logs,
CostTracking, and Audit are required only for the corresponding adx-mon
pipelines.
Create identities and grant roles
For AKS, federate each exact ServiceAccount to a managed identity. Workload Identity obtains an Entra token; granting ADX database access is a separate role-assignment step below.
az identity federated-credential create --resource-group <resource-group> \
--identity-name <identity-name> --name <credential-name> \
--issuer <aks-oidc-issuer> \
--subject system:serviceaccount:<namespace>:<service-account> \
--audiences api://AzureADTokenExchange
An authorized ADX administrator must separately grant database roles. In
production, use distinct principals: Portal reader (Viewer), lifecycle
recorder writer (Ingestor), and adx-mon identity (currently ADX database
Admin for the databases whose schema it reconciles). Azure RBAC, Kubernetes
RBAC, and ADX database roles are independent.
For example, an ADX administrator can grant the two least-privilege consumer roles in PowerShell or another approved Azure CLI environment:
$tenant = az account show --query tenantId -o tsv
az kusto database-principal-assignment create `
--resource-group <resource-group> --cluster-name <adx-cluster-name> `
--database-name Metrics --principal-assignment-name taugrid-portal-viewer `
--principal-id <portal-managed-identity-client-id> --principal-type App `
--role Viewer --tenant-id $tenant
az kusto database-principal-assignment create `
--resource-group <resource-group> --cluster-name <adx-cluster-name> `
--database-name Metrics --principal-assignment-name taugrid-recorder-ingestor `
--principal-id <recorder-managed-identity-client-id> --principal-type App `
--role Ingestor --tenant-id $tenant
Use a stable, unique assignment name per database/principal/role. These commands grant ADX data-plane access only; create the federated credential and Kubernetes RBAC through the separate steps above.
Let the platform charts manage producer schemas
Let the platform charts manage TauGrid lifecycle tables, mappings, and
functions automatically; treat
taugrid-portal exp kusto schema --ingestion lifecycle as a
development/release artifact generator rather than a platform deployment
prerequisite. It produces KQL text for review, not for direct execution
against ADX.
For a release that includes lifecycle schema management, enable adx-mon first
and grant its identity the ADX database Admin role on Metrics. Explicitly
enable the lifecycle recorder and schema management together. The schema
template is intentionally gated by both
lifecycleRecorder.enabled=true and
lifecycleRecorder.schemaManagement.enabled=true; this chart does not expose
a schema-only mode. The recorder also requires an existing target namespace,
cluster label, ADX endpoint, dedicated ServiceAccount, workload identity, and
read-only workload RBAC:
lifecycleRecorder:
enabled: true
targetNamespace: <workspace-namespace>
cluster: <cluster-name>
kusto:
endpoint: https://<cluster>.<region>.kusto.windows.net
database: Metrics
table: TauExpRunLifecycle
workloadIdentity:
enabled: true
serviceAccount:
create: true
name: tau-lifecycle-recorder
annotations:
azure.workload.identity/client-id: <recorder-ingestion-client-id>
rbac:
create: true
schemaManagement:
enabled: true
namespace: <adx-mon-namespace>
resourceName: taugrid-lifecycle-schema
These values create the recorder Deployment plus an adx-mon
ManagementCommand that idempotently creates or updates
Metrics.TauExpRunLifecycle, its named JSON mapping, and
TauExpRunLifecycleDashboardRows(). The recorder identity retains only the
Ingestor role; the separate adx-mon identity executes the schema command.
Render the exact objects before deployment:
helm template taugrid-core charts/taugrid-core \
--namespace tau-system \
--values <lifecycle-values.yaml> |
yq 'select(.kind == "ManagementCommand" or
(.kind == "Deployment" and .metadata.name == "tau-lifecycle-recorder"))'
Check that automation before enabling a Kusto-backed Portal capability:
kubectl -n <adx-mon-namespace> get managementcommand \
<lifecycle-schema-resource-name> \
-o jsonpath='{.status.conditions[0].status}{" "}{.status.conditions[0].reason}{"\n"}'
Wait for a successful status. adx-mon v0.3.0 reconciles commands every 10
minutes. The recorder starts immediately and retries ingestion until the
schema is available; use kubectl rollout status deploy/tau-lifecycle-recorder --timeout=25m to wait for it to become Ready. Set
lifecycleRecorder.schemaManagement.enabled=false only when an existing
platform-owned automation already manages the identical lifecycle contract.
Stellar uses scalar metric tables supplied by its selected ingestion path
(commonly adx-mon remote-write Metrics.ExperimentMetrics). For adx-mon,
follow its published chart guide and enable Metrics/Logs table precreation
before broad collection to avoid ADX control-plane throttling.
The standalone collector-v1 runtime sends canonical
tau.experiment.metric.v1 chunks through queued ADX ingestion. Prepare the
Metrics.TauExpMetricEventsV1 table, its
TauExpMetricEventsV1Json mapping, and the stable
TauExpMetricEventRows() function through adx-mon before enabling workloads.
Canonical Portal v2 discovery and series reads require the typed catalog
Functions and do not fall back to raw ExperimentMetrics.
Enable the complete typed contract in the adx-mon release values:
managementCommands:
typedMetricEventsV1:
enabled: true
experimentCatalogV1:
enabled: true
functions:
items:
tauExpMetricEventRows:
enabled: true
tauExpSeriesCatalogRows:
enabled: true
tauExpRunCatalogRows:
enabled: true
Apply the lifecycle schema from taugrid-core with the complete recorder values
above, or leave both recorder/schema switches disabled and provision the
identical TauExpRunLifecycle contract through platform-owned automation. Wait
for both adx-mon ManagementCommands and the lifecycle schema command to succeed
before routing Portal traffic or enabling collector sidecars. Verify the
rendered objects and ADX assets:
kubectl -n <adx-mon-namespace> get managementcommands,functions
kubectl -n <adx-mon-namespace> get managementcommand \
<adx-mon-release>-typed-metric-events-v1 \
<adx-mon-release>-experiment-catalog-v1
# Run in the Metrics database with an authorized read-only ADX client.
.show tables | where TableName in ("TauExpMetricEventsV1", "TauExpRunLifecycle")
.show functions | where Name in (
"TauExpMetricEventRows",
"TauExpSeriesCatalogRows",
"TauExpRunCatalogRows"
)
Grant the workload identity used by the TauWorkspace ServiceAccount only the
ADX database/table ingestion role required for TauExpMetricEventsV1. The
collector uses an Azure Identity Workload Identity credential with the
non-secret user-assigned identity client ID; do not create a client secret or
grant the workload management-command permissions. The adx-mon operator, not
the workload, owns table, mapping, retention, batching, and materialized-view
commands.
Queued submission is not final ingestion acknowledgement. TauGrid’s
adx-queued-v1 sink requests final result reporting and waits for ADX to report
success before persisting its delivery receipt. Monitor final ingestion
failures, status latency/timeouts, throttling, and materialized-view health
for every workload using adx-required.
Release owners must publish immutable tau, taugrid-portal, and
taugrid-metrics-collector images from the same reviewed source stack. The
coordinated 0.4.4 chart train also references a publishable
tau-core-controller:0.4.4 artifact even though this telemetry change does not
modify the controller binary’s source dependencies. Hand consumers the
collector digest, tested ADX endpoint, database, ServiceAccount subject, and
non-secret identity client ID. The collector is a tau run workload sidecar,
not a Helm-managed Deployment; there is no chart-side runtime selector. Then
configure Portal or adx-mon.