jordandesigns.ioCloud & Platform Engineering
Azure · FinOps

Azure FinOps Dashboard

Cost visibility that answers what a bill cannot: which resource changed behavior, who owns the spend, where Advisor says it is wasted, and whether tags are governed at the control plane. Statistical anomaly detection, cost allocation by tag, Azure Advisor optimization, Azure Policy tag governance, and FOCUS normalization so Azure and AWS spend join on one schema, over the Cost Management API, written in C# and running credential-free.

Microsoft Azure
Role
Cloud / FinOps
Cloud
Azure
Language
C# .NET 8
Governance
Azure Policy
ArchitectureOpen full size ↗
Architecture diagram for Azure FinOps Dashboard
How it flows
Timer Triggers06:00 · 06:30 · 07:00 UTC
→
Cost Mgmt API7-day actuals by resource
→
Ingest FnC# .NET 8 · upsert
Anomaly Fn30d rolling · 2σ
Forecast Fn14d linear trend
→
Cosmos DBRBAC only · key auth off
→
HTTP API5 endpoints
React SPAStatic Web Apps
Daily ingest, then statistics: sigma-tiered anomalies and a 14-day projection, all under one managed identity

Problem

A cloud bill tells you what you spent after you have already spent it, aggregated to a level where nothing is actionable. By the time a runaway resource shows up as a line item, it has been running for most of a billing cycle, and the person who could have caught it has no signal that anything changed.

The three questions worth answering are earlier and more specific: which resources are behaving differently than they did last month, where is spend heading if nothing changes, and which resources cannot even be attributed to an owner because nobody tagged them.

Approach

  • A timer-triggered Function ingests the previous seven days of actual cost from the Cost Management REST API each morning, grouped by resource, resource type, and resource group, upserting into Cosmos DB keyed by resource ID so re-runs are idempotent.
  • Anomaly detection runs half an hour later against the stored history: a rolling 30-day mean and standard deviation per resource, flagging any resource whose latest daily cost exceeds two sigma, tiered Low at 2.0, Medium at 2.5, and High at 3.0.
  • Forecasting runs after that, projecting 14 days on a linear trend over the trailing 30-day window with confidence intervals derived from historical variance, and refuses to project at all on fewer than seven days of data rather than emitting a number nobody should trust.
  • A tag hygiene pass evaluates every subscription resource against a required-tag policy and reports both a compliance percentage and the specific resources missing specific tags, because a percentage alone is not something anyone can act on.
  • Cost allocation runs as a live query grouped by a cost allocation tag, so the dashboard answers what each project or owner costs, not just what each resource costs, and surfaces untagged spend as its own bucket. Optimization reads Azure Advisor cost recommendations, idle resources, right-sizing, and reservation purchases, each with an estimated monthly saving.
  • A /api/focus endpoint, backed by a pure, unit-testable C# FocusMapper, maps Azure cost records to the FOCUS open cost-and-usage schema (ProviderName, ServiceCategory, BilledCost, EffectiveCost, plus ResourceId, SubAccountId, and Tags). The AWS sibling emits the same core columns, so the two clouds join on one schema for cross-provider chargeback.

Governance: audit, not deny

The reporting layer flags untagged resources after the fact. The governance layer governs them at the control plane: a custom Azure Policy definition audits every taggable resource for the cost_center chargeback tag, assigned at resource-group scope. The effect is a deliberate design choice. The sample workload includes a purposely untagged storage account so the hygiene view has something to find; Deny would have blocked it at apply time and Modify would have auto-tagged it and erased the demo, so Audit flags non-compliance while leaving the resource exactly as it is.

Showing both layers, and knowing why they differ, is the point: the Function scanner reports, Azure Policy governs continuously.

Architecture and credential-free posture

Eight HTTP-triggered Functions expose the results as a REST API to a React single-page app on Static Web Apps. The read path never touches the Cost Management API for stored data, and cost-by-tag, Advisor, and FOCUS queries run live on demand. The whole thing runs without a stored credential: a system-assigned managed identity holds Cost Management Reader and Reader at subscription scope (covering Advisor too) and Cosmos DB Built-in Data Contributor at database scope. Key-based Cosmos access is disabled at the account level, so even a leaked connection string would be inert.

The AWS counterpart, the Cost Intelligence Dashboard, applies the same allocation, waste, and forecasting approach to Cost Explorer and emits the identical FOCUS schema at its own /focus endpoint; running it across both clouds on one schema is what makes the practice portable. The governance layer here deployed and was demoed live, the policy assignment created, resources carrying the new cost_center and team tags, the untagged resource flagged. The Consumption Function App could not deploy in this subscription because its App Service VM quota is zero, a subscription-wide limit that needs an Azure support quota increase; the FOCUS mapper and the two Function-hosted features build clean (dotnet build) and are proven end to end on the AWS side.

Live run receipt

Governance
Azure Policy Audit for cost_center deployed and demoed, untagged resource flagged
Allocation
Cost-by-tag and Advisor optimization endpoints, credential-free via managed identity
FOCUS
/api/focus emits the same open cost-and-usage schema as the AWS sibling; pure C# mapper, dotnet build clean
Auth
Managed identity throughout, key-based Cosmos access disabled
Constraint
Function App blocked by a zero App Service VM quota, code proven on the AWS sibling
Posture
Keyless, governed at the control plane

Built with

Azure FunctionsC# .NET 8Cosmos DBCost Management APIAzure AdvisorAzure PolicyFOCUSStatic Web AppsReactTerraform

Want something like this for your cloud?